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