Sat Mar 10 01:54:20 2012

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

Generated on Sat Mar 10 01:54:20 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7