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