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

Generated on Tue Nov 4 13:20:20 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7