Wed Mar 3 22:36:59 2010

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

Generated on 3 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1