Thu Apr 28 2011 16:56:47

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