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