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: 185127 $")
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 both values, the presentation indicators are used from\n"
00203 "\tAsterisks SetCallerPres application.\n"
00204 "\n"
00205 "\tscreen=0, presentation=0 -> callerid presented not screened\n"
00206 "\tscreen=1, presentation=1 -> callerid presented but screened (the remote end doesn't see it!)" },
00207 { "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 both values, the presentation indicators are used from\n"
00211 "\tAsterisks SetCallerPres application.\n"
00212 "\n"
00213 "\tscreen=0, presentation=0 -> callerid presented not screened\n"
00214 "\tscreen=1, presentation=1 -> callerid presented but screened (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 tempbuf[strlen(tempbuf)-2] = 0;
00798 }
00799 snprintf(buf, bufsize, " -> msns: %s", *tempbuf ? tempbuf : "none");
00800 break;
00801 case MISDN_CTYPE_STR:
00802 if ( port_cfg[port][place].str) {
00803 snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[port][place].str);
00804 } else if (port_cfg[0][place].str) {
00805 snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[0][place].str);
00806 } else {
00807 snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
00808 }
00809 break;
00810 }
00811 } else if (elem > MISDN_GEN_FIRST && elem < MISDN_GEN_LAST) {
00812 switch (gen_spec[place].type) {
00813 case MISDN_CTYPE_INT:
00814 case MISDN_CTYPE_BOOLINT:
00815 if (general_cfg[place].num)
00816 snprintf(buf, bufsize, " -> %s: %d", gen_spec[place].name, *general_cfg[place].num);
00817 else
00818 snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00819 break;
00820 case MISDN_CTYPE_BOOL:
00821 if (general_cfg[place].num)
00822 snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, *general_cfg[place].num ? "yes" : "no");
00823 else
00824 snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00825 break;
00826 case MISDN_CTYPE_STR:
00827 if ( general_cfg[place].str) {
00828 snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, general_cfg[place].str);
00829 } else {
00830 snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
00831 }
00832 break;
00833 default:
00834 snprintf(buf, bufsize, " -> type of %s not handled yet", gen_spec[place].name);
00835 break;
00836 }
00837 } else {
00838 *buf = 0;
00839 ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Invalid config element (%d) requested.\n", elem);
00840 }
00841 misdn_cfg_unlock();
00842 }
00843
00844 int misdn_cfg_get_next_port (int port)
00845 {
00846 int p = -1;
00847 int gn = map[MISDN_CFG_GROUPNAME];
00848
00849 misdn_cfg_lock();
00850 for (port++; port <= max_ports; port++) {
00851 if (port_cfg[port][gn].str) {
00852 p = port;
00853 break;
00854 }
00855 }
00856 misdn_cfg_unlock();
00857
00858 return p;
00859 }
00860
00861 int misdn_cfg_get_next_port_spin (int port)
00862 {
00863 int p = misdn_cfg_get_next_port(port);
00864 return (p > 0) ? p : misdn_cfg_get_next_port(0);
00865 }
00866
00867 static int _parse (union misdn_cfg_pt *dest, const char *value, enum misdn_cfg_type type, int boolint_def)
00868 {
00869 int re = 0;
00870 int len, tmp;
00871 char *valtmp;
00872 char *tmp2 = ast_strdupa(value);
00873
00874 switch (type) {
00875 case MISDN_CTYPE_STR:
00876 if ((len = strlen(value))) {
00877 dest->str = ast_malloc((len + 1) * sizeof(char));
00878 strncpy(dest->str, value, len);
00879 dest->str[len] = 0;
00880 } else {
00881 dest->str = ast_malloc(sizeof(char));
00882 dest->str[0] = 0;
00883 }
00884 break;
00885 case MISDN_CTYPE_INT:
00886 {
00887 int res;
00888
00889 if (strchr(value,'x')) {
00890 res = sscanf(value, "%x", &tmp);
00891 } else {
00892 res = sscanf(value, "%d", &tmp);
00893 }
00894 if (res) {
00895 dest->num = ast_malloc(sizeof(int));
00896 memcpy(dest->num, &tmp, sizeof(int));
00897 } else
00898 re = -1;
00899 }
00900 break;
00901 case MISDN_CTYPE_BOOL:
00902 dest->num = ast_malloc(sizeof(int));
00903 *(dest->num) = (ast_true(value) ? 1 : 0);
00904 break;
00905 case MISDN_CTYPE_BOOLINT:
00906 dest->num = ast_malloc(sizeof(int));
00907 if (sscanf(value, "%d", &tmp)) {
00908 memcpy(dest->num, &tmp, sizeof(int));
00909 } else {
00910 *(dest->num) = (ast_true(value) ? boolint_def : 0);
00911 }
00912 break;
00913 case MISDN_CTYPE_MSNLIST:
00914 for (valtmp = strsep(&tmp2, ","); valtmp; valtmp = strsep(&tmp2, ",")) {
00915 if ((len = strlen(valtmp))) {
00916 struct msn_list *ml = ast_malloc(sizeof(*ml));
00917 ml->msn = ast_calloc(len+1, sizeof(char));
00918 strncpy(ml->msn, valtmp, len);
00919 ml->next = dest->ml;
00920 dest->ml = ml;
00921 }
00922 }
00923 break;
00924 case MISDN_CTYPE_ASTGROUP:
00925 dest->grp = ast_malloc(sizeof(ast_group_t));
00926 *(dest->grp) = ast_get_group(value);
00927 break;
00928 }
00929
00930 return re;
00931 }
00932
00933 static void _build_general_config (struct ast_variable *v)
00934 {
00935 int pos;
00936
00937 for (; v; v = v->next) {
00938 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
00939 continue;
00940 if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) ||
00941 (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0))
00942 CLI_ERROR(v->name, v->value, "general");
00943 }
00944 }
00945
00946 static void _build_port_config (struct ast_variable *v, char *cat)
00947 {
00948 int pos, i;
00949 union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS];
00950 int cfg_for_ports[max_ports + 1];
00951
00952 if (!v || !cat)
00953 return;
00954
00955 memset(cfg_tmp, 0, sizeof(cfg_tmp));
00956 memset(cfg_for_ports, 0, sizeof(cfg_for_ports));
00957
00958 if (!strcasecmp(cat, "default")) {
00959 cfg_for_ports[0] = 1;
00960 }
00961
00962 if (((pos = get_cfg_position("name", PORT_CFG)) < 0) ||
00963 (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
00964 CLI_ERROR(v->name, v->value, cat);
00965 return;
00966 }
00967
00968 for (; v; v = v->next) {
00969 if (!strcasecmp(v->name, "ports")) {
00970 char *token, *tmp = ast_strdupa(v->value);
00971 char ptpbuf[BUFFERSIZE] = "";
00972 int start, end;
00973 for (token = strsep(&tmp, ","); token; token = strsep(&tmp, ","), *ptpbuf = 0) {
00974 if (!*token)
00975 continue;
00976 if (sscanf(token, "%d-%d%s", &start, &end, ptpbuf) >= 2) {
00977 for (; start <= end; start++) {
00978 if (start <= max_ports && start > 0) {
00979 cfg_for_ports[start] = 1;
00980 ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
00981 } else
00982 CLI_ERROR(v->name, v->value, cat);
00983 }
00984 } else {
00985 if (sscanf(token, "%d%s", &start, ptpbuf)) {
00986 if (start <= max_ports && start > 0) {
00987 cfg_for_ports[start] = 1;
00988 ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
00989 } else
00990 CLI_ERROR(v->name, v->value, cat);
00991 } else
00992 CLI_ERROR(v->name, v->value, cat);
00993 }
00994 }
00995 } else {
00996 if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) ||
00997 (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
00998 CLI_ERROR(v->name, v->value, cat);
00999 }
01000 }
01001
01002 for (i = 0; i < (max_ports + 1); ++i) {
01003 if (cfg_for_ports[i]) {
01004 memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp));
01005 }
01006 }
01007 }
01008
01009 void misdn_cfg_update_ptp (void)
01010 {
01011 #ifndef MISDN_1_2
01012 char misdn_init[BUFFERSIZE];
01013 char line[BUFFERSIZE];
01014 FILE *fp;
01015 char *tok, *p, *end;
01016 int port;
01017
01018 misdn_cfg_get(0, MISDN_GEN_MISDN_INIT, &misdn_init, sizeof(misdn_init));
01019
01020 if (!ast_strlen_zero(misdn_init)) {
01021 fp = fopen(misdn_init, "r");
01022 if (fp) {
01023 while(fgets(line, sizeof(line), fp)) {
01024 if (!strncmp(line, "nt_ptp", 6)) {
01025 for (tok = strtok_r(line,",=", &p);
01026 tok;
01027 tok = strtok_r(NULL,",=", &p)) {
01028 port = strtol(tok, &end, 10);
01029 if (end != tok && misdn_cfg_is_port_valid(port)) {
01030 misdn_cfg_lock();
01031 ptp[port] = 1;
01032 misdn_cfg_unlock();
01033 }
01034 }
01035 }
01036 }
01037 fclose(fp);
01038 } else {
01039 ast_log(LOG_WARNING,"Couldn't open %s: %s\n", misdn_init, strerror(errno));
01040 }
01041 }
01042 #else
01043 int i;
01044 int proto;
01045 char filename[128];
01046 FILE *fp;
01047
01048 for (i = 1; i <= max_ports; ++i) {
01049 snprintf(filename, sizeof(filename), "/sys/class/mISDN-stacks/st-%08x/protocol", i << 8);
01050 fp = fopen(filename, "r");
01051 if (!fp) {
01052 ast_log(LOG_WARNING, "Could not open %s: %s\n", filename, strerror(errno));
01053 continue;
01054 }
01055 if (fscanf(fp, "0x%08x", &proto) != 1)
01056 ast_log(LOG_WARNING, "Could not parse contents of %s!\n", filename);
01057 else
01058 ptp[i] = proto & 1<<5 ? 1 : 0;
01059 fclose(fp);
01060 }
01061 #endif
01062 }
01063
01064 static void _fill_defaults (void)
01065 {
01066 int i;
01067
01068 for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
01069 if (!port_cfg[0][i].any && strcasecmp(port_spec[i].def, NO_DEFAULT))
01070 _parse(&(port_cfg[0][i]), (char *)port_spec[i].def, port_spec[i].type, port_spec[i].boolint_def);
01071 }
01072 for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
01073 if (!general_cfg[i].any && strcasecmp(gen_spec[i].def, NO_DEFAULT))
01074 _parse(&(general_cfg[i]), (char *)gen_spec[i].def, gen_spec[i].type, gen_spec[i].boolint_def);
01075 }
01076 }
01077
01078 void misdn_cfg_reload (void)
01079 {
01080 misdn_cfg_init(0, 1);
01081 }
01082
01083 void misdn_cfg_destroy (void)
01084 {
01085 misdn_cfg_lock();
01086
01087 _free_port_cfg();
01088 _free_general_cfg();
01089
01090 ast_free(port_cfg);
01091 ast_free(general_cfg);
01092 ast_free(ptp);
01093 ast_free(map);
01094
01095 misdn_cfg_unlock();
01096 ast_mutex_destroy(&config_mutex);
01097 }
01098
01099 int misdn_cfg_init(int this_max_ports, int reload)
01100 {
01101 char config[] = "misdn.conf";
01102 char *cat, *p;
01103 int i;
01104 struct ast_config *cfg;
01105 struct ast_variable *v;
01106 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01107
01108 if (!(cfg = ast_config_load2(config, "chan_misdn", config_flags))) {
01109 ast_log(LOG_WARNING, "missing file: misdn.conf\n");
01110 return -1;
01111 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
01112 return 0;
01113
01114 ast_mutex_init(&config_mutex);
01115
01116
01117 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01118
01119 misdn_cfg_lock();
01120
01121 if (this_max_ports) {
01122
01123 max_ports = this_max_ports;
01124 map = ast_calloc(MISDN_GEN_LAST + 1, sizeof(int));
01125 if (_enum_array_map())
01126 return -1;
01127 p = ast_calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
01128 + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
01129 port_cfg = (union misdn_cfg_pt **)p;
01130 p += (max_ports + 1) * sizeof(union misdn_cfg_pt *);
01131 for (i = 0; i <= max_ports; ++i) {
01132 port_cfg[i] = (union misdn_cfg_pt *)p;
01133 p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt);
01134 }
01135 general_cfg = ast_calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01136 ptp = ast_calloc(max_ports + 1, sizeof(int));
01137 }
01138 else {
01139
01140 _free_port_cfg();
01141 _free_general_cfg();
01142 memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1));
01143 memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
01144 memset(ptp, 0, sizeof(int) * (max_ports + 1));
01145 }
01146
01147 cat = ast_category_browse(cfg, NULL);
01148
01149 while(cat) {
01150 v = ast_variable_browse(cfg, cat);
01151 if (!strcasecmp(cat, "general")) {
01152 _build_general_config(v);
01153 } else {
01154 _build_port_config(v, cat);
01155 }
01156 cat = ast_category_browse(cfg, cat);
01157 }
01158
01159 _fill_defaults();
01160
01161 misdn_cfg_unlock();
01162 ast_config_destroy(cfg);
01163
01164 return 0;
01165 }
01166
01167 struct ast_jb_conf *misdn_get_global_jbconf() {
01168 return &global_jbconf;
01169 }