Wed Apr 6 11:29:46 2011

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

Generated on Wed Apr 6 11:29:46 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7