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