Fri Jul 24 00:40:59 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: 185127 $")
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 both values, the presentation indicators are used from\n"
00203       "\tAsterisks SetCallerPres application.\n"
00204       "\n"
00205       "\tscreen=0, presentation=0 -> callerid presented not screened\n"
00206       "\tscreen=1, presentation=1 -> callerid presented but screened (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 both values, the presentation indicators are used from\n"
00211       "\tAsterisks SetCallerPres application.\n"
00212       "\n"
00213       "\tscreen=0, presentation=0 -> callerid presented not screened\n"
00214       "\tscreen=1, presentation=1 -> callerid presented but screened (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             tempbuf[strlen(tempbuf)-2] = 0;
00798          }
00799          snprintf(buf, bufsize, " -> msns: %s", *tempbuf ? tempbuf : "none");
00800          break;
00801       case MISDN_CTYPE_STR:
00802          if ( port_cfg[port][place].str) {
00803             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[port][place].str);
00804          } else if (port_cfg[0][place].str) {
00805             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[0][place].str);
00806          } else {
00807             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00808          }
00809          break;
00810       }
00811    } else if (elem > MISDN_GEN_FIRST && elem < MISDN_GEN_LAST) {
00812       switch (gen_spec[place].type) {
00813       case MISDN_CTYPE_INT:
00814       case MISDN_CTYPE_BOOLINT:
00815          if (general_cfg[place].num)
00816             snprintf(buf, bufsize, " -> %s: %d", gen_spec[place].name, *general_cfg[place].num);
00817          else
00818             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00819          break;
00820       case MISDN_CTYPE_BOOL:
00821          if (general_cfg[place].num)
00822             snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, *general_cfg[place].num ? "yes" : "no");
00823          else
00824             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00825          break;
00826       case MISDN_CTYPE_STR:
00827          if ( general_cfg[place].str) {
00828             snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, general_cfg[place].str);
00829          } else {
00830             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00831          }
00832          break;
00833       default:
00834          snprintf(buf, bufsize, " -> type of %s not handled yet", gen_spec[place].name);
00835          break;
00836       }
00837    } else {
00838       *buf = 0;
00839       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Invalid config element (%d) requested.\n", elem);
00840    }
00841    misdn_cfg_unlock();
00842 }
00843 
00844 int misdn_cfg_get_next_port (int port)
00845 {
00846    int p = -1;
00847    int gn = map[MISDN_CFG_GROUPNAME];
00848    
00849    misdn_cfg_lock();
00850    for (port++; port <= max_ports; port++) {
00851       if (port_cfg[port][gn].str) {
00852          p = port;
00853          break;
00854       }
00855    }
00856    misdn_cfg_unlock();
00857 
00858    return p;
00859 }
00860 
00861 int misdn_cfg_get_next_port_spin (int port)
00862 {
00863    int p = misdn_cfg_get_next_port(port);
00864    return (p > 0) ? p : misdn_cfg_get_next_port(0);
00865 }
00866 
00867 static int _parse (union misdn_cfg_pt *dest, const char *value, enum misdn_cfg_type type, int boolint_def)
00868 {
00869    int re = 0;
00870    int len, tmp;
00871    char *valtmp;
00872    char *tmp2 = ast_strdupa(value);
00873 
00874    switch (type) {
00875    case MISDN_CTYPE_STR:
00876       if ((len = strlen(value))) {
00877          dest->str = ast_malloc((len + 1) * sizeof(char));
00878          strncpy(dest->str, value, len);
00879          dest->str[len] = 0;
00880       } else {
00881          dest->str = ast_malloc(sizeof(char));
00882          dest->str[0] = 0;
00883       }
00884       break;
00885    case MISDN_CTYPE_INT:
00886    {
00887       int res;
00888 
00889       if (strchr(value,'x')) {
00890          res = sscanf(value, "%x", &tmp);
00891       } else {
00892          res = sscanf(value, "%d", &tmp);
00893       }
00894       if (res) {
00895          dest->num = ast_malloc(sizeof(int));
00896          memcpy(dest->num, &tmp, sizeof(int));
00897       } else
00898          re = -1;
00899    }
00900       break;
00901    case MISDN_CTYPE_BOOL:
00902       dest->num = ast_malloc(sizeof(int));
00903       *(dest->num) = (ast_true(value) ? 1 : 0);
00904       break;
00905    case MISDN_CTYPE_BOOLINT:
00906       dest->num = ast_malloc(sizeof(int));
00907       if (sscanf(value, "%d", &tmp)) {
00908          memcpy(dest->num, &tmp, sizeof(int));
00909       } else {
00910          *(dest->num) = (ast_true(value) ? boolint_def : 0);
00911       }
00912       break;
00913    case MISDN_CTYPE_MSNLIST:
00914       for (valtmp = strsep(&tmp2, ","); valtmp; valtmp = strsep(&tmp2, ",")) {
00915          if ((len = strlen(valtmp))) {
00916             struct msn_list *ml = ast_malloc(sizeof(*ml));
00917             ml->msn = ast_calloc(len+1, sizeof(char));
00918             strncpy(ml->msn, valtmp, len);
00919             ml->next = dest->ml;
00920             dest->ml = ml;
00921          }
00922       }
00923       break;
00924    case MISDN_CTYPE_ASTGROUP:
00925       dest->grp = ast_malloc(sizeof(ast_group_t));
00926       *(dest->grp) = ast_get_group(value);
00927       break;
00928    }
00929 
00930    return re;
00931 }
00932 
00933 static void _build_general_config (struct ast_variable *v)
00934 {
00935    int pos;
00936 
00937    for (; v; v = v->next) {
00938       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
00939          continue;
00940       if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) || 
00941          (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0))
00942          CLI_ERROR(v->name, v->value, "general");
00943    }
00944 }
00945 
00946 static void _build_port_config (struct ast_variable *v, char *cat)
00947 {
00948    int pos, i;
00949    union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS];
00950    int cfg_for_ports[max_ports + 1];
00951 
00952    if (!v || !cat)
00953       return;
00954 
00955    memset(cfg_tmp, 0, sizeof(cfg_tmp));
00956    memset(cfg_for_ports, 0, sizeof(cfg_for_ports));
00957 
00958    if (!strcasecmp(cat, "default")) {
00959       cfg_for_ports[0] = 1;
00960    }
00961 
00962    if (((pos = get_cfg_position("name", PORT_CFG)) < 0) || 
00963       (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
00964       CLI_ERROR(v->name, v->value, cat);
00965       return;
00966    }
00967 
00968    for (; v; v = v->next) {
00969       if (!strcasecmp(v->name, "ports")) {
00970          char *token, *tmp = ast_strdupa(v->value);
00971          char ptpbuf[BUFFERSIZE] = "";
00972          int start, end;
00973          for (token = strsep(&tmp, ","); token; token = strsep(&tmp, ","), *ptpbuf = 0) { 
00974             if (!*token)
00975                continue;
00976             if (sscanf(token, "%d-%d%s", &start, &end, ptpbuf) >= 2) {
00977                for (; start <= end; start++) {
00978                   if (start <= max_ports && start > 0) {
00979                      cfg_for_ports[start] = 1;
00980                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
00981                   } else
00982                      CLI_ERROR(v->name, v->value, cat);
00983                }
00984             } else {
00985                if (sscanf(token, "%d%s", &start, ptpbuf)) {
00986                   if (start <= max_ports && start > 0) {
00987                      cfg_for_ports[start] = 1;
00988                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
00989                   } else
00990                      CLI_ERROR(v->name, v->value, cat);
00991                } else
00992                   CLI_ERROR(v->name, v->value, cat);
00993             }
00994          }
00995       } else {
00996          if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) || 
00997             (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
00998             CLI_ERROR(v->name, v->value, cat);
00999       }
01000    }
01001 
01002    for (i = 0; i < (max_ports + 1); ++i) {
01003       if (cfg_for_ports[i]) {
01004          memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp));
01005       }
01006    }
01007 }
01008 
01009 void misdn_cfg_update_ptp (void)
01010 {
01011 #ifndef MISDN_1_2
01012    char misdn_init[BUFFERSIZE];
01013    char line[BUFFERSIZE];
01014    FILE *fp;
01015    char *tok, *p, *end;
01016    int port;
01017 
01018    misdn_cfg_get(0, MISDN_GEN_MISDN_INIT, &misdn_init, sizeof(misdn_init));
01019 
01020    if (!ast_strlen_zero(misdn_init)) {
01021       fp = fopen(misdn_init, "r");
01022       if (fp) {
01023          while(fgets(line, sizeof(line), fp)) {
01024             if (!strncmp(line, "nt_ptp", 6)) {
01025                for (tok = strtok_r(line,",=", &p);
01026                    tok;
01027                    tok = strtok_r(NULL,",=", &p)) {
01028                   port = strtol(tok, &end, 10);
01029                   if (end != tok && misdn_cfg_is_port_valid(port)) {
01030                      misdn_cfg_lock();
01031                      ptp[port] = 1;
01032                      misdn_cfg_unlock();
01033                   }
01034                }
01035             }
01036          }
01037          fclose(fp);
01038       } else {
01039          ast_log(LOG_WARNING,"Couldn't open %s: %s\n", misdn_init, strerror(errno));
01040       }
01041    }
01042 #else
01043    int i;
01044    int proto;
01045    char filename[128];
01046    FILE *fp;
01047 
01048    for (i = 1; i <= max_ports; ++i) {
01049       snprintf(filename, sizeof(filename), "/sys/class/mISDN-stacks/st-%08x/protocol", i << 8);
01050       fp = fopen(filename, "r");
01051       if (!fp) {
01052          ast_log(LOG_WARNING, "Could not open %s: %s\n", filename, strerror(errno));
01053          continue;
01054       }
01055       if (fscanf(fp, "0x%08x", &proto) != 1)
01056          ast_log(LOG_WARNING, "Could not parse contents of %s!\n", filename);
01057       else
01058          ptp[i] = proto & 1<<5 ? 1 : 0;
01059       fclose(fp);
01060    }
01061 #endif
01062 }
01063 
01064 static void _fill_defaults (void)
01065 {
01066    int i;
01067 
01068    for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
01069       if (!port_cfg[0][i].any && strcasecmp(port_spec[i].def, NO_DEFAULT))
01070          _parse(&(port_cfg[0][i]), (char *)port_spec[i].def, port_spec[i].type, port_spec[i].boolint_def);
01071    }
01072    for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
01073       if (!general_cfg[i].any && strcasecmp(gen_spec[i].def, NO_DEFAULT))
01074          _parse(&(general_cfg[i]), (char *)gen_spec[i].def, gen_spec[i].type, gen_spec[i].boolint_def);
01075    }
01076 }
01077 
01078 void misdn_cfg_reload (void)
01079 {
01080    misdn_cfg_init(0, 1);
01081 }
01082 
01083 void misdn_cfg_destroy (void)
01084 {
01085    misdn_cfg_lock();
01086 
01087    _free_port_cfg();
01088    _free_general_cfg();
01089 
01090    ast_free(port_cfg);
01091    ast_free(general_cfg);
01092    ast_free(ptp);
01093    ast_free(map);
01094 
01095    misdn_cfg_unlock();
01096    ast_mutex_destroy(&config_mutex);
01097 }
01098 
01099 int misdn_cfg_init(int this_max_ports, int reload)
01100 {
01101    char config[] = "misdn.conf";
01102    char *cat, *p;
01103    int i;
01104    struct ast_config *cfg;
01105    struct ast_variable *v;
01106    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01107 
01108    if (!(cfg = ast_config_load2(config, "chan_misdn", config_flags))) {
01109       ast_log(LOG_WARNING, "missing file: misdn.conf\n");
01110       return -1;
01111    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
01112       return 0;
01113 
01114    ast_mutex_init(&config_mutex);
01115 
01116    /* Copy the default jb config over global_jbconf */
01117    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01118 
01119    misdn_cfg_lock();
01120 
01121    if (this_max_ports) {
01122       /* this is the first run */
01123       max_ports = this_max_ports;
01124       map = ast_calloc(MISDN_GEN_LAST + 1, sizeof(int));
01125       if (_enum_array_map())
01126          return -1;
01127       p = ast_calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
01128                      + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
01129       port_cfg = (union misdn_cfg_pt **)p;
01130       p += (max_ports + 1) * sizeof(union misdn_cfg_pt *);
01131       for (i = 0; i <= max_ports; ++i) {
01132          port_cfg[i] = (union misdn_cfg_pt *)p;
01133          p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt);
01134       }
01135       general_cfg = ast_calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01136       ptp = ast_calloc(max_ports + 1, sizeof(int));
01137    }
01138    else {
01139       /* misdn reload */
01140       _free_port_cfg();
01141       _free_general_cfg();
01142       memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1));
01143       memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01144       memset(ptp, 0, sizeof(int) * (max_ports + 1));
01145    }
01146 
01147    cat = ast_category_browse(cfg, NULL);
01148 
01149    while(cat) {
01150       v = ast_variable_browse(cfg, cat);
01151       if (!strcasecmp(cat, "general")) {
01152          _build_general_config(v);
01153       } else {
01154          _build_port_config(v, cat);
01155       }
01156       cat = ast_category_browse(cfg, cat);
01157    }
01158 
01159    _fill_defaults();
01160 
01161    misdn_cfg_unlock();
01162    ast_config_destroy(cfg);
01163 
01164    return 0;
01165 }
01166 
01167 struct ast_jb_conf *misdn_get_global_jbconf() {
01168    return &global_jbconf;
01169 }

Generated on Fri Jul 24 00:40:59 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7