Mon Nov 24 15:34:19 2008

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

Generated on Mon Nov 24 15:34:19 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7