Sat Aug 6 00:39:30 2011

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

Generated on Sat Aug 6 00:39:30 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7