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