Fri Aug 24 02:22:15 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    { "bridging", MISDN_CFG_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE,
00318       "Set this to yes/no, default is yes.\n"
00319       "This can be used to have bridging enabled in general and to\n"
00320       "disable it for specific ports. It makes sense to disable\n"
00321       "bridging on NT Port where you plan to use the HOLD/RETRIEVE\n"
00322       "features with ISDN phones.\n"
00323       },
00324    { "msns", MISDN_CFG_MSNS, MISDN_CTYPE_MSNLIST, "*", NONE,
00325       "MSN's for TE ports, listen on those numbers on the above ports, and\n"
00326       "\tindicate the incoming calls to Asterisk.\n"
00327       "\tHere you can give a comma seperated list, or simply an '*' for any msn." },
00328 };
00329 
00330 static const struct misdn_cfg_spec gen_spec[] = {
00331    { "debug", MISDN_GEN_DEBUG, MISDN_CTYPE_INT, "0", NONE,
00332       "Sets the debugging flag:\n"
00333       "\t0 - No Debug\n"
00334       "\t1 - mISDN Messages and * - Messages, and * - State changes\n"
00335       "\t2 - Messages + Message specific Informations (e.g. bearer capability)\n"
00336       "\t3 - very Verbose, the above + lots of Driver specific infos\n"
00337       "\t4 - even more Verbose than 3" },
00338 #ifndef MISDN_1_2
00339    { "misdn_init", MISDN_GEN_MISDN_INIT, MISDN_CTYPE_STR, "/etc/misdn-init.conf", NONE,
00340       "Set the path to the misdn-init.conf (for nt_ptp mode checking)." },
00341 #endif
00342    { "tracefile", MISDN_GEN_TRACEFILE, MISDN_CTYPE_STR, "/var/log/asterisk/misdn.log", NONE,
00343       "Set the path to the massively growing trace file, if you want that." },
00344    { "bridging", MISDN_GEN_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE,
00345       "Set this to yes if you want mISDN_dsp to bridge the calls in HW." },
00346    { "stop_tone_after_first_digit", MISDN_GEN_STOP_TONE, MISDN_CTYPE_BOOL, "yes", NONE,
00347       "Stops dialtone after getting first digit on NT Port." },
00348    { "append_digits2exten", MISDN_GEN_APPEND_DIGITS2EXTEN, MISDN_CTYPE_BOOL, "yes", NONE,
00349       "Wether to append overlapdialed Digits to Extension or not." },
00350    { "dynamic_crypt", MISDN_GEN_DYNAMIC_CRYPT, MISDN_CTYPE_BOOL, "no", NONE,
00351       "Wether to look out for dynamic crypting attempts." },
00352    { "crypt_prefix", MISDN_GEN_CRYPT_PREFIX, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
00353       "What is used for crypting Protocol." },
00354    { "crypt_keys", MISDN_GEN_CRYPT_KEYS, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
00355       "Keys for cryption, you reference them in the dialplan\n"
00356       "\tLater also in dynamic encr." },
00357    { "ntdebugflags", MISDN_GEN_NTDEBUGFLAGS, MISDN_CTYPE_INT, "0", NONE,
00358       "No description yet."},
00359    { "ntdebugfile", MISDN_GEN_NTDEBUGFILE, MISDN_CTYPE_STR, "/var/log/misdn-nt.log", NONE,
00360       "No description yet." }
00361 };
00362 
00363 
00364 /* array of port configs, default is at position 0. */
00365 static union misdn_cfg_pt **port_cfg;
00366 /* max number of available ports, is set on init */
00367 static int max_ports;
00368 /* general config */
00369 static union misdn_cfg_pt *general_cfg;
00370 /* storing the ptp flag separated to save memory */
00371 static int *ptp;
00372 /* maps enum config elements to array positions */
00373 static int *map;
00374 
00375 static ast_mutex_t config_mutex; 
00376 
00377 #define CLI_ERROR(name, value, section) ({ \
00378    ast_log(LOG_WARNING, "misdn.conf: \"%s=%s\" (section: %s) invalid or out of range. " \
00379       "Please edit your misdn.conf and then do a \"misdn reload\".\n", name, value, section); \
00380 })
00381 
00382 static int _enum_array_map (void)
00383 {
00384    int i, j, ok;
00385 
00386    for (i = MISDN_CFG_FIRST + 1; i < MISDN_CFG_LAST; ++i) {
00387       if (i == MISDN_CFG_PTP)
00388          continue;
00389       ok = 0;
00390       for (j = 0; j < NUM_PORT_ELEMENTS; ++j) {
00391          if (port_spec[j].elem == i) {
00392             map[i] = j;
00393             ok = 1;
00394             break;
00395          }
00396       }
00397       if (!ok) {
00398          ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (port section) has no corresponding element in the config struct!\n", i);
00399          return -1;
00400       }
00401    }
00402    for (i = MISDN_GEN_FIRST + 1; i < MISDN_GEN_LAST; ++i) {
00403       ok = 0;
00404       for (j = 0; j < NUM_GEN_ELEMENTS; ++j) {
00405          if (gen_spec[j].elem == i) {
00406             map[i] = j;
00407             ok = 1;
00408             break;
00409          }
00410       }
00411       if (!ok) {
00412          ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (general section) has no corresponding element in the config struct!\n", i);
00413          return -1;
00414       }
00415    }
00416    return 0;
00417 }
00418 
00419 static int get_cfg_position (char *name, int type)
00420 {
00421    int i;
00422 
00423    switch (type) {
00424    case PORT_CFG:
00425       for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
00426          if (!strcasecmp(name, port_spec[i].name))
00427             return i;
00428       }
00429       break;
00430    case GEN_CFG:
00431       for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
00432          if (!strcasecmp(name, gen_spec[i].name))
00433             return i;
00434       }
00435    }
00436 
00437    return -1;
00438 }
00439 
00440 static inline void misdn_cfg_lock (void)
00441 {
00442    ast_mutex_lock(&config_mutex);
00443 }
00444 
00445 static inline void misdn_cfg_unlock (void)
00446 {
00447    ast_mutex_unlock(&config_mutex);
00448 }
00449 
00450 static void _free_msn_list (struct msn_list* iter)
00451 {
00452    if (iter->next)
00453       _free_msn_list(iter->next);
00454    if (iter->msn)
00455       free(iter->msn);
00456    free(iter);
00457 }
00458 
00459 static void _free_port_cfg (void)
00460 {
00461    int i, j;
00462    int gn = map[MISDN_CFG_GROUPNAME];
00463    union misdn_cfg_pt* free_list[max_ports + 2];
00464    
00465    memset(free_list, 0, sizeof(free_list));
00466    free_list[0] = port_cfg[0];
00467    for (i = 1; i <= max_ports; ++i) {
00468       if (port_cfg[i][gn].str) {
00469          /* we always have a groupname in the non-default case, so this is fine */
00470          for (j = 1; j <= max_ports; ++j) {
00471             if (free_list[j] && free_list[j][gn].str == port_cfg[i][gn].str)
00472                break;
00473             else if (!free_list[j]) {
00474                free_list[j] = port_cfg[i];
00475                break;
00476             }
00477          }
00478       }
00479    }
00480    for (j = 0; free_list[j]; ++j) {
00481       for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
00482          if (free_list[j][i].any) {
00483             if (port_spec[i].type == MISDN_CTYPE_MSNLIST)
00484                _free_msn_list(free_list[j][i].ml);
00485             else
00486                free(free_list[j][i].any);
00487          }
00488       }
00489    }
00490 }
00491 
00492 static void _free_general_cfg (void)
00493 {
00494    int i;
00495 
00496    for (i = 0; i < NUM_GEN_ELEMENTS; i++) 
00497       if (general_cfg[i].any)
00498          free(general_cfg[i].any);
00499 }
00500 
00501 void misdn_cfg_get (int port, enum misdn_cfg_elements elem, void *buf, int bufsize)
00502 {
00503    int place;
00504 
00505    if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
00506       memset(buf, 0, bufsize);
00507       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Port number %d is not valid.\n", port);
00508       return;
00509    }
00510 
00511    misdn_cfg_lock();
00512    if (elem == MISDN_CFG_PTP) {
00513       if (!memcpy(buf, &ptp[port], (bufsize > ptp[port]) ? sizeof(ptp[port]) : bufsize))
00514          memset(buf, 0, bufsize);
00515    } else {
00516       if ((place = map[elem]) < 0) {
00517          memset (buf, 0, bufsize);
00518          ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Invalid element (%d) requested.\n", elem);
00519       } else {
00520          if (elem < MISDN_CFG_LAST) {
00521             switch (port_spec[place].type) {
00522             case MISDN_CTYPE_STR:
00523                if (port_cfg[port][place].str) {
00524                   if (!memccpy(buf, port_cfg[port][place].str, 0, bufsize))
00525                      memset(buf, 0, 1);
00526                } else if (port_cfg[0][place].str) {
00527                   if (!memccpy(buf, port_cfg[0][place].str, 0, bufsize))
00528                      memset(buf, 0, 1);
00529                }
00530                break;
00531             default:
00532                if (port_cfg[port][place].any)
00533                   memcpy(buf, port_cfg[port][place].any, bufsize);
00534                else if (port_cfg[0][place].any)
00535                   memcpy(buf, port_cfg[0][place].any, bufsize);
00536                else
00537                   memset(buf, 0, bufsize);
00538             }
00539          } else {
00540             switch (gen_spec[place].type) {
00541             case MISDN_CTYPE_STR:
00542                if (!general_cfg[place].str || !memccpy(buf, general_cfg[place].str, 0, bufsize))
00543                   memset(buf, 0, 1);
00544                break;
00545             default:
00546                if (general_cfg[place].any)
00547                   memcpy(buf, general_cfg[place].any, bufsize);
00548                else
00549                   memset(buf, 0, bufsize);
00550             }
00551          }
00552       }
00553    }
00554    misdn_cfg_unlock();
00555 }
00556 
00557 enum misdn_cfg_elements misdn_cfg_get_elem (char *name)
00558 {
00559    int pos;
00560 
00561    /* here comes a hack to replace the (not existing) "name" elemet with the "ports" element */
00562    if (!strcmp(name, "ports"))
00563       return MISDN_CFG_GROUPNAME;
00564    if (!strcmp(name, "name"))
00565       return MISDN_CFG_FIRST;
00566 
00567    pos = get_cfg_position (name, PORT_CFG);
00568    if (pos >= 0)
00569       return port_spec[pos].elem;
00570    
00571    pos = get_cfg_position (name, GEN_CFG);
00572    if (pos >= 0)
00573       return gen_spec[pos].elem;
00574    
00575    return MISDN_CFG_FIRST;
00576 }
00577 
00578 void misdn_cfg_get_name (enum misdn_cfg_elements elem, void *buf, int bufsize)
00579 {
00580    struct misdn_cfg_spec *spec = NULL;
00581    int place = map[elem];
00582 
00583    /* the ptp hack */
00584    if (elem == MISDN_CFG_PTP) {
00585       memset(buf, 0, 1);
00586       return;
00587    }
00588    
00589    /* here comes a hack to replace the (not existing) "name" elemet with the "ports" element */
00590    if (elem == MISDN_CFG_GROUPNAME) {
00591       if (!snprintf(buf, bufsize, "ports"))
00592          memset(buf, 0, 1);
00593       return;
00594    }
00595    
00596    if ((elem > MISDN_CFG_FIRST) && (elem < MISDN_CFG_LAST))
00597       spec = (struct misdn_cfg_spec *)port_spec;
00598    else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST))
00599       spec = (struct misdn_cfg_spec *)gen_spec;
00600 
00601    if (!spec || !memccpy(buf, spec[place].name, 0, bufsize))
00602       memset(buf, 0, 1);
00603 }
00604 
00605 void misdn_cfg_get_desc (enum misdn_cfg_elements elem, void *buf, int bufsize, void *buf_default, int bufsize_default)
00606 {
00607    int place = map[elem];
00608    struct misdn_cfg_spec *spec = NULL;
00609 
00610    /* here comes a hack to replace the (not existing) "name" elemet with the "ports" element */
00611    if (elem == MISDN_CFG_GROUPNAME) {
00612       if (!memccpy(buf, ports_description, 0, bufsize))
00613          memset(buf, 0, 1);
00614       if (buf_default && bufsize_default)
00615          memset(buf_default, 0, 1);
00616       return;
00617    }
00618 
00619    if ((elem > MISDN_CFG_FIRST) && (elem < MISDN_CFG_LAST))
00620       spec = (struct misdn_cfg_spec *)port_spec;
00621    else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST))
00622       spec = (struct misdn_cfg_spec *)gen_spec;
00623       
00624    if (!spec || !spec[place].desc)
00625       memset(buf, 0, 1);
00626    else {
00627       if (!memccpy(buf, spec[place].desc, 0, bufsize))
00628          memset(buf, 0, 1);
00629       if (buf_default && bufsize) {
00630          if (!strcmp(spec[place].def, NO_DEFAULT))
00631             memset(buf_default, 0, 1);
00632          else if (!memccpy(buf_default, spec[place].def, 0, bufsize_default))
00633             memset(buf_default, 0, 1);
00634       }
00635    }
00636 }
00637 
00638 int misdn_cfg_is_msn_valid (int port, char* msn)
00639 {
00640    int re = 0;
00641    struct msn_list *iter;
00642 
00643    if (!misdn_cfg_is_port_valid(port)) {
00644       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_is_msn_valid! Port number %d is not valid.\n", port);
00645       return 0;
00646    }
00647 
00648    misdn_cfg_lock();
00649    if (port_cfg[port][map[MISDN_CFG_MSNS]].ml)
00650       iter = port_cfg[port][map[MISDN_CFG_MSNS]].ml;
00651    else
00652       iter = port_cfg[0][map[MISDN_CFG_MSNS]].ml;
00653    for (; iter; iter = iter->next) 
00654       if (*(iter->msn) == '*' || ast_extension_match(iter->msn, msn)) {
00655          re = 1;
00656          break;
00657       }
00658    misdn_cfg_unlock();
00659 
00660    return re;
00661 }
00662 
00663 int misdn_cfg_is_port_valid (int port)
00664 {
00665    int gn = map[MISDN_CFG_GROUPNAME];
00666 
00667    return (port >= 1 && port <= max_ports && port_cfg[port][gn].str);
00668 }
00669 
00670 int misdn_cfg_is_group_method (char *group, enum misdn_cfg_method meth)
00671 {
00672    int i, re = 0;
00673    char *method ;
00674 
00675    misdn_cfg_lock();
00676 
00677    method = port_cfg[0][map[MISDN_CFG_METHOD]].str;
00678 
00679    for (i = 1; i <= max_ports; i++) {
00680       if (port_cfg[i] && port_cfg[i][map[MISDN_CFG_GROUPNAME]].str) {
00681          if (!strcasecmp(port_cfg[i][map[MISDN_CFG_GROUPNAME]].str, group))
00682             method = (port_cfg[i][map[MISDN_CFG_METHOD]].str ? 
00683                     port_cfg[i][map[MISDN_CFG_METHOD]].str : port_cfg[0][map[MISDN_CFG_METHOD]].str);
00684       }
00685    }
00686 
00687    if (method) {
00688       switch (meth) {
00689       case METHOD_STANDARD:      re = !strcasecmp(method, "standard");
00690                            break;
00691       case METHOD_ROUND_ROBIN:   re = !strcasecmp(method, "round_robin");
00692                            break;
00693       case METHOD_STANDARD_DEC:  re = !strcasecmp(method, "standard_dec");
00694                            break;
00695       }
00696    }
00697    misdn_cfg_unlock();
00698 
00699    return re;
00700 }
00701 
00702 void misdn_cfg_get_ports_string (char *ports)
00703 {
00704    char tmp[16];
00705    int l, i;
00706    int gn = map[MISDN_CFG_GROUPNAME];
00707 
00708    *ports = 0;
00709 
00710    misdn_cfg_lock();
00711    for (i = 1; i <= max_ports; i++) {
00712       if (port_cfg[i][gn].str) {
00713          if (ptp[i])
00714             sprintf(tmp, "%dptp,", i);
00715          else
00716             sprintf(tmp, "%d,", i);
00717          strcat(ports, tmp);
00718       }
00719    }
00720    misdn_cfg_unlock();
00721 
00722    if ((l = strlen(ports)))
00723       ports[l-1] = 0;
00724 }
00725 
00726 void misdn_cfg_get_config_string (int port, enum misdn_cfg_elements elem, char* buf, int bufsize)
00727 {
00728    int place;
00729    char tempbuf[BUFFERSIZE] = "";
00730    struct msn_list *iter;
00731 
00732    if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
00733       *buf = 0;
00734       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Port number %d is not valid.\n", port);
00735       return;
00736    }
00737 
00738    place = map[elem];
00739 
00740    misdn_cfg_lock();
00741    if (elem == MISDN_CFG_PTP) {
00742       snprintf(buf, bufsize, " -> ptp: %s", ptp[port] ? "yes" : "no");
00743    }
00744    else if (elem > MISDN_CFG_FIRST && elem < MISDN_CFG_LAST) {
00745       switch (port_spec[place].type) {
00746       case MISDN_CTYPE_INT:
00747       case MISDN_CTYPE_BOOLINT:
00748          if (port_cfg[port][place].num)
00749             snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[port][place].num);
00750          else if (port_cfg[0][place].num)
00751             snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[0][place].num);
00752          else
00753             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00754          break;
00755       case MISDN_CTYPE_BOOL:
00756          if (port_cfg[port][place].num)
00757             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[port][place].num ? "yes" : "no");
00758          else if (port_cfg[0][place].num)
00759             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[0][place].num ? "yes" : "no");
00760          else
00761             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00762          break;
00763       case MISDN_CTYPE_ASTGROUP:
00764          if (port_cfg[port][place].grp)
00765             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, 
00766                    ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[port][place].grp));
00767          else if (port_cfg[0][place].grp)
00768             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, 
00769                    ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[0][place].grp));
00770          else
00771             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00772          break;
00773       case MISDN_CTYPE_MSNLIST:
00774          if (port_cfg[port][place].ml)
00775             iter = port_cfg[port][place].ml;
00776          else
00777             iter = port_cfg[0][place].ml;
00778          if (iter) {
00779             for (; iter; iter = iter->next)
00780                sprintf(tempbuf, "%s%s, ", tempbuf, iter->msn);
00781             tempbuf[strlen(tempbuf)-2] = 0;
00782          }
00783          snprintf(buf, bufsize, " -> msns: %s", *tempbuf ? tempbuf : "none");
00784          break;
00785       case MISDN_CTYPE_STR:
00786          if ( port_cfg[port][place].str) {
00787             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[port][place].str);
00788          } else if (port_cfg[0][place].str) {
00789             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[0][place].str);
00790          } else {
00791             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00792          }
00793          break;
00794       }
00795    } else if (elem > MISDN_GEN_FIRST && elem < MISDN_GEN_LAST) {
00796       switch (gen_spec[place].type) {
00797       case MISDN_CTYPE_INT:
00798       case MISDN_CTYPE_BOOLINT:
00799          if (general_cfg[place].num)
00800             snprintf(buf, bufsize, " -> %s: %d", gen_spec[place].name, *general_cfg[place].num);
00801          else
00802             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00803          break;
00804       case MISDN_CTYPE_BOOL:
00805          if (general_cfg[place].num)
00806             snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, *general_cfg[place].num ? "yes" : "no");
00807          else
00808             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00809          break;
00810       case MISDN_CTYPE_STR:
00811          if ( general_cfg[place].str) {
00812             snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, general_cfg[place].str);
00813          } else {
00814             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00815          }
00816          break;
00817       default:
00818          snprintf(buf, bufsize, " -> type of %s not handled yet", gen_spec[place].name);
00819          break;
00820       }
00821    } else {
00822       *buf = 0;
00823       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Invalid config element (%d) requested.\n", elem);
00824    }
00825    misdn_cfg_unlock();
00826 }
00827 
00828 int misdn_cfg_get_next_port (int port)
00829 {
00830    int p = -1;
00831    int gn = map[MISDN_CFG_GROUPNAME];
00832    
00833    misdn_cfg_lock();
00834    for (port++; port <= max_ports; port++) {
00835       if (port_cfg[port][gn].str) {
00836          p = port;
00837          break;
00838       }
00839    }
00840    misdn_cfg_unlock();
00841 
00842    return p;
00843 }
00844 
00845 int misdn_cfg_get_next_port_spin (int port)
00846 {
00847    int p = misdn_cfg_get_next_port(port);
00848    return (p > 0) ? p : misdn_cfg_get_next_port(0);
00849 }
00850 
00851 static int _parse (union misdn_cfg_pt *dest, char *value, enum misdn_cfg_type type, int boolint_def)
00852 {
00853    int re = 0;
00854    int len, tmp;
00855    char *valtmp;
00856 
00857    switch (type) {
00858    case MISDN_CTYPE_STR:
00859       if ((len = strlen(value))) {
00860          dest->str = (char *)malloc((len + 1) * sizeof(char));
00861          strncpy(dest->str, value, len);
00862          dest->str[len] = 0;
00863       } else {
00864          dest->str = (char *)malloc( sizeof(char));
00865          dest->str[0] = 0;
00866       }
00867       break;
00868    case MISDN_CTYPE_INT:
00869    {
00870       char *pat;
00871       if (strchr(value,'x')) 
00872          pat="%x";
00873       else
00874          pat="%d";
00875       if (sscanf(value, pat, &tmp)) {
00876          dest->num = (int *)malloc(sizeof(int));
00877          memcpy(dest->num, &tmp, sizeof(int));
00878       } else
00879          re = -1;
00880    }
00881       break;
00882    case MISDN_CTYPE_BOOL:
00883       dest->num = (int *)malloc(sizeof(int));
00884       *(dest->num) = (ast_true(value) ? 1 : 0);
00885       break;
00886    case MISDN_CTYPE_BOOLINT:
00887       dest->num = (int *)malloc(sizeof(int));
00888       if (sscanf(value, "%d", &tmp)) {
00889          memcpy(dest->num, &tmp, sizeof(int));
00890       } else {
00891          *(dest->num) = (ast_true(value) ? boolint_def : 0);
00892       }
00893       break;
00894    case MISDN_CTYPE_MSNLIST:
00895       for (valtmp = strsep(&value, ","); valtmp; valtmp = strsep(&value, ",")) {
00896          if ((len = strlen(valtmp))) {
00897             struct msn_list *ml = (struct msn_list *)malloc(sizeof(struct msn_list));
00898             ml->msn = (char *)calloc(len+1, sizeof(char));
00899             strncpy(ml->msn, valtmp, len);
00900             ml->next = dest->ml;
00901             dest->ml = ml;
00902          }
00903       }
00904       break;
00905    case MISDN_CTYPE_ASTGROUP:
00906       dest->grp = (ast_group_t *)malloc(sizeof(ast_group_t));
00907       *(dest->grp) = ast_get_group(value);
00908       break;
00909    }
00910 
00911    return re;
00912 }
00913 
00914 static void _build_general_config (struct ast_variable *v)
00915 {
00916    int pos;
00917 
00918    for (; v; v = v->next) {
00919       if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) || 
00920          (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0))
00921          CLI_ERROR(v->name, v->value, "general");
00922    }
00923 }
00924 
00925 static void _build_port_config (struct ast_variable *v, char *cat)
00926 {
00927    int pos, i;
00928    union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS];
00929    int cfg_for_ports[max_ports + 1];
00930 
00931    if (!v || !cat)
00932       return;
00933 
00934    memset(cfg_tmp, 0, sizeof(cfg_tmp));
00935    memset(cfg_for_ports, 0, sizeof(cfg_for_ports));
00936 
00937    if (!strcasecmp(cat, "default")) {
00938       cfg_for_ports[0] = 1;
00939    }
00940 
00941    if (((pos = get_cfg_position("name", PORT_CFG)) < 0) || 
00942       (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
00943       CLI_ERROR(v->name, v->value, cat);
00944       return;
00945    }
00946 
00947    for (; v; v = v->next) {
00948       if (!strcasecmp(v->name, "ports")) {
00949          char *token;
00950          char ptpbuf[BUFFERSIZE] = "";
00951          int start, end;
00952          for (token = strsep(&v->value, ","); token; token = strsep(&v->value, ","), *ptpbuf = 0) { 
00953             if (!*token)
00954                continue;
00955             if (sscanf(token, "%d-%d%s", &start, &end, ptpbuf) >= 2) {
00956                for (; start <= end; start++) {
00957                   if (start <= max_ports && start > 0) {
00958                      cfg_for_ports[start] = 1;
00959                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
00960                   } else
00961                      CLI_ERROR(v->name, v->value, cat);
00962                }
00963             } else {
00964                if (sscanf(token, "%d%s", &start, ptpbuf)) {
00965                   if (start <= max_ports && start > 0) {
00966                      cfg_for_ports[start] = 1;
00967                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
00968                   } else
00969                      CLI_ERROR(v->name, v->value, cat);
00970                } else
00971                   CLI_ERROR(v->name, v->value, cat);
00972             }
00973          }
00974       } else {
00975          if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) || 
00976             (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
00977             CLI_ERROR(v->name, v->value, cat);
00978       }
00979    }
00980 
00981    for (i = 0; i < (max_ports + 1); ++i) {
00982       if (cfg_for_ports[i]) {
00983          memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp));
00984       }
00985    }
00986 }
00987 
00988 void misdn_cfg_update_ptp (void)
00989 {
00990 #ifndef MISDN_1_2
00991    char misdn_init[BUFFERSIZE];
00992    char line[BUFFERSIZE];
00993    FILE *fp;
00994    char *tok, *p, *end;
00995    int port;
00996 
00997    misdn_cfg_get(0, MISDN_GEN_MISDN_INIT, &misdn_init, sizeof(misdn_init));
00998 
00999    if (misdn_init) {
01000       fp = fopen(misdn_init, "r");
01001       if (fp) {
01002          while(fgets(line, sizeof(line), fp)) {
01003             if (!strncmp(line, "nt_ptp", 6)) {
01004                for (tok = strtok_r(line,",=", &p);
01005                    tok;
01006                    tok = strtok_r(NULL,",=", &p)) {
01007                   port = strtol(tok, &end, 10);
01008                   if (end != tok && misdn_cfg_is_port_valid(port)) {
01009                      misdn_cfg_lock();
01010                      ptp[port] = 1;
01011                      misdn_cfg_unlock();
01012                   }
01013                }
01014             }
01015          }
01016          fclose(fp);
01017       } else {
01018          ast_log(LOG_WARNING,"Couldn't open %s: %s\n", misdn_init, strerror(errno));
01019       }
01020    }
01021 #else
01022    int i;
01023    int proto;
01024    char filename[128];
01025    FILE *fp;
01026 
01027    for (i = 1; i <= max_ports; ++i) {
01028       snprintf(filename, sizeof(filename), "/sys/class/mISDN-stacks/st-%08x/protocol", i << 8);
01029       fp = fopen(filename, "r");
01030       if (!fp) {
01031          ast_log(LOG_WARNING, "Could not open %s: %s\n", filename, strerror(errno));
01032          continue;
01033       }
01034       if (fscanf(fp, "0x%08x", &proto) != 1)
01035          ast_log(LOG_WARNING, "Could not parse contents of %s!\n", filename);
01036       else
01037          ptp[i] = proto & 1<<5 ? 1 : 0;
01038       fclose(fp);
01039    }
01040 #endif
01041 }
01042 
01043 static void _fill_defaults (void)
01044 {
01045    int i;
01046 
01047    for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
01048       if (!port_cfg[0][i].any && strcasecmp(port_spec[i].def, NO_DEFAULT))
01049          _parse(&(port_cfg[0][i]), (char *)port_spec[i].def, port_spec[i].type, port_spec[i].boolint_def);
01050    }
01051    for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
01052       if (!general_cfg[i].any && strcasecmp(gen_spec[i].def, NO_DEFAULT))
01053          _parse(&(general_cfg[i]), (char *)gen_spec[i].def, gen_spec[i].type, gen_spec[i].boolint_def);
01054    }
01055 }
01056 
01057 void misdn_cfg_reload (void)
01058 {
01059    misdn_cfg_init (0);
01060 }
01061 
01062 void misdn_cfg_destroy (void)
01063 {
01064    misdn_cfg_lock();
01065 
01066    _free_port_cfg();
01067    _free_general_cfg();
01068 
01069    free(port_cfg);
01070    free(general_cfg);
01071    free(ptp);
01072    free(map);
01073 
01074    misdn_cfg_unlock();
01075    ast_mutex_destroy(&config_mutex);
01076 }
01077 
01078 int misdn_cfg_init (int this_max_ports)
01079 {
01080    char config[] = "misdn.conf";
01081    char *cat, *p;
01082    int i;
01083    struct ast_config *cfg;
01084    struct ast_variable *v;
01085 
01086    if (!(cfg = AST_LOAD_CFG(config))) {
01087       ast_log(LOG_WARNING, "missing file: misdn.conf\n");
01088       return -1;
01089    }
01090 
01091    ast_mutex_init(&config_mutex);
01092 
01093    misdn_cfg_lock();
01094 
01095    if (this_max_ports) {
01096       /* this is the first run */
01097       max_ports = this_max_ports;
01098       map = (int *)calloc(MISDN_GEN_LAST + 1, sizeof(int));
01099       if (_enum_array_map())
01100          return -1;
01101       p = (char *)calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
01102                      + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
01103       port_cfg = (union misdn_cfg_pt **)p;
01104       p += (max_ports + 1) * sizeof(union misdn_cfg_pt *);
01105       for (i = 0; i <= max_ports; ++i) {
01106          port_cfg[i] = (union misdn_cfg_pt *)p;
01107          p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt);
01108       }
01109       general_cfg = (union misdn_cfg_pt *)calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01110       ptp = (int *)calloc(max_ports + 1, sizeof(int));
01111    }
01112    else {
01113       /* misdn reload */
01114       _free_port_cfg();
01115       _free_general_cfg();
01116       memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1));
01117       memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01118       memset(ptp, 0, sizeof(int) * (max_ports + 1));
01119    }
01120 
01121    cat = ast_category_browse(cfg, NULL);
01122 
01123    while(cat) {
01124       v = ast_variable_browse(cfg, cat);
01125       if (!strcasecmp(cat, "general")) {
01126          _build_general_config(v);
01127       } else {
01128          _build_port_config(v, cat);
01129       }
01130       cat = ast_category_browse(cfg, cat);
01131    }
01132 
01133    _fill_defaults();
01134 
01135    misdn_cfg_unlock();
01136    AST_DESTROY_CFG(cfg);
01137 
01138    return 0;
01139 }
01140 
01141 

Generated on Fri Aug 24 02:22:15 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1