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