Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:50 2007

Asterisk developer's documentation :: Codename Pineapple


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

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen