Mon May 14 04:42:59 2007

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

Generated on Mon May 14 04:42:59 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1