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

Generated on Thu Jul 9 13:40:37 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7