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: 67210 $")
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
00365 static union misdn_cfg_pt **port_cfg;
00366
00367 static int max_ports;
00368
00369 static union misdn_cfg_pt *general_cfg;
00370
00371 static int *ptp;
00372
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
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
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
00584 if (elem == MISDN_CFG_PTP) {
00585 memset(buf, 0, 1);
00586 return;
00587 }
00588
00589
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
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
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
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