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