Wed Oct 28 11:51:05 2009

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: 222801 $")
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 (dest->str) {
00879          ast_free(dest->str);
00880       }
00881       if ((len = strlen(value))) {
00882          dest->str = ast_malloc((len + 1) * sizeof(char));
00883          strncpy(dest->str, value, len);
00884          dest->str[len] = 0;
00885       } else {
00886          dest->str = ast_malloc(sizeof(char));
00887          dest->str[0] = 0;
00888       }
00889       break;
00890    case MISDN_CTYPE_INT:
00891    {
00892       int res;
00893 
00894       if (strchr(value,'x')) {
00895          res = sscanf(value, "%30x", &tmp);
00896       } else {
00897          res = sscanf(value, "%30d", &tmp);
00898       }
00899       if (res) {
00900          if (!dest->num) {
00901             dest->num = ast_malloc(sizeof(int));
00902          }
00903          memcpy(dest->num, &tmp, sizeof(int));
00904       } else
00905          re = -1;
00906    }
00907       break;
00908    case MISDN_CTYPE_BOOL:
00909       if (!dest->num) {
00910          dest->num = ast_malloc(sizeof(int));
00911       }
00912       *(dest->num) = (ast_true(value) ? 1 : 0);
00913       break;
00914    case MISDN_CTYPE_BOOLINT:
00915       if (!dest->num) {
00916          dest->num = ast_malloc(sizeof(int));
00917       }
00918       if (sscanf(value, "%30d", &tmp)) {
00919          memcpy(dest->num, &tmp, sizeof(int));
00920       } else {
00921          *(dest->num) = (ast_true(value) ? boolint_def : 0);
00922       }
00923       break;
00924    case MISDN_CTYPE_MSNLIST:
00925       for (valtmp = strsep(&tmp2, ","); valtmp; valtmp = strsep(&tmp2, ",")) {
00926          if ((len = strlen(valtmp))) {
00927             struct msn_list *ml = ast_malloc(sizeof(*ml));
00928             ml->msn = ast_calloc(len+1, sizeof(char));
00929             strncpy(ml->msn, valtmp, len);
00930             ml->next = dest->ml;
00931             dest->ml = ml;
00932          }
00933       }
00934       break;
00935    case MISDN_CTYPE_ASTGROUP:
00936       if (!dest->grp) {
00937          dest->grp = ast_malloc(sizeof(ast_group_t));
00938       }
00939       *(dest->grp) = ast_get_group(value);
00940       break;
00941    }
00942 
00943    return re;
00944 }
00945 
00946 static void _build_general_config (struct ast_variable *v)
00947 {
00948    int pos;
00949 
00950    for (; v; v = v->next) {
00951       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
00952          continue;
00953       if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) || 
00954          (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0))
00955          CLI_ERROR(v->name, v->value, "general");
00956    }
00957 }
00958 
00959 static void _build_port_config (struct ast_variable *v, char *cat)
00960 {
00961    int pos, i;
00962    union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS];
00963    int cfg_for_ports[max_ports + 1];
00964 
00965    if (!v || !cat)
00966       return;
00967 
00968    memset(cfg_tmp, 0, sizeof(cfg_tmp));
00969    memset(cfg_for_ports, 0, sizeof(cfg_for_ports));
00970 
00971    if (!strcasecmp(cat, "default")) {
00972       cfg_for_ports[0] = 1;
00973    }
00974 
00975    if (((pos = get_cfg_position("name", PORT_CFG)) < 0) || 
00976       (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
00977       CLI_ERROR(v->name, v->value, cat);
00978       return;
00979    }
00980 
00981    for (; v; v = v->next) {
00982       if (!strcasecmp(v->name, "ports")) {
00983          char *token, *tmp = ast_strdupa(v->value);
00984          char ptpbuf[BUFFERSIZE] = "";
00985          int start, end;
00986          for (token = strsep(&tmp, ","); token; token = strsep(&tmp, ","), *ptpbuf = 0) { 
00987             if (!*token)
00988                continue;
00989             if (sscanf(token, "%30d-%30d%511s", &start, &end, ptpbuf) >= 2) {
00990                for (; start <= end; start++) {
00991                   if (start <= max_ports && start > 0) {
00992                      cfg_for_ports[start] = 1;
00993                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
00994                   } else
00995                      CLI_ERROR(v->name, v->value, cat);
00996                }
00997             } else {
00998                if (sscanf(token, "%30d%511s", &start, ptpbuf)) {
00999                   if (start <= max_ports && start > 0) {
01000                      cfg_for_ports[start] = 1;
01001                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
01002                   } else
01003                      CLI_ERROR(v->name, v->value, cat);
01004                } else
01005                   CLI_ERROR(v->name, v->value, cat);
01006             }
01007          }
01008       } else {
01009          if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) || 
01010             (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
01011             CLI_ERROR(v->name, v->value, cat);
01012       }
01013    }
01014 
01015    for (i = 0; i < (max_ports + 1); ++i) {
01016       if (i > 0 && cfg_for_ports[0]) {
01017          /* default category, will populate the port_cfg with additional port
01018          categories in subsequent calls to this function */
01019          memset(cfg_tmp, 0, sizeof(cfg_tmp));
01020       }
01021       if (cfg_for_ports[i]) {
01022          memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp));
01023       }
01024    }
01025 }
01026 
01027 void misdn_cfg_update_ptp (void)
01028 {
01029 #ifndef MISDN_1_2
01030    char misdn_init[BUFFERSIZE];
01031    char line[BUFFERSIZE];
01032    FILE *fp;
01033    char *tok, *p, *end;
01034    int port;
01035 
01036    misdn_cfg_get(0, MISDN_GEN_MISDN_INIT, &misdn_init, sizeof(misdn_init));
01037 
01038    if (!ast_strlen_zero(misdn_init)) {
01039       fp = fopen(misdn_init, "r");
01040       if (fp) {
01041          while(fgets(line, sizeof(line), fp)) {
01042             if (!strncmp(line, "nt_ptp", 6)) {
01043                for (tok = strtok_r(line,",=", &p);
01044                    tok;
01045                    tok = strtok_r(NULL,",=", &p)) {
01046                   port = strtol(tok, &end, 10);
01047                   if (end != tok && misdn_cfg_is_port_valid(port)) {
01048                      misdn_cfg_lock();
01049                      ptp[port] = 1;
01050                      misdn_cfg_unlock();
01051                   }
01052                }
01053             }
01054          }
01055          fclose(fp);
01056       } else {
01057          ast_log(LOG_WARNING,"Couldn't open %s: %s\n", misdn_init, strerror(errno));
01058       }
01059    }
01060 #else
01061    int i;
01062    int proto;
01063    char filename[128];
01064    FILE *fp;
01065 
01066    for (i = 1; i <= max_ports; ++i) {
01067       snprintf(filename, sizeof(filename), "/sys/class/mISDN-stacks/st-%08x/protocol", i << 8);
01068       fp = fopen(filename, "r");
01069       if (!fp) {
01070          ast_log(LOG_WARNING, "Could not open %s: %s\n", filename, strerror(errno));
01071          continue;
01072       }
01073       if (fscanf(fp, "0x%08x", &proto) != 1)
01074          ast_log(LOG_WARNING, "Could not parse contents of %s!\n", filename);
01075       else
01076          ptp[i] = proto & 1<<5 ? 1 : 0;
01077       fclose(fp);
01078    }
01079 #endif
01080 }
01081 
01082 static void _fill_defaults (void)
01083 {
01084    int i;
01085 
01086    for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
01087       if (!port_cfg[0][i].any && strcasecmp(port_spec[i].def, NO_DEFAULT))
01088          _parse(&(port_cfg[0][i]), (char *)port_spec[i].def, port_spec[i].type, port_spec[i].boolint_def);
01089    }
01090    for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
01091       if (!general_cfg[i].any && strcasecmp(gen_spec[i].def, NO_DEFAULT))
01092          _parse(&(general_cfg[i]), (char *)gen_spec[i].def, gen_spec[i].type, gen_spec[i].boolint_def);
01093    }
01094 }
01095 
01096 void misdn_cfg_reload (void)
01097 {
01098    misdn_cfg_init(0, 1);
01099 }
01100 
01101 void misdn_cfg_destroy (void)
01102 {
01103    misdn_cfg_lock();
01104 
01105    _free_port_cfg();
01106    _free_general_cfg();
01107 
01108    ast_free(port_cfg);
01109    ast_free(general_cfg);
01110    ast_free(ptp);
01111    ast_free(map);
01112 
01113    misdn_cfg_unlock();
01114    ast_mutex_destroy(&config_mutex);
01115 }
01116 
01117 int misdn_cfg_init(int this_max_ports, int reload)
01118 {
01119    char config[] = "misdn.conf";
01120    char *cat, *p;
01121    int i;
01122    struct ast_config *cfg;
01123    struct ast_variable *v;
01124    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01125 
01126    if (!(cfg = ast_config_load2(config, "chan_misdn", config_flags))) {
01127       ast_log(LOG_WARNING, "missing file: misdn.conf\n");
01128       return -1;
01129    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
01130       return 0;
01131 
01132    ast_mutex_init(&config_mutex);
01133 
01134    /* Copy the default jb config over global_jbconf */
01135    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01136 
01137    misdn_cfg_lock();
01138 
01139    if (this_max_ports) {
01140       /* this is the first run */
01141       max_ports = this_max_ports;
01142       map = ast_calloc(MISDN_GEN_LAST + 1, sizeof(int));
01143       if (_enum_array_map())
01144          return -1;
01145       p = ast_calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
01146                      + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
01147       port_cfg = (union misdn_cfg_pt **)p;
01148       p += (max_ports + 1) * sizeof(union misdn_cfg_pt *);
01149       for (i = 0; i <= max_ports; ++i) {
01150          port_cfg[i] = (union misdn_cfg_pt *)p;
01151          p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt);
01152       }
01153       general_cfg = ast_calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01154       ptp = ast_calloc(max_ports + 1, sizeof(int));
01155    }
01156    else {
01157       /* misdn reload */
01158       _free_port_cfg();
01159       _free_general_cfg();
01160       memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1));
01161       memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01162       memset(ptp, 0, sizeof(int) * (max_ports + 1));
01163    }
01164 
01165    cat = ast_category_browse(cfg, NULL);
01166 
01167    while(cat) {
01168       v = ast_variable_browse(cfg, cat);
01169       if (!strcasecmp(cat, "general")) {
01170          _build_general_config(v);
01171       } else {
01172          _build_port_config(v, cat);
01173       }
01174       cat = ast_category_browse(cfg, cat);
01175    }
01176 
01177    _fill_defaults();
01178 
01179    misdn_cfg_unlock();
01180    ast_config_destroy(cfg);
01181 
01182    return 0;
01183 }
01184 
01185 struct ast_jb_conf *misdn_get_global_jbconf() {
01186    return &global_jbconf;
01187 }

Generated on Wed Oct 28 11:51:05 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6