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

Generated on Sat Jul 26 06:13:18 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1