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