Mon Aug 31 12:30:09 2015

Asterisk developer's documentation


misdn_config.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2005, Christian Richter
00005  *
00006  * Christian Richter <crich@beronet.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  *
00018  */
00019 
00020 /*!
00021  * \file
00022  *
00023  * \brief chan_misdn configuration management
00024  * \author Christian Richter <crich@beronet.com>
00025  *
00026  * \ingroup channel_drivers
00027  */
00028 
00029 /*** MODULEINFO
00030    <support_level>extended</support_level>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369001 $")
00036 
00037 #include "chan_misdn_config.h"
00038 
00039 #include "asterisk/config.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/lock.h"
00042 #include "asterisk/pbx.h"
00043 #include "asterisk/strings.h"
00044 #include "asterisk/utils.h"
00045 
00046 #define NO_DEFAULT "<>"
00047 #define NONE 0
00048 
00049 #define GEN_CFG 1
00050 #define PORT_CFG 2
00051 #define NUM_GEN_ELEMENTS (sizeof(gen_spec) / sizeof(struct misdn_cfg_spec))
00052 #define NUM_PORT_ELEMENTS (sizeof(port_spec) / sizeof(struct misdn_cfg_spec))
00053 
00054 /*! Global jitterbuffer configuration - by default, jb is disabled
00055  *  \note Values shown here match the defaults shown in misdn.conf.sample */
00056 static struct ast_jb_conf default_jbconf =
00057 {
00058    .flags = 0,
00059    .max_size = 200,
00060    .resync_threshold = 1000,
00061    .impl = "fixed",
00062    .target_extra = 40,
00063 };
00064 
00065 static struct ast_jb_conf global_jbconf;
00066 
00067 enum misdn_cfg_type {
00068    MISDN_CTYPE_STR,
00069    MISDN_CTYPE_INT,
00070    MISDN_CTYPE_BOOL,
00071    MISDN_CTYPE_BOOLINT,
00072    MISDN_CTYPE_MSNLIST,
00073    MISDN_CTYPE_ASTGROUP
00074 };
00075 
00076 struct msn_list {
00077    char *msn;
00078    struct msn_list *next;
00079 };
00080 
00081 union misdn_cfg_pt {
00082    char *str;
00083    int *num;
00084    struct msn_list *ml;
00085    ast_group_t *grp;
00086    void *any;
00087 };
00088 
00089 struct misdn_cfg_spec {
00090    char name[BUFFERSIZE];
00091    enum misdn_cfg_elements elem;
00092    enum misdn_cfg_type type;
00093    char def[BUFFERSIZE];
00094    int boolint_def;
00095    char desc[BUFFERSIZE];
00096 };
00097 
00098 
00099 static const char ports_description[] =
00100    "Define your ports, e.g. 1,2 (depends on mISDN-driver loading order).";
00101 
00102 static const struct misdn_cfg_spec port_spec[] = {
00103    { "name", MISDN_CFG_GROUPNAME, MISDN_CTYPE_STR, "default", NONE,
00104       "Name of the portgroup." },
00105    { "allowed_bearers", MISDN_CFG_ALLOWED_BEARERS, MISDN_CTYPE_STR, "all", NONE,
00106       "Here you can list which bearer capabilities should be allowed:\n"
00107       "\t  all                  - allow any bearer capability\n"
00108       "\t  speech               - allow speech\n"
00109       "\t  3_1khz               - allow 3.1KHz audio\n"
00110       "\t  digital_unrestricted - allow unrestricted digital\n"
00111       "\t  digital_restricted   - allow restricted digital\n"
00112       "\t  video                - allow video" },
00113    { "rxgain", MISDN_CFG_RXGAIN, MISDN_CTYPE_INT, "0", NONE,
00114       "Set this between -8 and 8 to change the RX Gain." },
00115    { "txgain", MISDN_CFG_TXGAIN, MISDN_CTYPE_INT, "0", NONE,
00116       "Set this between -8 and 8 to change the TX Gain." },
00117    { "te_choose_channel", MISDN_CFG_TE_CHOOSE_CHANNEL, MISDN_CTYPE_BOOL, "no", NONE,
00118       "Some telcos especially in NL seem to need this set to yes,\n"
00119       "\talso in Switzerland this seems to be important." },
00120    { "far_alerting", MISDN_CFG_FAR_ALERTING, MISDN_CTYPE_BOOL, "no", NONE,
00121       "If we should generate ringing for chan_sip and others." },
00122    { "pmp_l1_check", MISDN_CFG_PMP_L1_CHECK, MISDN_CTYPE_BOOL, "no", NONE,
00123       "This option defines, if chan_misdn should check the L1 on a PMP\n"
00124       "\tbefore making a group call on it. The L1 may go down for PMP Ports\n"
00125       "\tso we might need this.\n"
00126       "\tBut be aware! a broken or plugged off cable might be used for a group call\n"
00127       "\tas well, since chan_misdn has no chance to distinguish if the L1 is down\n"
00128       "\tbecause of a lost Link or because the Provider shut it down..." },
00129    { "block_on_alarm", MISDN_CFG_ALARM_BLOCK, MISDN_CTYPE_BOOL, "no", NONE ,
00130      "Block this port if we have an alarm on it." },
00131    { "hdlc", MISDN_CFG_HDLC, MISDN_CTYPE_BOOL, "no", NONE,
00132       "Set this to yes, if you want to bridge a mISDN data channel to\n"
00133       "\tanother channel type or to an application." },
00134    { "context", MISDN_CFG_CONTEXT, MISDN_CTYPE_STR, "default", NONE,
00135       "Context to use for incoming calls." },
00136    { "language", MISDN_CFG_LANGUAGE, MISDN_CTYPE_STR, "en", NONE,
00137       "Language." },
00138    { "musicclass", MISDN_CFG_MUSICCLASS, MISDN_CTYPE_STR, "default", NONE,
00139       "Sets the musiconhold class." },
00140    { "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE,
00141       "Set the outgoing caller id to the value." },
00142    { "incoming_cid_tag", MISDN_CFG_INCOMING_CALLERID_TAG, MISDN_CTYPE_STR, "", NONE,
00143       "Set the incoming caller id string tag to the value." },
00144    { "append_msn_to_cid_tag", MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, MISDN_CTYPE_BOOL, "no", NONE,
00145       "Automatically appends incoming or outgoing MSN to the incoming caller\n"
00146       "\tid string tag. An underscore '_' is used as delimiter. Incoming calls\n"
00147       "\twill have the dialed number appended, and outgoing calls will have the\n"
00148       "\tcaller number appended to the tag." },
00149    { "method", MISDN_CFG_METHOD, MISDN_CTYPE_STR, "standard", NONE,
00150       "Set the method to use for channel selection:\n"
00151       "\t  standard     - Use the first free channel starting from the lowest number.\n"
00152       "\t  standard_dec - Use the first free channel starting from the highest number.\n"
00153       "\t  round_robin  - Use the round robin algorithm to select a channel. Use this\n"
00154       "\t                 if you want to balance your load." },
00155    { "dialplan", MISDN_CFG_DIALPLAN, MISDN_CTYPE_INT, "0", NONE,
00156       "Dialplan means Type Of Number in ISDN Terms\n"
00157       "\tThere are different types of the dialplan:\n"
00158       "\n"
00159       "\tdialplan -> for outgoing call's dialed number\n"
00160       "\tlocaldialplan -> for outgoing call's callerid\n"
00161       "\t      (if -1 is set use the value from the asterisk channel)\n"
00162       "\tcpndialplan -> for incoming call's connected party number sent to caller\n"
00163       "\t      (if -1 is set use the value from the asterisk channel)\n"
00164       "\n"
00165       "\tdialplan options:\n"
00166       "\n"
00167       "\t0 - unknown\n"
00168       "\t1 - International\n"
00169       "\t2 - National\n"
00170       "\t4 - Subscriber" },
00171    { "localdialplan", MISDN_CFG_LOCALDIALPLAN, MISDN_CTYPE_INT, "0", NONE,
00172       "Dialplan means Type Of Number in ISDN Terms\n"
00173       "\tThere are different types of the dialplan:\n"
00174       "\n"
00175       "\tdialplan -> for outgoing call's dialed number\n"
00176       "\tlocaldialplan -> for outgoing call's callerid\n"
00177       "\t      (if -1 is set use the value from the asterisk channel)\n"
00178       "\tcpndialplan -> for incoming call's connected party number sent to caller\n"
00179       "\t      (if -1 is set use the value from the asterisk channel)\n"
00180       "\n"
00181       "\tdialplan options:\n"
00182       "\n"
00183       "\t0 - unknown\n"
00184       "\t1 - International\n"
00185       "\t2 - National\n"
00186       "\t4 - Subscriber" },
00187    { "cpndialplan", MISDN_CFG_CPNDIALPLAN, MISDN_CTYPE_INT, "0", NONE,
00188       "Dialplan means Type Of Number in ISDN Terms\n"
00189       "\tThere are different types of the dialplan:\n"
00190       "\n"
00191       "\tdialplan -> for outgoing call's dialed number\n"
00192       "\tlocaldialplan -> for outgoing call's callerid\n"
00193       "\t      (if -1 is set use the value from the asterisk channel)\n"
00194       "\tcpndialplan -> for incoming call's connected party number sent to caller\n"
00195       "\t      (if -1 is set use the value from the asterisk channel)\n"
00196       "\n"
00197       "\tdialplan options:\n"
00198       "\n"
00199       "\t0 - unknown\n"
00200       "\t1 - International\n"
00201       "\t2 - National\n"
00202       "\t4 - Subscriber" },
00203    { "unknownprefix", MISDN_CFG_TON_PREFIX_UNKNOWN, MISDN_CTYPE_STR, "", NONE,
00204       "Prefix for unknown numbers, this is put before an incoming number\n"
00205       "\tif its type-of-number is unknown." },
00206    { "internationalprefix", MISDN_CFG_TON_PREFIX_INTERNATIONAL, MISDN_CTYPE_STR, "00", NONE,
00207       "Prefix for international numbers, this is put before an incoming number\n"
00208       "\tif its type-of-number is international." },
00209    { "nationalprefix", MISDN_CFG_TON_PREFIX_NATIONAL, MISDN_CTYPE_STR, "0", NONE,
00210       "Prefix for national numbers, this is put before an incoming number\n"
00211       "\tif its type-of-number is national." },
00212    { "netspecificprefix", MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC, MISDN_CTYPE_STR, "", NONE,
00213       "Prefix for network-specific numbers, this is put before an incoming number\n"
00214       "\tif its type-of-number is network-specific." },
00215    { "subscriberprefix", MISDN_CFG_TON_PREFIX_SUBSCRIBER, MISDN_CTYPE_STR, "", NONE,
00216       "Prefix for subscriber numbers, this is put before an incoming number\n"
00217       "\tif its type-of-number is subscriber." },
00218    { "abbreviatedprefix", MISDN_CFG_TON_PREFIX_ABBREVIATED, MISDN_CTYPE_STR, "", NONE,
00219       "Prefix for abbreviated numbers, this is put before an incoming number\n"
00220       "\tif its type-of-number is abbreviated." },
00221    { "presentation", MISDN_CFG_PRES, MISDN_CTYPE_INT, "-1", NONE,
00222       "These (presentation and screen) are the exact isdn screening and presentation\n"
00223       "\tindicators.\n"
00224       "\tIf -1 is given for either value, the presentation indicators are used from\n"
00225       "\tAsterisk's CALLERPRES function.\n"
00226       "\n"
00227       "\tscreen=0, presentation=0 -> callerid presented\n"
00228       "\tscreen=1, presentation=1 -> callerid restricted (the remote end doesn't see it!)" },
00229    { "screen", MISDN_CFG_SCREEN, MISDN_CTYPE_INT, "-1", NONE,
00230       "These (presentation and screen) are the exact isdn screening and presentation\n"
00231       "\tindicators.\n"
00232       "\tIf -1 is given for either value, the presentation indicators are used from\n"
00233       "\tAsterisk's CALLERPRES function.\n"
00234       "\n"
00235       "\tscreen=0, presentation=0 -> callerid presented\n"
00236       "\tscreen=1, presentation=1 -> callerid restricted (the remote end doesn't see it!)" },
00237    { "outgoing_colp", MISDN_CFG_OUTGOING_COLP, MISDN_CTYPE_INT, "0", NONE,
00238       "Select what to do with outgoing COLP information on this port.\n"
00239       "\n"
00240       "\t0 - Send out COLP information unaltered.\n"
00241       "\t1 - Force COLP to restricted on all outgoing COLP information.\n"
00242       "\t2 - Do not send COLP information." },
00243    { "display_connected", MISDN_CFG_DISPLAY_CONNECTED, MISDN_CTYPE_INT, "0", NONE,
00244       "Put a display ie in the CONNECT message containing the following\n"
00245       "\tinformation if it is available (nt port only):\n"
00246       "\n"
00247       "\t0 - Do not put the connected line information in the display ie.\n"
00248       "\t1 - Put the available connected line name in the display ie.\n"
00249       "\t2 - Put the available connected line number in the display ie.\n"
00250       "\t3 - Put the available connected line name and number in the display ie." },
00251    { "display_setup", MISDN_CFG_DISPLAY_SETUP, MISDN_CTYPE_INT, "0", NONE,
00252       "Put a display ie in the SETUP message containing the following\n"
00253       "\tinformation if it is available (nt port only):\n"
00254       "\n"
00255       "\t0 - Do not put the caller information in the display ie.\n"
00256       "\t1 - Put the available caller name in the display ie.\n"
00257       "\t2 - Put the available caller number in the display ie.\n"
00258       "\t3 - Put the available caller name and number in the display ie." },
00259    { "always_immediate", MISDN_CFG_ALWAYS_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
00260       "Enable this to get into the s dialplan-extension.\n"
00261       "\tThere you can use DigitTimeout if you can't or don't want to use\n"
00262       "\tisdn overlap dial.\n"
00263       "\tNOTE: This will jump into the s extension for every exten!" },
00264    { "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE,
00265       "Enable this to prevent chan_misdn to generate the dialtone\n"
00266       "\tThis makes only sense together with the always_immediate=yes option\n"
00267       "\tto generate your own dialtone with Playtones or so." },
00268    { "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
00269       "Enable this if you want callers which called exactly the base\n"
00270       "\tnumber (so no extension is set) to jump into the s extension.\n"
00271       "\tIf the user dials something more, it jumps to the correct extension\n"
00272       "\tinstead." },
00273    { "senddtmf", MISDN_CFG_SENDDTMF, MISDN_CTYPE_BOOL, "no", NONE,
00274       "Enable this if we should produce DTMF Tones ourselves." },
00275    { "astdtmf", MISDN_CFG_ASTDTMF, MISDN_CTYPE_BOOL, "no", NONE,
00276       "Enable this if you want to use the Asterisk dtmf detector\n"
00277       "instead of the mISDN_dsp/hfcmulti one."
00278       },
00279    { "hold_allowed", MISDN_CFG_HOLD_ALLOWED, MISDN_CTYPE_BOOL, "no", NONE,
00280       "Enable this to have support for hold and retrieve." },
00281    { "early_bconnect", MISDN_CFG_EARLY_BCONNECT, MISDN_CTYPE_BOOL, "yes", NONE,
00282       "Disable this if you don't mind correct handling of Progress Indicators." },
00283    { "incoming_early_audio", MISDN_CFG_INCOMING_EARLY_AUDIO, MISDN_CTYPE_BOOL, "no", NONE,
00284       "Turn this on if you like to send Tone Indications to a Incoming\n"
00285       "\tisdn channel on a TE Port. Rarely used, only if the Telco allows\n"
00286       "\tyou to send indications by yourself, normally the Telco sends the\n"
00287       "\tindications to the remote party." },
00288    { "echocancel", MISDN_CFG_ECHOCANCEL, MISDN_CTYPE_BOOLINT, "0", 128,
00289       "This enables echo cancellation with the given number of taps.\n"
00290       "\tBe aware: Move this setting only to outgoing portgroups!\n"
00291       "\tA value of zero turns echo cancellation off.\n"
00292       "\n"
00293       "\tPossible values are: 0,32,64,128,256,yes(=128),no(=0)" },
00294 #ifdef MISDN_1_2
00295    { "pipeline", MISDN_CFG_PIPELINE, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
00296       "Set the configuration string for the mISDN dsp pipeline.\n"
00297       "\n"
00298       "\tExample for enabling the mg2 echo cancellation module with deftaps\n"
00299       "\tset to 128:\n"
00300       "\t\tmg2ec(deftaps=128)" },
00301 #endif
00302 #ifdef WITH_BEROEC
00303    { "bnechocancel", MISDN_CFG_BNECHOCANCEL, MISDN_CTYPE_BOOLINT, "yes", 64,
00304       "echotail in ms (1-200)" },
00305    { "bnec_antihowl", MISDN_CFG_BNEC_ANTIHOWL, MISDN_CTYPE_INT, "0", NONE,
00306       "Use antihowl" },
00307    { "bnec_nlp", MISDN_CFG_BNEC_NLP, MISDN_CTYPE_BOOL, "yes", NONE,
00308       "Nonlinear Processing (much faster adaption)" },
00309    { "bnec_zerocoeff", MISDN_CFG_BNEC_ZEROCOEFF, MISDN_CTYPE_BOOL, "no", NONE,
00310       "ZeroCoeffeciens" },
00311    { "bnec_tonedisabler", MISDN_CFG_BNEC_TD, MISDN_CTYPE_BOOL, "no", NONE,
00312       "Disable Tone" },
00313    { "bnec_adaption", MISDN_CFG_BNEC_ADAPT, MISDN_CTYPE_INT, "1", NONE,
00314       "Adaption mode (0=no,1=full,2=fast)" },
00315 #endif
00316    { "need_more_infos", MISDN_CFG_NEED_MORE_INFOS, MISDN_CTYPE_BOOL, "0", NONE,
00317       "Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),\n"
00318       "\tthis requests additional Infos, so we can waitfordigits without much\n"
00319       "\tissues. This works only for PTP Ports" },
00320    { "noautorespond_on_setup", MISDN_CFG_NOAUTORESPOND_ON_SETUP, MISDN_CTYPE_BOOL, "0", NONE,
00321       "Do not send SETUP_ACKNOWLEDGE or PROCEEDING automatically to the calling Party.\n"
00322       "Instead we directly jump into the dialplan. This might be useful for fast call\n"
00323       "rejection, or for some broken switches, that need hangup causes like busy in the.\n"
00324       "RELEASE_COMPLETE Message, instead of the DISCONNECT Message."},
00325    { "jitterbuffer", MISDN_CFG_JITTERBUFFER, MISDN_CTYPE_INT, "4000", NONE,
00326       "The jitterbuffer." },
00327    { "jitterbuffer_upper_threshold", MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, MISDN_CTYPE_INT, "0", NONE,
00328       "Change this threshold to enable dejitter functionality." },
00329    { "callgroup", MISDN_CFG_CALLGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE,
00330       "Callgroup." },
00331    { "pickupgroup", MISDN_CFG_PICKUPGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE,
00332       "Pickupgroup." },
00333    { "max_incoming", MISDN_CFG_MAX_IN, MISDN_CTYPE_INT, "-1", NONE,
00334       "Defines the maximum amount of incoming calls per port for this group.\n"
00335       "\tCalls which exceed the maximum will be marked with the channel variable\n"
00336       "\tMAX_OVERFLOW. It will contain the amount of overflowed calls" },
00337    { "max_outgoing", MISDN_CFG_MAX_OUT, MISDN_CTYPE_INT, "-1", NONE,
00338       "Defines the maximum amount of outgoing calls per port for this group\n"
00339       "\texceeding calls will be rejected" },
00340 
00341    { "reject_cause", MISDN_CFG_REJECT_CAUSE, MISDN_CTYPE_INT, "21", NONE,
00342       "Defines the cause with which a 3. call is rejected on PTMP BRI."},
00343    { "faxdetect", MISDN_CFG_FAXDETECT, MISDN_CTYPE_STR, "no", NONE,
00344       "Setup fax detection:\n"
00345       "\t    no        - no fax detection\n"
00346       "\t    incoming  - fax detection for incoming calls\n"
00347       "\t    outgoing  - fax detection for outgoing calls\n"
00348       "\t    both      - fax detection for incoming and outgoing calls\n"
00349       "\tAdd +nojump to your value (i.e. faxdetect=both+nojump) if you don't want to jump into the\n"
00350       "\tfax-extension but still want to detect the fax and prepare the channel for fax transfer." },
00351    { "faxdetect_timeout", MISDN_CFG_FAXDETECT_TIMEOUT, MISDN_CTYPE_INT, "5", NONE,
00352       "Number of seconds the fax detection should do its job. After the given period of time,\n"
00353       "\twe assume that it's not a fax call and save some CPU time by turning off fax detection.\n"
00354       "\tSet this to 0 if you don't want a timeout (never stop detecting)." },
00355    { "faxdetect_context", MISDN_CFG_FAXDETECT_CONTEXT, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
00356       "Context to jump into if we detect a fax. Don't set this if you want to stay in the current context." },
00357    { "l1watcher_timeout", MISDN_CFG_L1_TIMEOUT, MISDN_CTYPE_BOOLINT, "0", 4,
00358       "Monitors L1 of the port.  If L1 is down it tries\n"
00359       "\tto bring it up.  The polling timeout is given in seconds.\n"
00360       "\tSetting the value to 0 disables monitoring L1 of the port.\n"
00361       "\n"
00362       "\tThis option is only read at chan_misdn loading time.\n"
00363       "\tYou need to unload and load chan_misdn to change the\n"
00364       "\tvalue.  An asterisk restart will also do the trick." },
00365    { "overlapdial", MISDN_CFG_OVERLAP_DIAL, MISDN_CTYPE_BOOLINT, "0", 4,
00366       "Enables overlap dial for the given amount of seconds.\n"
00367       "\tPossible values are positive integers or:\n"
00368       "\t   yes (= 4 seconds)\n"
00369       "\t   no  (= 0 seconds = disabled)" },
00370    { "nttimeout", MISDN_CFG_NTTIMEOUT, MISDN_CTYPE_BOOL, "no", NONE ,
00371       "Set this to yes if you want calls disconnected in overlap mode\n"
00372       "\twhen a timeout happens." },
00373    { "bridging", MISDN_CFG_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE,
00374       "Set this to yes/no, default is yes.\n"
00375       "This can be used to have bridging enabled in general and to\n"
00376       "disable it for specific ports. It makes sense to disable\n"
00377       "bridging on NT Port where you plan to use the HOLD/RETRIEVE\n"
00378       "features with ISDN phones." },
00379    { "msns", MISDN_CFG_MSNS, MISDN_CTYPE_MSNLIST, "*", NONE,
00380       "MSN's for TE ports, listen on those numbers on the above ports, and\n"
00381       "\tindicate the incoming calls to Asterisk.\n"
00382       "\tHere you can give a comma separated list, or simply an '*' for any msn." },
00383    { "cc_request_retention", MISDN_CFG_CC_REQUEST_RETENTION, MISDN_CTYPE_BOOL, "yes", NONE,
00384       "Enable/Disable call-completion request retention support (ptp)." },
00385 };
00386 
00387 static const struct misdn_cfg_spec gen_spec[] = {
00388    { "debug", MISDN_GEN_DEBUG, MISDN_CTYPE_INT, "0", NONE,
00389       "Sets the debugging flag:\n"
00390       "\t0 - No Debug\n"
00391       "\t1 - mISDN Messages and * - Messages, and * - State changes\n"
00392       "\t2 - Messages + Message specific Informations (e.g. bearer capability)\n"
00393       "\t3 - very Verbose, the above + lots of Driver specific infos\n"
00394       "\t4 - even more Verbose than 3" },
00395 #ifndef MISDN_1_2
00396    { "misdn_init", MISDN_GEN_MISDN_INIT, MISDN_CTYPE_STR, "/etc/misdn-init.conf", NONE,
00397       "Set the path to the misdn-init.conf (for nt_ptp mode checking)." },
00398 #endif
00399    { "tracefile", MISDN_GEN_TRACEFILE, MISDN_CTYPE_STR, "/var/log/asterisk/misdn.log", NONE,
00400       "Set the path to the massively growing trace file, if you want that." },
00401    { "bridging", MISDN_GEN_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE,
00402       "Set this to yes if you want mISDN_dsp to bridge the calls in HW." },
00403    { "stop_tone_after_first_digit", MISDN_GEN_STOP_TONE, MISDN_CTYPE_BOOL, "yes", NONE,
00404       "Stops dialtone after getting first digit on NT Port." },
00405    { "append_digits2exten", MISDN_GEN_APPEND_DIGITS2EXTEN, MISDN_CTYPE_BOOL, "yes", NONE,
00406       "Whether to append overlapdialed Digits to Extension or not." },
00407    { "dynamic_crypt", MISDN_GEN_DYNAMIC_CRYPT, MISDN_CTYPE_BOOL, "no", NONE,
00408       "Whether to look out for dynamic crypting attempts." },
00409    { "crypt_prefix", MISDN_GEN_CRYPT_PREFIX, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
00410       "What is used for crypting Protocol." },
00411    { "crypt_keys", MISDN_GEN_CRYPT_KEYS, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
00412       "Keys for cryption, you reference them in the dialplan\n"
00413       "\tLater also in dynamic encr." },
00414    { "ntkeepcalls", MISDN_GEN_NTKEEPCALLS, MISDN_CTYPE_BOOL, "no", NONE,
00415       "avoid dropping calls if the L2 goes down. some Nortel pbx\n"
00416       "do put down the L2/L1 for some milliseconds even if there\n"
00417       "are running calls. with this option you can avoid dropping them" },
00418    { "ntdebugflags", MISDN_GEN_NTDEBUGFLAGS, MISDN_CTYPE_INT, "0", NONE,
00419       "No description yet."},
00420    { "ntdebugfile", MISDN_GEN_NTDEBUGFILE, MISDN_CTYPE_STR, "/var/log/misdn-nt.log", NONE,
00421       "No description yet." }
00422 };
00423 
00424 
00425 /* array of port configs, default is at position 0. */
00426 static union misdn_cfg_pt **port_cfg;
00427 /* max number of available ports, is set on init */
00428 static int max_ports;
00429 /* general config */
00430 static union misdn_cfg_pt *general_cfg;
00431 /* storing the ptp flag separated to save memory */
00432 static int *ptp;
00433 /* maps enum config elements to array positions */
00434 static int *map;
00435 
00436 static ast_mutex_t config_mutex;
00437 
00438 #define CLI_ERROR(name, value, section) ({ \
00439    ast_log(LOG_WARNING, "misdn.conf: \"%s=%s\" (section: %s) invalid or out of range. " \
00440       "Please edit your misdn.conf and then do a \"misdn reload\".\n", name, value, section); \
00441 })
00442 
00443 static int _enum_array_map (void)
00444 {
00445    int i, j, ok;
00446 
00447    for (i = MISDN_CFG_FIRST + 1; i < MISDN_CFG_LAST; ++i) {
00448       if (i == MISDN_CFG_PTP)
00449          continue;
00450       ok = 0;
00451       for (j = 0; j < NUM_PORT_ELEMENTS; ++j) {
00452          if (port_spec[j].elem == i) {
00453             map[i] = j;
00454             ok = 1;
00455             break;
00456          }
00457       }
00458       if (!ok) {
00459          ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (port section) has no corresponding element in the config struct!\n", i);
00460          return -1;
00461       }
00462    }
00463    for (i = MISDN_GEN_FIRST + 1; i < MISDN_GEN_LAST; ++i) {
00464       ok = 0;
00465       for (j = 0; j < NUM_GEN_ELEMENTS; ++j) {
00466          if (gen_spec[j].elem == i) {
00467             map[i] = j;
00468             ok = 1;
00469             break;
00470          }
00471       }
00472       if (!ok) {
00473          ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (general section) has no corresponding element in the config struct!\n", i);
00474          return -1;
00475       }
00476    }
00477    return 0;
00478 }
00479 
00480 static int get_cfg_position (const char *name, int type)
00481 {
00482    int i;
00483 
00484    switch (type) {
00485    case PORT_CFG:
00486       for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
00487          if (!strcasecmp(name, port_spec[i].name))
00488             return i;
00489       }
00490       break;
00491    case GEN_CFG:
00492       for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
00493          if (!strcasecmp(name, gen_spec[i].name))
00494             return i;
00495       }
00496    }
00497 
00498    return -1;
00499 }
00500 
00501 static inline void misdn_cfg_lock (void)
00502 {
00503    ast_mutex_lock(&config_mutex);
00504 }
00505 
00506 static inline void misdn_cfg_unlock (void)
00507 {
00508    ast_mutex_unlock(&config_mutex);
00509 }
00510 
00511 static void _free_msn_list (struct msn_list* iter)
00512 {
00513    if (iter->next)
00514       _free_msn_list(iter->next);
00515    if (iter->msn)
00516       ast_free(iter->msn);
00517    ast_free(iter);
00518 }
00519 
00520 static void _free_port_cfg (void)
00521 {
00522    int i, j;
00523    int gn = map[MISDN_CFG_GROUPNAME];
00524    union misdn_cfg_pt* free_list[max_ports + 2];
00525 
00526    memset(free_list, 0, sizeof(free_list));
00527    free_list[0] = port_cfg[0];
00528    for (i = 1; i <= max_ports; ++i) {
00529       if (port_cfg[i][gn].str) {
00530          /* we always have a groupname in the non-default case, so this is fine */
00531          for (j = 1; j <= max_ports; ++j) {
00532             if (free_list[j] && free_list[j][gn].str == port_cfg[i][gn].str)
00533                break;
00534             else if (!free_list[j]) {
00535                free_list[j] = port_cfg[i];
00536                break;
00537             }
00538          }
00539       }
00540    }
00541    for (j = 0; free_list[j]; ++j) {
00542       for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
00543          if (free_list[j][i].any) {
00544             if (port_spec[i].type == MISDN_CTYPE_MSNLIST)
00545                _free_msn_list(free_list[j][i].ml);
00546             else
00547                ast_free(free_list[j][i].any);
00548          }
00549       }
00550    }
00551 }
00552 
00553 static void _free_general_cfg (void)
00554 {
00555    int i;
00556 
00557    for (i = 0; i < NUM_GEN_ELEMENTS; i++)
00558       if (general_cfg[i].any)
00559          ast_free(general_cfg[i].any);
00560 }
00561 
00562 void misdn_cfg_get(int port, enum misdn_cfg_elements elem, void *buf, int bufsize)
00563 {
00564    int place;
00565 
00566    if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
00567       memset(buf, 0, bufsize);
00568       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Port number %d is not valid.\n", port);
00569       return;
00570    }
00571 
00572    misdn_cfg_lock();
00573    if (elem == MISDN_CFG_PTP) {
00574       if (!memcpy(buf, &ptp[port], (bufsize > ptp[port]) ? sizeof(ptp[port]) : bufsize))
00575          memset(buf, 0, bufsize);
00576    } else {
00577       if ((place = map[elem]) < 0) {
00578          memset(buf, 0, bufsize);
00579          ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Invalid element (%d) requested.\n", elem);
00580       } else {
00581          if (elem < MISDN_CFG_LAST) {
00582             switch (port_spec[place].type) {
00583             case MISDN_CTYPE_STR:
00584                if (port_cfg[port][place].str) {
00585                   ast_copy_string(buf, port_cfg[port][place].str, bufsize);
00586                } else if (port_cfg[0][place].str) {
00587                   ast_copy_string(buf, port_cfg[0][place].str, bufsize);
00588                } else
00589                   memset(buf, 0, bufsize);
00590                break;
00591             default:
00592                if (port_cfg[port][place].any)
00593                   memcpy(buf, port_cfg[port][place].any, bufsize);
00594                else if (port_cfg[0][place].any)
00595                   memcpy(buf, port_cfg[0][place].any, bufsize);
00596                else
00597                   memset(buf, 0, bufsize);
00598             }
00599          } else {
00600             switch (gen_spec[place].type) {
00601             case MISDN_CTYPE_STR:
00602                ast_copy_string(buf, S_OR(general_cfg[place].str, ""), bufsize);
00603                break;
00604             default:
00605                if (general_cfg[place].any)
00606                   memcpy(buf, general_cfg[place].any, bufsize);
00607                else
00608                   memset(buf, 0, bufsize);
00609             }
00610          }
00611       }
00612    }
00613    misdn_cfg_unlock();
00614 }
00615 
00616 enum misdn_cfg_elements misdn_cfg_get_elem(const char *name)
00617 {
00618    int pos;
00619 
00620    /* here comes a hack to replace the (not existing) "name" element with the "ports" element */
00621    if (!strcmp(name, "ports"))
00622       return MISDN_CFG_GROUPNAME;
00623    if (!strcmp(name, "name"))
00624       return MISDN_CFG_FIRST;
00625 
00626    pos = get_cfg_position(name, PORT_CFG);
00627    if (pos >= 0)
00628       return port_spec[pos].elem;
00629 
00630    pos = get_cfg_position(name, GEN_CFG);
00631    if (pos >= 0)
00632       return gen_spec[pos].elem;
00633 
00634    return MISDN_CFG_FIRST;
00635 }
00636 
00637 void misdn_cfg_get_name(enum misdn_cfg_elements elem, void *buf, int bufsize)
00638 {
00639    struct misdn_cfg_spec *spec = NULL;
00640    int place = map[elem];
00641 
00642    /* the ptp hack */
00643    if (elem == MISDN_CFG_PTP) {
00644       memset(buf, 0, 1);
00645       return;
00646    }
00647 
00648    /* here comes a hack to replace the (not existing) "name" element with the "ports" element */
00649    if (elem == MISDN_CFG_GROUPNAME) {
00650       if (!snprintf(buf, bufsize, "ports"))
00651          memset(buf, 0, 1);
00652       return;
00653    }
00654 
00655    if ((elem > MISDN_CFG_FIRST) && (elem < MISDN_CFG_LAST))
00656       spec = (struct misdn_cfg_spec *)port_spec;
00657    else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST))
00658       spec = (struct misdn_cfg_spec *)gen_spec;
00659 
00660    ast_copy_string(buf, spec ? spec[place].name : "", bufsize);
00661 }
00662 
00663 void misdn_cfg_get_desc (enum misdn_cfg_elements elem, void *buf, int bufsize, void *buf_default, int bufsize_default)
00664 {
00665    int place = map[elem];
00666    struct misdn_cfg_spec *spec = NULL;
00667 
00668    /* here comes a hack to replace the (not existing) "name" element with the "ports" element */
00669    if (elem == MISDN_CFG_GROUPNAME) {
00670       ast_copy_string(buf, ports_description, bufsize);
00671       if (buf_default && bufsize_default)
00672          memset(buf_default, 0, 1);
00673       return;
00674    }
00675 
00676    if ((elem > MISDN_CFG_FIRST) && (elem < MISDN_CFG_LAST))
00677       spec = (struct misdn_cfg_spec *)port_spec;
00678    else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST))
00679       spec = (struct misdn_cfg_spec *)gen_spec;
00680 
00681    if (!spec || !spec[place].desc)
00682       memset(buf, 0, 1);
00683    else {
00684       ast_copy_string(buf, spec[place].desc, bufsize);
00685       if (buf_default && bufsize) {
00686          if (!strcmp(spec[place].def, NO_DEFAULT))
00687             memset(buf_default, 0, 1);
00688          else
00689             ast_copy_string(buf_default, spec[place].def, bufsize_default);
00690       }
00691    }
00692 }
00693 
00694 int misdn_cfg_is_msn_valid (int port, char* msn)
00695 {
00696    int re = 0;
00697    struct msn_list *iter;
00698 
00699    if (!misdn_cfg_is_port_valid(port)) {
00700       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_is_msn_valid! Port number %d is not valid.\n", port);
00701       return 0;
00702    }
00703 
00704    misdn_cfg_lock();
00705    if (port_cfg[port][map[MISDN_CFG_MSNS]].ml)
00706       iter = port_cfg[port][map[MISDN_CFG_MSNS]].ml;
00707    else
00708       iter = port_cfg[0][map[MISDN_CFG_MSNS]].ml;
00709    for (; iter; iter = iter->next)
00710       if (*(iter->msn) == '*' || ast_extension_match(iter->msn, msn)) {
00711          re = 1;
00712          break;
00713       }
00714    misdn_cfg_unlock();
00715 
00716    return re;
00717 }
00718 
00719 int misdn_cfg_is_port_valid (int port)
00720 {
00721    int gn = map[MISDN_CFG_GROUPNAME];
00722 
00723    return (port >= 1 && port <= max_ports && port_cfg[port][gn].str);
00724 }
00725 
00726 int misdn_cfg_is_group_method (char *group, enum misdn_cfg_method meth)
00727 {
00728    int i, re = 0;
00729    char *method ;
00730 
00731    misdn_cfg_lock();
00732 
00733    method = port_cfg[0][map[MISDN_CFG_METHOD]].str;
00734 
00735    for (i = 1; i <= max_ports; i++) {
00736       if (port_cfg[i] && port_cfg[i][map[MISDN_CFG_GROUPNAME]].str) {
00737          if (!strcasecmp(port_cfg[i][map[MISDN_CFG_GROUPNAME]].str, group))
00738             method = (port_cfg[i][map[MISDN_CFG_METHOD]].str ?
00739                     port_cfg[i][map[MISDN_CFG_METHOD]].str : port_cfg[0][map[MISDN_CFG_METHOD]].str);
00740       }
00741    }
00742 
00743    if (method) {
00744       switch (meth) {
00745       case METHOD_STANDARD:      re = !strcasecmp(method, "standard");
00746                            break;
00747       case METHOD_ROUND_ROBIN:   re = !strcasecmp(method, "round_robin");
00748                            break;
00749       case METHOD_STANDARD_DEC:  re = !strcasecmp(method, "standard_dec");
00750                            break;
00751       }
00752    }
00753    misdn_cfg_unlock();
00754 
00755    return re;
00756 }
00757 
00758 /*!
00759  * \brief Generate a comma separated list of all active ports
00760  */
00761 void misdn_cfg_get_ports_string (char *ports)
00762 {
00763    char tmp[16];
00764    int l, i;
00765    int gn = map[MISDN_CFG_GROUPNAME];
00766 
00767    *ports = 0;
00768 
00769    misdn_cfg_lock();
00770    for (i = 1; i <= max_ports; i++) {
00771       if (port_cfg[i][gn].str) {
00772          if (ptp[i])
00773             sprintf(tmp, "%dptp,", i);
00774          else
00775             sprintf(tmp, "%d,", i);
00776          strcat(ports, tmp);
00777       }
00778    }
00779    misdn_cfg_unlock();
00780 
00781    if ((l = strlen(ports))) {
00782       /* Strip trailing ',' */
00783       ports[l-1] = 0;
00784    }
00785 }
00786 
00787 void misdn_cfg_get_config_string (int port, enum misdn_cfg_elements elem, char* buf, int bufsize)
00788 {
00789    int place;
00790    char tempbuf[BUFFERSIZE] = "";
00791    struct msn_list *iter;
00792 
00793    if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
00794       *buf = 0;
00795       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Port number %d is not valid.\n", port);
00796       return;
00797    }
00798 
00799    place = map[elem];
00800 
00801    misdn_cfg_lock();
00802    if (elem == MISDN_CFG_PTP) {
00803       snprintf(buf, bufsize, " -> ptp: %s", ptp[port] ? "yes" : "no");
00804    }
00805    else if (elem > MISDN_CFG_FIRST && elem < MISDN_CFG_LAST) {
00806       switch (port_spec[place].type) {
00807       case MISDN_CTYPE_INT:
00808       case MISDN_CTYPE_BOOLINT:
00809          if (port_cfg[port][place].num)
00810             snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[port][place].num);
00811          else if (port_cfg[0][place].num)
00812             snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[0][place].num);
00813          else
00814             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00815          break;
00816       case MISDN_CTYPE_BOOL:
00817          if (port_cfg[port][place].num)
00818             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[port][place].num ? "yes" : "no");
00819          else if (port_cfg[0][place].num)
00820             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[0][place].num ? "yes" : "no");
00821          else
00822             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00823          break;
00824       case MISDN_CTYPE_ASTGROUP:
00825          if (port_cfg[port][place].grp)
00826             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
00827                    ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[port][place].grp));
00828          else if (port_cfg[0][place].grp)
00829             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
00830                    ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[0][place].grp));
00831          else
00832             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00833          break;
00834       case MISDN_CTYPE_MSNLIST:
00835          if (port_cfg[port][place].ml)
00836             iter = port_cfg[port][place].ml;
00837          else
00838             iter = port_cfg[0][place].ml;
00839          if (iter) {
00840             for (; iter; iter = iter->next) {
00841                strncat(tempbuf, iter->msn, sizeof(tempbuf) - strlen(tempbuf) - 1);
00842             }
00843             if (strlen(tempbuf) > 1) {
00844                tempbuf[strlen(tempbuf)-2] = 0;
00845             }
00846          }
00847          snprintf(buf, bufsize, " -> msns: %s", *tempbuf ? tempbuf : "none");
00848          break;
00849       case MISDN_CTYPE_STR:
00850          if ( port_cfg[port][place].str) {
00851             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[port][place].str);
00852          } else if (port_cfg[0][place].str) {
00853             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[0][place].str);
00854          } else {
00855             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00856          }
00857          break;
00858       }
00859    } else if (elem > MISDN_GEN_FIRST && elem < MISDN_GEN_LAST) {
00860       switch (gen_spec[place].type) {
00861       case MISDN_CTYPE_INT:
00862       case MISDN_CTYPE_BOOLINT:
00863          if (general_cfg[place].num)
00864             snprintf(buf, bufsize, " -> %s: %d", gen_spec[place].name, *general_cfg[place].num);
00865          else
00866             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00867          break;
00868       case MISDN_CTYPE_BOOL:
00869          if (general_cfg[place].num)
00870             snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, *general_cfg[place].num ? "yes" : "no");
00871          else
00872             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00873          break;
00874       case MISDN_CTYPE_STR:
00875          if ( general_cfg[place].str) {
00876             snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, general_cfg[place].str);
00877          } else {
00878             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00879          }
00880          break;
00881       default:
00882          snprintf(buf, bufsize, " -> type of %s not handled yet", gen_spec[place].name);
00883          break;
00884       }
00885    } else {
00886       *buf = 0;
00887       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Invalid config element (%d) requested.\n", elem);
00888    }
00889    misdn_cfg_unlock();
00890 }
00891 
00892 int misdn_cfg_get_next_port (int port)
00893 {
00894    int p = -1;
00895    int gn = map[MISDN_CFG_GROUPNAME];
00896 
00897    misdn_cfg_lock();
00898    for (port++; port <= max_ports; port++) {
00899       if (port_cfg[port][gn].str) {
00900          p = port;
00901          break;
00902       }
00903    }
00904    misdn_cfg_unlock();
00905 
00906    return p;
00907 }
00908 
00909 int misdn_cfg_get_next_port_spin (int port)
00910 {
00911    int p = misdn_cfg_get_next_port(port);
00912    return (p > 0) ? p : misdn_cfg_get_next_port(0);
00913 }
00914 
00915 static int _parse (union misdn_cfg_pt *dest, const char *value, enum misdn_cfg_type type, int boolint_def)
00916 {
00917    int re = 0;
00918    int len, tmp;
00919    char *valtmp;
00920    char *tmp2 = ast_strdupa(value);
00921 
00922    switch (type) {
00923    case MISDN_CTYPE_STR:
00924       if (dest->str) {
00925          ast_free(dest->str);
00926       }
00927       if ((len = strlen(value))) {
00928          dest->str = ast_malloc((len + 1) * sizeof(char));
00929          strncpy(dest->str, value, len);
00930          dest->str[len] = 0;
00931       } else {
00932          dest->str = ast_malloc(sizeof(char));
00933          dest->str[0] = 0;
00934       }
00935       break;
00936    case MISDN_CTYPE_INT:
00937    {
00938       int res;
00939 
00940       if (strchr(value,'x')) {
00941          res = sscanf(value, "%30x", &tmp);
00942       } else {
00943          res = sscanf(value, "%30d", &tmp);
00944       }
00945       if (res) {
00946          if (!dest->num) {
00947             dest->num = ast_malloc(sizeof(int));
00948          }
00949          memcpy(dest->num, &tmp, sizeof(int));
00950       } else
00951          re = -1;
00952    }
00953       break;
00954    case MISDN_CTYPE_BOOL:
00955       if (!dest->num) {
00956          dest->num = ast_malloc(sizeof(int));
00957       }
00958       *(dest->num) = (ast_true(value) ? 1 : 0);
00959       break;
00960    case MISDN_CTYPE_BOOLINT:
00961       if (!dest->num) {
00962          dest->num = ast_malloc(sizeof(int));
00963       }
00964       if (sscanf(value, "%30d", &tmp)) {
00965          memcpy(dest->num, &tmp, sizeof(int));
00966       } else {
00967          *(dest->num) = (ast_true(value) ? boolint_def : 0);
00968       }
00969       break;
00970    case MISDN_CTYPE_MSNLIST:
00971       for (valtmp = strsep(&tmp2, ","); valtmp; valtmp = strsep(&tmp2, ",")) {
00972          if ((len = strlen(valtmp))) {
00973             struct msn_list *ml = ast_malloc(sizeof(*ml));
00974             ml->msn = ast_calloc(len+1, sizeof(char));
00975             strncpy(ml->msn, valtmp, len);
00976             ml->next = dest->ml;
00977             dest->ml = ml;
00978          }
00979       }
00980       break;
00981    case MISDN_CTYPE_ASTGROUP:
00982       if (!dest->grp) {
00983          dest->grp = ast_malloc(sizeof(ast_group_t));
00984       }
00985       *(dest->grp) = ast_get_group(value);
00986       break;
00987    }
00988 
00989    return re;
00990 }
00991 
00992 static void _build_general_config (struct ast_variable *v)
00993 {
00994    int pos;
00995 
00996    for (; v; v = v->next) {
00997       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
00998          continue;
00999       if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) ||
01000          (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0))
01001          CLI_ERROR(v->name, v->value, "general");
01002    }
01003 }
01004 
01005 static void _build_port_config (struct ast_variable *v, char *cat)
01006 {
01007    int pos, i;
01008    union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS];
01009    int cfg_for_ports[max_ports + 1];
01010 
01011    if (!v || !cat)
01012       return;
01013 
01014    memset(cfg_tmp, 0, sizeof(cfg_tmp));
01015    memset(cfg_for_ports, 0, sizeof(cfg_for_ports));
01016 
01017    if (!strcasecmp(cat, "default")) {
01018       cfg_for_ports[0] = 1;
01019    }
01020 
01021    if (((pos = get_cfg_position("name", PORT_CFG)) < 0) ||
01022       (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
01023       CLI_ERROR(v->name, v->value, cat);
01024       return;
01025    }
01026 
01027    for (; v; v = v->next) {
01028       if (!strcasecmp(v->name, "ports")) {
01029          char *token, *tmp = ast_strdupa(v->value);
01030          char ptpbuf[BUFFERSIZE] = "";
01031          int start, end;
01032          for (token = strsep(&tmp, ","); token; token = strsep(&tmp, ","), *ptpbuf = 0) {
01033             if (!*token)
01034                continue;
01035             if (sscanf(token, "%30d-%30d%511s", &start, &end, ptpbuf) >= 2) {
01036                for (; start <= end; start++) {
01037                   if (start <= max_ports && start > 0) {
01038                      cfg_for_ports[start] = 1;
01039                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
01040                   } else
01041                      CLI_ERROR(v->name, v->value, cat);
01042                }
01043             } else {
01044                if (sscanf(token, "%30d%511s", &start, ptpbuf)) {
01045                   if (start <= max_ports && start > 0) {
01046                      cfg_for_ports[start] = 1;
01047                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
01048                   } else
01049                      CLI_ERROR(v->name, v->value, cat);
01050                } else
01051                   CLI_ERROR(v->name, v->value, cat);
01052             }
01053          }
01054       } else {
01055          if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) ||
01056             (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
01057             CLI_ERROR(v->name, v->value, cat);
01058       }
01059    }
01060 
01061    for (i = 0; i < (max_ports + 1); ++i) {
01062       if (i > 0 && cfg_for_ports[0]) {
01063          /* default category, will populate the port_cfg with additional port
01064          categories in subsequent calls to this function */
01065          memset(cfg_tmp, 0, sizeof(cfg_tmp));
01066       }
01067       if (cfg_for_ports[i]) {
01068          memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp));
01069       }
01070    }
01071 }
01072 
01073 void misdn_cfg_update_ptp (void)
01074 {
01075 #ifndef MISDN_1_2
01076    char misdn_init[BUFFERSIZE];
01077    char line[BUFFERSIZE];
01078    FILE *fp;
01079    char *tok, *p, *end;
01080    int port;
01081 
01082    misdn_cfg_get(0, MISDN_GEN_MISDN_INIT, &misdn_init, sizeof(misdn_init));
01083 
01084    if (!ast_strlen_zero(misdn_init)) {
01085       fp = fopen(misdn_init, "r");
01086       if (fp) {
01087          while(fgets(line, sizeof(line), fp)) {
01088             if (!strncmp(line, "nt_ptp", 6)) {
01089                for (tok = strtok_r(line,",=", &p);
01090                    tok;
01091                    tok = strtok_r(NULL,",=", &p)) {
01092                   port = strtol(tok, &end, 10);
01093                   if (end != tok && misdn_cfg_is_port_valid(port)) {
01094                      misdn_cfg_lock();
01095                      ptp[port] = 1;
01096                      misdn_cfg_unlock();
01097                   }
01098                }
01099             }
01100          }
01101          fclose(fp);
01102       } else {
01103          ast_log(LOG_WARNING,"Couldn't open %s: %s\n", misdn_init, strerror(errno));
01104       }
01105    }
01106 #else
01107    int i;
01108    int proto;
01109    char filename[128];
01110    FILE *fp;
01111 
01112    for (i = 1; i <= max_ports; ++i) {
01113       snprintf(filename, sizeof(filename), "/sys/class/mISDN-stacks/st-%08x/protocol", i << 8);
01114       fp = fopen(filename, "r");
01115       if (!fp) {
01116          ast_log(LOG_WARNING, "Could not open %s: %s\n", filename, strerror(errno));
01117          continue;
01118       }
01119       if (fscanf(fp, "0x%08x", &proto) != 1)
01120          ast_log(LOG_WARNING, "Could not parse contents of %s!\n", filename);
01121       else
01122          ptp[i] = proto & 1<<5 ? 1 : 0;
01123       fclose(fp);
01124    }
01125 #endif
01126 }
01127 
01128 static void _fill_defaults (void)
01129 {
01130    int i;
01131 
01132    for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
01133       if (!port_cfg[0][i].any && strcasecmp(port_spec[i].def, NO_DEFAULT))
01134          _parse(&(port_cfg[0][i]), (char *)port_spec[i].def, port_spec[i].type, port_spec[i].boolint_def);
01135    }
01136    for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
01137       if (!general_cfg[i].any && strcasecmp(gen_spec[i].def, NO_DEFAULT))
01138          _parse(&(general_cfg[i]), (char *)gen_spec[i].def, gen_spec[i].type, gen_spec[i].boolint_def);
01139    }
01140 }
01141 
01142 void misdn_cfg_reload (void)
01143 {
01144    misdn_cfg_init(0, 1);
01145 }
01146 
01147 void misdn_cfg_destroy (void)
01148 {
01149    misdn_cfg_lock();
01150 
01151    _free_port_cfg();
01152    _free_general_cfg();
01153 
01154    ast_free(port_cfg);
01155    ast_free(general_cfg);
01156    ast_free(ptp);
01157    ast_free(map);
01158 
01159    misdn_cfg_unlock();
01160    ast_mutex_destroy(&config_mutex);
01161 }
01162 
01163 int misdn_cfg_init(int this_max_ports, int reload)
01164 {
01165    char config[] = "misdn.conf";
01166    char *cat, *p;
01167    int i;
01168    struct ast_config *cfg;
01169    struct ast_variable *v;
01170    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01171 
01172    if (!(cfg = ast_config_load2(config, "chan_misdn", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
01173       ast_log(LOG_WARNING, "missing or invalid file: misdn.conf\n");
01174       return -1;
01175    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
01176       return 0;
01177 
01178    ast_mutex_init(&config_mutex);
01179 
01180    /* Copy the default jb config over global_jbconf */
01181    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01182 
01183    misdn_cfg_lock();
01184 
01185    if (this_max_ports) {
01186       /* this is the first run */
01187       max_ports = this_max_ports;
01188       map = ast_calloc(MISDN_GEN_LAST + 1, sizeof(int));
01189       if (_enum_array_map())
01190          return -1;
01191       p = ast_calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
01192                      + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
01193       port_cfg = (union misdn_cfg_pt **)p;
01194       p += (max_ports + 1) * sizeof(union misdn_cfg_pt *);
01195       for (i = 0; i <= max_ports; ++i) {
01196          port_cfg[i] = (union misdn_cfg_pt *)p;
01197          p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt);
01198       }
01199       general_cfg = ast_calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01200       ptp = ast_calloc(max_ports + 1, sizeof(int));
01201    }
01202    else {
01203       /* misdn reload */
01204       _free_port_cfg();
01205       _free_general_cfg();
01206       memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1));
01207       memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01208       memset(ptp, 0, sizeof(int) * (max_ports + 1));
01209    }
01210 
01211    cat = ast_category_browse(cfg, NULL);
01212 
01213    while(cat) {
01214       v = ast_variable_browse(cfg, cat);
01215       if (!strcasecmp(cat, "general")) {
01216          _build_general_config(v);
01217       } else {
01218          _build_port_config(v, cat);
01219       }
01220       cat = ast_category_browse(cfg, cat);
01221    }
01222 
01223    _fill_defaults();
01224 
01225    misdn_cfg_unlock();
01226    ast_config_destroy(cfg);
01227 
01228    return 0;
01229 }
01230 
01231 struct ast_jb_conf *misdn_get_global_jbconf() {
01232    return &global_jbconf;
01233 }

Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1