fd9df2248d022f76db693c2cecb79b5901e1e957
[asterisk/asterisk.git] / channels / misdn_config.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  * 
4  * Copyright (C) 2005, Christian Richter
5  *
6  * Christian Richter <crich@beronet.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  *
18  */
19
20 /*!
21  * \file
22  *
23  * \brief chan_misdn configuration management
24  * \author Christian Richter <crich@beronet.com>
25  *
26  * \ingroup channel_drivers
27  */
28
29 #include "asterisk.h"
30
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32
33 #include "chan_misdn_config.h"
34
35 #include "asterisk/config.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/lock.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/strings.h"
40 #include "asterisk/utils.h"
41
42 #define NO_DEFAULT "<>"
43 #define NONE 0
44
45 #define GEN_CFG 1
46 #define PORT_CFG 2
47 #define NUM_GEN_ELEMENTS (sizeof(gen_spec) / sizeof(struct misdn_cfg_spec))
48 #define NUM_PORT_ELEMENTS (sizeof(port_spec) / sizeof(struct misdn_cfg_spec))
49
50 /*! Global jitterbuffer configuration - by default, jb is disabled */
51 static struct ast_jb_conf default_jbconf =
52 {
53         .flags = 0,
54         .max_size = -1,
55         .resync_threshold = -1,
56         .impl = "",
57 };
58
59 static struct ast_jb_conf global_jbconf;
60
61 enum misdn_cfg_type {
62         MISDN_CTYPE_STR,
63         MISDN_CTYPE_INT,
64         MISDN_CTYPE_BOOL,
65         MISDN_CTYPE_BOOLINT,
66         MISDN_CTYPE_MSNLIST,
67         MISDN_CTYPE_ASTGROUP
68 };
69
70 struct msn_list {
71         char *msn;
72         struct msn_list *next;
73 };
74
75 union misdn_cfg_pt {
76         char *str;
77         int *num;
78         struct msn_list *ml;
79         ast_group_t *grp;
80         void *any;
81 };
82
83 struct misdn_cfg_spec {
84         char name[BUFFERSIZE];
85         enum misdn_cfg_elements elem;
86         enum misdn_cfg_type type;
87         char def[BUFFERSIZE];
88         int boolint_def;
89         char desc[BUFFERSIZE];
90 };
91
92
93 static const char ports_description[] =
94         "Define your ports, e.g. 1,2 (depends on mISDN-driver loading order).";
95
96 static const struct misdn_cfg_spec port_spec[] = {
97         { "name", MISDN_CFG_GROUPNAME, MISDN_CTYPE_STR, "default", NONE,
98                 "Name of the portgroup." },
99         { "allowed_bearers", MISDN_CFG_ALLOWED_BEARERS, MISDN_CTYPE_STR, "all", NONE,
100                 "Here you can define which bearers should be allowed." },
101         { "rxgain", MISDN_CFG_RXGAIN, MISDN_CTYPE_INT, "0", NONE,
102                 "Set this between -8 and 8 to change the RX Gain." },
103         { "txgain", MISDN_CFG_TXGAIN, MISDN_CTYPE_INT, "0", NONE,
104                 "Set this between -8 and 8 to change the TX Gain." },
105         { "te_choose_channel", MISDN_CFG_TE_CHOOSE_CHANNEL, MISDN_CTYPE_BOOL, "no", NONE,
106                 "Some telcos espacially in NL seem to need this set to yes,\n"
107                 "\talso in switzerland this seems to be important." },
108         { "far_alerting", MISDN_CFG_FAR_ALERTING, MISDN_CTYPE_BOOL, "no", NONE,
109                 "If we should generate ringing for chan_sip and others." },
110         { "pmp_l1_check", MISDN_CFG_PMP_L1_CHECK, MISDN_CTYPE_BOOL, "no", NONE,
111                 "This option defines, if chan_misdn should check the L1 on a PMP\n"
112                 "\tbefore makeing a group call on it. The L1 may go down for PMP Ports\n"
113                 "\tso we might need this.\n"
114                 "\tBut be aware! a broken or plugged off cable might be used for a group call\n"
115                 "\tas well, since chan_misdn has no chance to distinguish if the L1 is down\n"
116                 "\tbecause of a lost Link or because the Provider shut it down..." },
117         { "block_on_alarm", MISDN_CFG_ALARM_BLOCK, MISDN_CTYPE_BOOL, "no", NONE ,
118           "Block this port if we have an alarm on it."
119           "default: yes\n" },
120         { "hdlc", MISDN_CFG_HDLC, MISDN_CTYPE_BOOL, "no", NONE,
121                 "Set this to yes, if you want to bridge a mISDN data channel to\n"
122                 "\tanother channel type or to an application." },
123         { "context", MISDN_CFG_CONTEXT, MISDN_CTYPE_STR, "default", NONE,
124                 "Context to use for incoming calls." },
125         { "language", MISDN_CFG_LANGUAGE, MISDN_CTYPE_STR, "en", NONE,
126                 "Language." },
127         { "musicclass", MISDN_CFG_MUSICCLASS, MISDN_CTYPE_STR, "default", NONE,
128                 "Sets the musiconhold class." },
129         { "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE,
130                 "Sets the caller ID." },
131         { "method", MISDN_CFG_METHOD, MISDN_CTYPE_STR, "standard", NONE,
132                 "Sets the method to use for channel selection:\n"
133                 "\t  standard    - always choose the first free channel with the lowest number\n"
134                 "\t  round_robin - use the round robin algorithm to select a channel. use this\n"
135                 "\t                if you want to balance your load." },
136         { "dialplan", MISDN_CFG_DIALPLAN, MISDN_CTYPE_INT, "0", NONE,
137                 "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
138                 "\n"
139                 "\tThere are different types of the dialplan:\n"
140                 "\n"
141                 "\tdialplan -> outgoing Number\n"
142                 "\tlocaldialplan -> callerid\n"
143                 "\tcpndialplan -> connected party number\n"
144                 "\n"
145                 "\tdialplan options:\n"
146                 "\n"
147                 "\t0 - unknown\n"
148                 "\t1 - International\n"
149                 "\t2 - National\n"
150                 "\t4 - Subscriber\n"
151                 "\n"
152                 "\tThis setting is used for outgoing calls." },
153         { "localdialplan", MISDN_CFG_LOCALDIALPLAN, MISDN_CTYPE_INT, "0", NONE,
154                 "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
155                 "\n"
156                 "\tThere are different types of the dialplan:\n"
157                 "\n"
158                 "\tdialplan -> outgoing Number\n"
159                 "\tlocaldialplan -> callerid\n"
160                 "\tcpndialplan -> connected party number\n"
161                 "\n"
162                 "\tdialplan options:\n"
163                 "\n"
164                 "\t0 - unknown\n"
165                 "\t1 - International\n"
166                 "\t2 - National\n"
167                 "\t4 - Subscriber\n"
168                 "\n"
169                 "\tThis setting is used for outgoing calls" },
170         { "cpndialplan", MISDN_CFG_CPNDIALPLAN, MISDN_CTYPE_INT, "0", NONE,
171                 "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
172                 "\n"
173                 "\tThere are different types of the dialplan:\n"
174                 "\n"
175                 "\tdialplan -> outgoing Number\n"
176                 "\tlocaldialplan -> callerid\n"
177                 "\tcpndialplan -> connected party number\n"
178                 "\n"
179                 "\tdialplan options:\n"
180                 "\n"
181                 "\t0 - unknown\n"
182                 "\t1 - International\n"
183                 "\t2 - National\n"
184                 "\t4 - Subscriber\n"
185                 "\n"
186                 "\tThis setting is used for outgoing calls." },
187         { "nationalprefix", MISDN_CFG_NATPREFIX, MISDN_CTYPE_STR, "0", NONE,
188                 "Prefix for national, this is put before the\n"
189                 "\toad if an according dialplan is set by the other end." },
190         { "internationalprefix", MISDN_CFG_INTERNATPREFIX, MISDN_CTYPE_STR, "00", NONE,
191                 "Prefix for international, this is put before the\n"
192                 "\toad if an according dialplan is set by the other end." },
193         { "presentation", MISDN_CFG_PRES, MISDN_CTYPE_INT, "-1", NONE,
194                 "These (presentation and screen) are the exact isdn screening and presentation\n"
195                 "\tindicators.\n"
196                 "\tIf -1 is given for both values, the presentation indicators are used from\n"
197                 "\tAsterisks SetCallerPres application.\n"
198                 "\n"
199                 "\tscreen=0, presentation=0 -> callerid presented not screened\n"
200                 "\tscreen=1, presentation=1 -> callerid presented but screened (the remote end doesn't see it!)" },
201         { "screen", MISDN_CFG_SCREEN, MISDN_CTYPE_INT, "-1", NONE,
202                 "These (presentation and screen) are the exact isdn screening and presentation\n"
203                 "\tindicators.\n"
204                 "\tIf -1 is given for both values, the presentation indicators are used from\n"
205                 "\tAsterisks SetCallerPres application.\n"
206                 "\n"
207                 "\tscreen=0, presentation=0 -> callerid presented not screened\n"
208                 "\tscreen=1, presentation=1 -> callerid presented but screened (the remote end doesn't see it!)" },
209         { "always_immediate", MISDN_CFG_ALWAYS_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
210                 "Enable this to get into the s dialplan-extension.\n"
211                 "\tThere you can use DigitTimeout if you can't or don't want to use\n"
212                 "\tisdn overlap dial.\n"
213                 "\tNOTE: This will jump into the s extension for every exten!" },
214         { "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE,
215                 "Enable this to prevent chan_misdn to generate the dialtone\n"
216                 "\tThis makes only sense together with the always_immediate=yes option\n"
217                 "\tto generate your own dialtone with Playtones or so."},
218         { "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
219                 "Enable this if you want callers which called exactly the base\n"
220                 "\tnumber (so no extension is set) to jump into the s extension.\n"
221                 "\tIf the user dials something more, it jumps to the correct extension\n"
222                 "\tinstead." },
223         { "senddtmf", MISDN_CFG_SENDDTMF, MISDN_CTYPE_BOOL, "no", NONE,
224                 "Enable this if we should produce DTMF Tones ourselves." },
225         { "astdtmf", MISDN_CFG_ASTDTMF, MISDN_CTYPE_BOOL, "no", NONE,
226                 "Enable this if you want to use the Asterisk dtmf detector\n"
227                 "instead of the mISDN_dsp/hfcmulti one."
228                 },
229         { "hold_allowed", MISDN_CFG_HOLD_ALLOWED, MISDN_CTYPE_BOOL, "no", NONE,
230                 "Enable this to have support for hold and retrieve." },
231         { "early_bconnect", MISDN_CFG_EARLY_BCONNECT, MISDN_CTYPE_BOOL, "yes", NONE,
232                 "Disable this if you don't mind correct handling of Progress Indicators." },
233         { "incoming_early_audio", MISDN_CFG_INCOMING_EARLY_AUDIO, MISDN_CTYPE_BOOL, "no", NONE,
234                 "Turn this on if you like to send Tone Indications to a Incoming\n"
235                 "\tisdn channel on a TE Port. Rarely used, only if the Telco allows\n"
236                 "\tyou to send indications by yourself, normally the Telco sends the\n"
237                 "\tindications to the remote party." },
238         { "echocancel", MISDN_CFG_ECHOCANCEL, MISDN_CTYPE_BOOLINT, "0", 128,
239                 "This enables echocancellation, with the given number of taps.\n"
240                 "\tBe aware, move this setting only to outgoing portgroups!\n"
241                 "\tA value of zero turns echocancellation off.\n"
242                 "\n"
243                 "\tPossible values are: 0,32,64,128,256,yes(=128),no(=0)" },
244 #ifdef MISDN_1_2
245         { "pipeline", MISDN_CFG_PIPELINE, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
246                 "Set the configuration string for the mISDN dsp pipeline.\n"
247                 "\n"
248                 "\tExample for enabling the mg2 echo cancellation module with deftaps\n"
249                 "\tset to 128:\n"
250                 "\t\tmg2ec(deftaps=128)" },
251 #endif
252 #ifdef WITH_BEROEC
253         { "bnechocancel", MISDN_CFG_BNECHOCANCEL, MISDN_CTYPE_BOOLINT, "yes", 64,
254                 "echotail in ms (1-200)\n"},
255         { "bnec_antihowl", MISDN_CFG_BNEC_ANTIHOWL, MISDN_CTYPE_INT, "0", NONE,
256                 "Use antihowl\n"},
257         { "bnec_nlp", MISDN_CFG_BNEC_NLP, MISDN_CTYPE_BOOL, "yes", NONE,
258                 "Nonlinear Processing (much faster adaption)"},
259         { "bnec_zerocoeff", MISDN_CFG_BNEC_ZEROCOEFF, MISDN_CTYPE_BOOL, "no", NONE,
260                 "ZeroCoeffeciens\n"},
261         { "bnec_tonedisabler", MISDN_CFG_BNEC_TD, MISDN_CTYPE_BOOL, "no", NONE,
262                 "Disable Tone\n"},
263         { "bnec_adaption", MISDN_CFG_BNEC_ADAPT, MISDN_CTYPE_INT, "1", NONE,
264                 "Adaption mode (0=no,1=full,2=fast)\n"},
265 #endif
266         { "need_more_infos", MISDN_CFG_NEED_MORE_INFOS, MISDN_CTYPE_BOOL, "0", NONE,
267                 "Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),\n"
268                 "\tthis requests additional Infos, so we can waitfordigits without much\n"
269                 "\tissues. This works only for PTP Ports" },
270         { "noautorespond_on_setup", MISDN_CFG_NOAUTORESPOND_ON_SETUP, MISDN_CTYPE_BOOL, "0", NONE,
271                 "Do not send SETUP_ACKNOWLEDGE or PROCEEDING automatically to the calling Party.\n"
272                 "Instead we directly jump into the dialplan. This might be useful for fast call\n"
273                 "rejection, or for some broken switches, that need hangup causes like busy in the.\n"
274                 "RELEASE_COMPLETE Message, instead of the DISCONNECT Message.\n"},
275         { "jitterbuffer", MISDN_CFG_JITTERBUFFER, MISDN_CTYPE_INT, "4000", NONE,
276                 "The jitterbuffer." },
277         { "jitterbuffer_upper_threshold", MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, MISDN_CTYPE_INT, "0", NONE,
278                 "Change this threshold to enable dejitter functionality." },
279         { "callgroup", MISDN_CFG_CALLGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE,
280                 "Callgroup." },
281         { "pickupgroup", MISDN_CFG_PICKUPGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE,
282                 "Pickupgroup." },
283         { "max_incoming", MISDN_CFG_MAX_IN, MISDN_CTYPE_INT, "-1", NONE,
284                 "Defines the maximum amount of incoming calls per port for this group.\n"
285                 "\tCalls which exceed the maximum will be marked with the channel varible\n"
286                 "\tMAX_OVERFLOW. It will contain the amount of overflowed calls" },
287         { "max_outgoing", MISDN_CFG_MAX_OUT, MISDN_CTYPE_INT, "-1", NONE,
288                 "Defines the maximum amount of outgoing calls per port for this group\n"
289                 "\texceeding calls will be rejected" },
290
291         { "reject_cause", MISDN_CFG_REJECT_CAUSE, MISDN_CTYPE_INT, "21", NONE,
292                 "Defines the cause with which a 3. call is rejected on PTMP BRI."},
293         { "faxdetect", MISDN_CFG_FAXDETECT, MISDN_CTYPE_STR, "no", NONE,
294                 "Setup fax detection:\n"
295                 "\t    no        - no fax detection\n"
296                 "\t    incoming  - fax detection for incoming calls\n"
297                 "\t    outgoing  - fax detection for outgoing calls\n"
298                 "\t    both      - fax detection for incoming and outgoing calls\n"
299                 "\tAdd +nojump to your value (i.e. faxdetect=both+nojump) if you don't want to jump into the\n"
300                 "\tfax-extension but still want to detect the fax and prepare the channel for fax transfer." },
301         { "faxdetect_timeout", MISDN_CFG_FAXDETECT_TIMEOUT, MISDN_CTYPE_INT, "5", NONE,
302                 "Number of seconds the fax detection should do its job. After the given period of time,\n"
303                 "\twe assume that it's not a fax call and save some CPU time by turning off fax detection.\n"
304                 "\tSet this to 0 if you don't want a timeout (never stop detecting)." },
305         { "faxdetect_context", MISDN_CFG_FAXDETECT_CONTEXT, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
306                 "Context to jump into if we detect a fax. Don't set this if you want to stay in the current context." },
307         { "l1watcher_timeout", MISDN_CFG_L1_TIMEOUT, MISDN_CTYPE_BOOLINT, "0", 4,
308                 "Watches the layer 1. If the layer 1 is down, it tries to\n"
309                 "\tget it up. The timeout is given in seconds. with 0 as value it\n"
310                 "\tdoes not watch the l1 at all\n"
311                 "\n"
312                 "\tThis option is only read at loading time of chan_misdn, which\n"
313                 "\tmeans you need to unload and load chan_misdn to change the value,\n"
314                 "\tan Asterisk restart should do the trick." },
315         { "overlapdial", MISDN_CFG_OVERLAP_DIAL, MISDN_CTYPE_BOOLINT, "0", 4,
316                 "Enables overlap dial for the given amount of seconds.\n"
317                 "\tPossible values are positive integers or:\n"
318                 "\t   yes (= 4 seconds)\n"
319                 "\t   no  (= 0 seconds = disabled)" },
320         { "nttimeout", MISDN_CFG_NTTIMEOUT, MISDN_CTYPE_BOOL, "no", NONE ,
321                 "Set this to yes if you want calls disconnected in overlap mode\n"
322                 "\twhen a timeout happens." },
323         { "bridging", MISDN_CFG_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE,
324                 "Set this to yes/no, default is yes.\n"
325                 "This can be used to have bridging enabled in general and to\n"
326                 "disable it for specific ports. It makes sense to disable\n"
327                 "bridging on NT Port where you plan to use the HOLD/RETRIEVE\n"
328                 "features with ISDN phones.\n"
329                 },
330         { "msns", MISDN_CFG_MSNS, MISDN_CTYPE_MSNLIST, "*", NONE,
331                 "MSN's for TE ports, listen on those numbers on the above ports, and\n"
332                 "\tindicate the incoming calls to Asterisk.\n"
333                 "\tHere you can give a comma seperated list, or simply an '*' for any msn." },
334 };
335
336 static const struct misdn_cfg_spec gen_spec[] = {
337         { "debug", MISDN_GEN_DEBUG, MISDN_CTYPE_INT, "0", NONE,
338                 "Sets the debugging flag:\n"
339                 "\t0 - No Debug\n"
340                 "\t1 - mISDN Messages and * - Messages, and * - State changes\n"
341                 "\t2 - Messages + Message specific Informations (e.g. bearer capability)\n"
342                 "\t3 - very Verbose, the above + lots of Driver specific infos\n"
343                 "\t4 - even more Verbose than 3" },
344 #ifndef MISDN_1_2
345         { "misdn_init", MISDN_GEN_MISDN_INIT, MISDN_CTYPE_STR, "/etc/misdn-init.conf", NONE,
346                 "Set the path to the misdn-init.conf (for nt_ptp mode checking)." },
347 #endif
348         { "tracefile", MISDN_GEN_TRACEFILE, MISDN_CTYPE_STR, "/var/log/asterisk/misdn.log", NONE,
349                 "Set the path to the massively growing trace file, if you want that." },
350         { "bridging", MISDN_GEN_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE,
351                 "Set this to yes if you want mISDN_dsp to bridge the calls in HW." },
352         { "stop_tone_after_first_digit", MISDN_GEN_STOP_TONE, MISDN_CTYPE_BOOL, "yes", NONE,
353                 "Stops dialtone after getting first digit on NT Port." },
354         { "append_digits2exten", MISDN_GEN_APPEND_DIGITS2EXTEN, MISDN_CTYPE_BOOL, "yes", NONE,
355                 "Wether to append overlapdialed Digits to Extension or not." },
356         { "dynamic_crypt", MISDN_GEN_DYNAMIC_CRYPT, MISDN_CTYPE_BOOL, "no", NONE,
357                 "Wether to look out for dynamic crypting attempts." },
358         { "crypt_prefix", MISDN_GEN_CRYPT_PREFIX, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
359                 "What is used for crypting Protocol." },
360         { "crypt_keys", MISDN_GEN_CRYPT_KEYS, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
361                 "Keys for cryption, you reference them in the dialplan\n"
362                 "\tLater also in dynamic encr." },
363         { "ntkeepcalls", MISDN_GEN_NTKEEPCALLS, MISDN_CTYPE_BOOL, "no", NONE, 
364                 "avoid dropping calls if the L2 goes down. some nortel pbx\n" 
365                 "do put down the L2/L1 for some milliseconds even if there\n"
366                 "are running calls. with this option you can avoid dropping them\n" },
367         { "ntdebugflags", MISDN_GEN_NTDEBUGFLAGS, MISDN_CTYPE_INT, "0", NONE,
368                 "No description yet."},
369         { "ntdebugfile", MISDN_GEN_NTDEBUGFILE, MISDN_CTYPE_STR, "/var/log/misdn-nt.log", NONE,
370                 "No description yet." }
371 };
372
373
374 /* array of port configs, default is at position 0. */
375 static union misdn_cfg_pt **port_cfg;
376 /* max number of available ports, is set on init */
377 static int max_ports;
378 /* general config */
379 static union misdn_cfg_pt *general_cfg;
380 /* storing the ptp flag separated to save memory */
381 static int *ptp;
382 /* maps enum config elements to array positions */
383 static int *map;
384
385 static ast_mutex_t config_mutex; 
386
387 #define CLI_ERROR(name, value, section) ({ \
388         ast_log(LOG_WARNING, "misdn.conf: \"%s=%s\" (section: %s) invalid or out of range. " \
389                 "Please edit your misdn.conf and then do a \"misdn reload\".\n", name, value, section); \
390 })
391
392 static int _enum_array_map (void)
393 {
394         int i, j, ok;
395
396         for (i = MISDN_CFG_FIRST + 1; i < MISDN_CFG_LAST; ++i) {
397                 if (i == MISDN_CFG_PTP)
398                         continue;
399                 ok = 0;
400                 for (j = 0; j < NUM_PORT_ELEMENTS; ++j) {
401                         if (port_spec[j].elem == i) {
402                                 map[i] = j;
403                                 ok = 1;
404                                 break;
405                         }
406                 }
407                 if (!ok) {
408                         ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (port section) has no corresponding element in the config struct!\n", i);
409                         return -1;
410                 }
411         }
412         for (i = MISDN_GEN_FIRST + 1; i < MISDN_GEN_LAST; ++i) {
413                 ok = 0;
414                 for (j = 0; j < NUM_GEN_ELEMENTS; ++j) {
415                         if (gen_spec[j].elem == i) {
416                                 map[i] = j;
417                                 ok = 1;
418                                 break;
419                         }
420                 }
421                 if (!ok) {
422                         ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (general section) has no corresponding element in the config struct!\n", i);
423                         return -1;
424                 }
425         }
426         return 0;
427 }
428
429 static int get_cfg_position (const char *name, int type)
430 {
431         int i;
432
433         switch (type) {
434         case PORT_CFG:
435                 for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
436                         if (!strcasecmp(name, port_spec[i].name))
437                                 return i;
438                 }
439                 break;
440         case GEN_CFG:
441                 for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
442                         if (!strcasecmp(name, gen_spec[i].name))
443                                 return i;
444                 }
445         }
446
447         return -1;
448 }
449
450 static inline void misdn_cfg_lock (void)
451 {
452         ast_mutex_lock(&config_mutex);
453 }
454
455 static inline void misdn_cfg_unlock (void)
456 {
457         ast_mutex_unlock(&config_mutex);
458 }
459
460 static void _free_msn_list (struct msn_list* iter)
461 {
462         if (iter->next)
463                 _free_msn_list(iter->next);
464         if (iter->msn)
465                 ast_free(iter->msn);
466         ast_free(iter);
467 }
468
469 static void _free_port_cfg (void)
470 {
471         int i, j;
472         int gn = map[MISDN_CFG_GROUPNAME];
473         union misdn_cfg_pt* free_list[max_ports + 2];
474         
475         memset(free_list, 0, sizeof(free_list));
476         free_list[0] = port_cfg[0];
477         for (i = 1; i <= max_ports; ++i) {
478                 if (port_cfg[i][gn].str) {
479                         /* we always have a groupname in the non-default case, so this is fine */
480                         for (j = 1; j <= max_ports; ++j) {
481                                 if (free_list[j] && free_list[j][gn].str == port_cfg[i][gn].str)
482                                         break;
483                                 else if (!free_list[j]) {
484                                         free_list[j] = port_cfg[i];
485                                         break;
486                                 }
487                         }
488                 }
489         }
490         for (j = 0; free_list[j]; ++j) {
491                 for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
492                         if (free_list[j][i].any) {
493                                 if (port_spec[i].type == MISDN_CTYPE_MSNLIST)
494                                         _free_msn_list(free_list[j][i].ml);
495                                 else
496                                         ast_free(free_list[j][i].any);
497                         }
498                 }
499         }
500 }
501
502 static void _free_general_cfg (void)
503 {
504         int i;
505
506         for (i = 0; i < NUM_GEN_ELEMENTS; i++) 
507                 if (general_cfg[i].any)
508                         ast_free(general_cfg[i].any);
509 }
510
511 void misdn_cfg_get(int port, enum misdn_cfg_elements elem, void *buf, int bufsize)
512 {
513         int place;
514
515         if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
516                 memset(buf, 0, bufsize);
517                 ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Port number %d is not valid.\n", port);
518                 return;
519         }
520
521         misdn_cfg_lock();
522         if (elem == MISDN_CFG_PTP) {
523                 if (!memcpy(buf, &ptp[port], (bufsize > ptp[port]) ? sizeof(ptp[port]) : bufsize))
524                         memset(buf, 0, bufsize);
525         } else {
526                 if ((place = map[elem]) < 0) {
527                         memset(buf, 0, bufsize);
528                         ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Invalid element (%d) requested.\n", elem);
529                 } else {
530                         if (elem < MISDN_CFG_LAST) {
531                                 switch (port_spec[place].type) {
532                                 case MISDN_CTYPE_STR:
533                                         if (port_cfg[port][place].str) {
534                                                 ast_copy_string(buf, port_cfg[port][place].str, bufsize);
535                                         } else if (port_cfg[0][place].str) {
536                                                 ast_copy_string(buf, port_cfg[0][place].str, bufsize);
537                                         } else
538                                                 memset(buf, 0, bufsize);
539                                         break;
540                                 default:
541                                         if (port_cfg[port][place].any)
542                                                 memcpy(buf, port_cfg[port][place].any, bufsize);
543                                         else if (port_cfg[0][place].any)
544                                                 memcpy(buf, port_cfg[0][place].any, bufsize);
545                                         else
546                                                 memset(buf, 0, bufsize);
547                                 }
548                         } else {
549                                 switch (gen_spec[place].type) {
550                                 case MISDN_CTYPE_STR:
551                                         ast_copy_string(buf, S_OR(general_cfg[place].str, ""), bufsize);
552                                         break;
553                                 default:
554                                         if (general_cfg[place].any)
555                                                 memcpy(buf, general_cfg[place].any, bufsize);
556                                         else
557                                                 memset(buf, 0, bufsize);
558                                 }
559                         }
560                 }
561         }
562         misdn_cfg_unlock();
563 }
564
565 enum misdn_cfg_elements misdn_cfg_get_elem(char *name)
566 {
567         int pos;
568
569         /* here comes a hack to replace the (not existing) "name" elemet with the "ports" element */
570         if (!strcmp(name, "ports"))
571                 return MISDN_CFG_GROUPNAME;
572         if (!strcmp(name, "name"))
573                 return MISDN_CFG_FIRST;
574
575         pos = get_cfg_position(name, PORT_CFG);
576         if (pos >= 0)
577                 return port_spec[pos].elem;
578         
579         pos = get_cfg_position(name, GEN_CFG);
580         if (pos >= 0)
581                 return gen_spec[pos].elem;
582         
583         return MISDN_CFG_FIRST;
584 }
585
586 void misdn_cfg_get_name(enum misdn_cfg_elements elem, void *buf, int bufsize)
587 {
588         struct misdn_cfg_spec *spec = NULL;
589         int place = map[elem];
590
591         /* the ptp hack */
592         if (elem == MISDN_CFG_PTP) {
593                 memset(buf, 0, 1);
594                 return;
595         }
596         
597         /* here comes a hack to replace the (not existing) "name" elemet with the "ports" element */
598         if (elem == MISDN_CFG_GROUPNAME) {
599                 if (!snprintf(buf, bufsize, "ports"))
600                         memset(buf, 0, 1);
601                 return;
602         }
603
604         if ((elem > MISDN_CFG_FIRST) && (elem < MISDN_CFG_LAST))
605                 spec = (struct misdn_cfg_spec *)port_spec;
606         else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST))
607                 spec = (struct misdn_cfg_spec *)gen_spec;
608
609         ast_copy_string(buf, spec ? spec[place].name : "", bufsize);
610 }
611
612 void misdn_cfg_get_desc (enum misdn_cfg_elements elem, void *buf, int bufsize, void *buf_default, int bufsize_default)
613 {
614         int place = map[elem];
615         struct misdn_cfg_spec *spec = NULL;
616
617         /* here comes a hack to replace the (not existing) "name" elemet with the "ports" element */
618         if (elem == MISDN_CFG_GROUPNAME) {
619                 ast_copy_string(buf, ports_description, bufsize);
620                 if (buf_default && bufsize_default)
621                         memset(buf_default, 0, 1);
622                 return;
623         }
624
625         if ((elem > MISDN_CFG_FIRST) && (elem < MISDN_CFG_LAST))
626                 spec = (struct misdn_cfg_spec *)port_spec;
627         else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST))
628                 spec = (struct misdn_cfg_spec *)gen_spec;
629                 
630         if (!spec || !spec[place].desc)
631                 memset(buf, 0, 1);
632         else {
633                 ast_copy_string(buf, spec[place].desc, bufsize);
634                 if (buf_default && bufsize) {
635                         if (!strcmp(spec[place].def, NO_DEFAULT))
636                                 memset(buf_default, 0, 1);
637                         else
638                                 ast_copy_string(buf_default, spec[place].def, bufsize_default);
639                 }
640         }
641 }
642
643 int misdn_cfg_is_msn_valid (int port, char* msn)
644 {
645         int re = 0;
646         struct msn_list *iter;
647
648         if (!misdn_cfg_is_port_valid(port)) {
649                 ast_log(LOG_WARNING, "Invalid call to misdn_cfg_is_msn_valid! Port number %d is not valid.\n", port);
650                 return 0;
651         }
652
653         misdn_cfg_lock();
654         if (port_cfg[port][map[MISDN_CFG_MSNS]].ml)
655                 iter = port_cfg[port][map[MISDN_CFG_MSNS]].ml;
656         else
657                 iter = port_cfg[0][map[MISDN_CFG_MSNS]].ml;
658         for (; iter; iter = iter->next) 
659                 if (*(iter->msn) == '*' || ast_extension_match(iter->msn, msn)) {
660                         re = 1;
661                         break;
662                 }
663         misdn_cfg_unlock();
664
665         return re;
666 }
667
668 int misdn_cfg_is_port_valid (int port)
669 {
670         int gn = map[MISDN_CFG_GROUPNAME];
671
672         return (port >= 1 && port <= max_ports && port_cfg[port][gn].str);
673 }
674
675 int misdn_cfg_is_group_method (char *group, enum misdn_cfg_method meth)
676 {
677         int i, re = 0;
678         char *method ;
679
680         misdn_cfg_lock();
681
682         method = port_cfg[0][map[MISDN_CFG_METHOD]].str;
683
684         for (i = 1; i <= max_ports; i++) {
685                 if (port_cfg[i] && port_cfg[i][map[MISDN_CFG_GROUPNAME]].str) {
686                         if (!strcasecmp(port_cfg[i][map[MISDN_CFG_GROUPNAME]].str, group))
687                                 method = (port_cfg[i][map[MISDN_CFG_METHOD]].str ? 
688                                                   port_cfg[i][map[MISDN_CFG_METHOD]].str : port_cfg[0][map[MISDN_CFG_METHOD]].str);
689                 }
690         }
691
692         if (method) {
693                 switch (meth) {
694                 case METHOD_STANDARD:           re = !strcasecmp(method, "standard");
695                                                                         break;
696                 case METHOD_ROUND_ROBIN:        re = !strcasecmp(method, "round_robin");
697                                                                         break;
698                 case METHOD_STANDARD_DEC:       re = !strcasecmp(method, "standard_dec");
699                                                                         break;
700                 }
701         }
702         misdn_cfg_unlock();
703
704         return re;
705 }
706
707 void misdn_cfg_get_ports_string (char *ports)
708 {
709         char tmp[16];
710         int l, i;
711         int gn = map[MISDN_CFG_GROUPNAME];
712
713         *ports = 0;
714
715         misdn_cfg_lock();
716         for (i = 1; i <= max_ports; i++) {
717                 if (port_cfg[i][gn].str) {
718                         if (ptp[i])
719                                 sprintf(tmp, "%dptp,", i);
720                         else
721                                 sprintf(tmp, "%d,", i);
722                         strcat(ports, tmp);
723                 }
724         }
725         misdn_cfg_unlock();
726
727         if ((l = strlen(ports)))
728                 ports[l-1] = 0;
729 }
730
731 void misdn_cfg_get_config_string (int port, enum misdn_cfg_elements elem, char* buf, int bufsize)
732 {
733         int place;
734         char tempbuf[BUFFERSIZE] = "";
735         struct msn_list *iter;
736
737         if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
738                 *buf = 0;
739                 ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Port number %d is not valid.\n", port);
740                 return;
741         }
742
743         place = map[elem];
744
745         misdn_cfg_lock();
746         if (elem == MISDN_CFG_PTP) {
747                 snprintf(buf, bufsize, " -> ptp: %s", ptp[port] ? "yes" : "no");
748         }
749         else if (elem > MISDN_CFG_FIRST && elem < MISDN_CFG_LAST) {
750                 switch (port_spec[place].type) {
751                 case MISDN_CTYPE_INT:
752                 case MISDN_CTYPE_BOOLINT:
753                         if (port_cfg[port][place].num)
754                                 snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[port][place].num);
755                         else if (port_cfg[0][place].num)
756                                 snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[0][place].num);
757                         else
758                                 snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
759                         break;
760                 case MISDN_CTYPE_BOOL:
761                         if (port_cfg[port][place].num)
762                                 snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[port][place].num ? "yes" : "no");
763                         else if (port_cfg[0][place].num)
764                                 snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[0][place].num ? "yes" : "no");
765                         else
766                                 snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
767                         break;
768                 case MISDN_CTYPE_ASTGROUP:
769                         if (port_cfg[port][place].grp)
770                                 snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, 
771                                                  ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[port][place].grp));
772                         else if (port_cfg[0][place].grp)
773                                 snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, 
774                                                  ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[0][place].grp));
775                         else
776                                 snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
777                         break;
778                 case MISDN_CTYPE_MSNLIST:
779                         if (port_cfg[port][place].ml)
780                                 iter = port_cfg[port][place].ml;
781                         else
782                                 iter = port_cfg[0][place].ml;
783                         if (iter) {
784                                 for (; iter; iter = iter->next)
785                                         sprintf(tempbuf, "%s%s, ", tempbuf, iter->msn);
786                                 tempbuf[strlen(tempbuf)-2] = 0;
787                         }
788                         snprintf(buf, bufsize, " -> msns: %s", *tempbuf ? tempbuf : "none");
789                         break;
790                 case MISDN_CTYPE_STR:
791                         if ( port_cfg[port][place].str) {
792                                 snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[port][place].str);
793                         } else if (port_cfg[0][place].str) {
794                                 snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[0][place].str);
795                         } else {
796                                 snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
797                         }
798                         break;
799                 }
800         } else if (elem > MISDN_GEN_FIRST && elem < MISDN_GEN_LAST) {
801                 switch (gen_spec[place].type) {
802                 case MISDN_CTYPE_INT:
803                 case MISDN_CTYPE_BOOLINT:
804                         if (general_cfg[place].num)
805                                 snprintf(buf, bufsize, " -> %s: %d", gen_spec[place].name, *general_cfg[place].num);
806                         else
807                                 snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
808                         break;
809                 case MISDN_CTYPE_BOOL:
810                         if (general_cfg[place].num)
811                                 snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, *general_cfg[place].num ? "yes" : "no");
812                         else
813                                 snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
814                         break;
815                 case MISDN_CTYPE_STR:
816                         if ( general_cfg[place].str) {
817                                 snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, general_cfg[place].str);
818                         } else {
819                                 snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
820                         }
821                         break;
822                 default:
823                         snprintf(buf, bufsize, " -> type of %s not handled yet", gen_spec[place].name);
824                         break;
825                 }
826         } else {
827                 *buf = 0;
828                 ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Invalid config element (%d) requested.\n", elem);
829         }
830         misdn_cfg_unlock();
831 }
832
833 int misdn_cfg_get_next_port (int port)
834 {
835         int p = -1;
836         int gn = map[MISDN_CFG_GROUPNAME];
837         
838         misdn_cfg_lock();
839         for (port++; port <= max_ports; port++) {
840                 if (port_cfg[port][gn].str) {
841                         p = port;
842                         break;
843                 }
844         }
845         misdn_cfg_unlock();
846
847         return p;
848 }
849
850 int misdn_cfg_get_next_port_spin (int port)
851 {
852         int p = misdn_cfg_get_next_port(port);
853         return (p > 0) ? p : misdn_cfg_get_next_port(0);
854 }
855
856 static int _parse (union misdn_cfg_pt *dest, const char *value, enum misdn_cfg_type type, int boolint_def)
857 {
858         int re = 0;
859         int len, tmp;
860         char *valtmp;
861         char *tmp2 = ast_strdupa(value);
862
863         switch (type) {
864         case MISDN_CTYPE_STR:
865                 if ((len = strlen(value))) {
866                         dest->str = ast_malloc((len + 1) * sizeof(char));
867                         strncpy(dest->str, value, len);
868                         dest->str[len] = 0;
869                 } else {
870                         dest->str = ast_malloc(sizeof(char));
871                         dest->str[0] = 0;
872                 }
873                 break;
874         case MISDN_CTYPE_INT:
875         {
876                 char *pat;
877                 if (strchr(value,'x')) 
878                         pat="%x";
879                 else
880                         pat="%d";
881                 if (sscanf(value, pat, &tmp)) {
882                         dest->num = ast_malloc(sizeof(int));
883                         memcpy(dest->num, &tmp, sizeof(int));
884                 } else
885                         re = -1;
886         }
887                 break;
888         case MISDN_CTYPE_BOOL:
889                 dest->num = ast_malloc(sizeof(int));
890                 *(dest->num) = (ast_true(value) ? 1 : 0);
891                 break;
892         case MISDN_CTYPE_BOOLINT:
893                 dest->num = ast_malloc(sizeof(int));
894                 if (sscanf(value, "%d", &tmp)) {
895                         memcpy(dest->num, &tmp, sizeof(int));
896                 } else {
897                         *(dest->num) = (ast_true(value) ? boolint_def : 0);
898                 }
899                 break;
900         case MISDN_CTYPE_MSNLIST:
901                 for (valtmp = strsep(&tmp2, ","); valtmp; valtmp = strsep(&tmp2, ",")) {
902                         if ((len = strlen(valtmp))) {
903                                 struct msn_list *ml = ast_malloc(sizeof(*ml));
904                                 ml->msn = ast_calloc(len+1, sizeof(char));
905                                 strncpy(ml->msn, valtmp, len);
906                                 ml->next = dest->ml;
907                                 dest->ml = ml;
908                         }
909                 }
910                 break;
911         case MISDN_CTYPE_ASTGROUP:
912                 dest->grp = ast_malloc(sizeof(ast_group_t));
913                 *(dest->grp) = ast_get_group(value);
914                 break;
915         }
916
917         return re;
918 }
919
920 static void _build_general_config (struct ast_variable *v)
921 {
922         int pos;
923
924         for (; v; v = v->next) {
925                 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
926                         continue;
927                 if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) || 
928                         (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0))
929                         CLI_ERROR(v->name, v->value, "general");
930         }
931 }
932
933 static void _build_port_config (struct ast_variable *v, char *cat)
934 {
935         int pos, i;
936         union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS];
937         int cfg_for_ports[max_ports + 1];
938
939         if (!v || !cat)
940                 return;
941
942         memset(cfg_tmp, 0, sizeof(cfg_tmp));
943         memset(cfg_for_ports, 0, sizeof(cfg_for_ports));
944
945         if (!strcasecmp(cat, "default")) {
946                 cfg_for_ports[0] = 1;
947         }
948
949         if (((pos = get_cfg_position("name", PORT_CFG)) < 0) || 
950                 (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
951                 CLI_ERROR(v->name, v->value, cat);
952                 return;
953         }
954
955         for (; v; v = v->next) {
956                 if (!strcasecmp(v->name, "ports")) {
957                         char *token, *tmp = ast_strdupa(v->value);
958                         char ptpbuf[BUFFERSIZE] = "";
959                         int start, end;
960                         for (token = strsep(&tmp, ","); token; token = strsep(&tmp, ","), *ptpbuf = 0) { 
961                                 if (!*token)
962                                         continue;
963                                 if (sscanf(token, "%d-%d%s", &start, &end, ptpbuf) >= 2) {
964                                         for (; start <= end; start++) {
965                                                 if (start <= max_ports && start > 0) {
966                                                         cfg_for_ports[start] = 1;
967                                                         ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
968                                                 } else
969                                                         CLI_ERROR(v->name, v->value, cat);
970                                         }
971                                 } else {
972                                         if (sscanf(token, "%d%s", &start, ptpbuf)) {
973                                                 if (start <= max_ports && start > 0) {
974                                                         cfg_for_ports[start] = 1;
975                                                         ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
976                                                 } else
977                                                         CLI_ERROR(v->name, v->value, cat);
978                                         } else
979                                                 CLI_ERROR(v->name, v->value, cat);
980                                 }
981                         }
982                 } else {
983                         if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) || 
984                                 (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
985                                 CLI_ERROR(v->name, v->value, cat);
986                 }
987         }
988
989         for (i = 0; i < (max_ports + 1); ++i) {
990                 if (cfg_for_ports[i]) {
991                         memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp));
992                 }
993         }
994 }
995
996 void misdn_cfg_update_ptp (void)
997 {
998 #ifndef MISDN_1_2
999         char misdn_init[BUFFERSIZE];
1000         char line[BUFFERSIZE];
1001         FILE *fp;
1002         char *tok, *p, *end;
1003         int port;
1004
1005         misdn_cfg_get(0, MISDN_GEN_MISDN_INIT, &misdn_init, sizeof(misdn_init));
1006
1007         if (!ast_strlen_zero(misdn_init)) {
1008                 fp = fopen(misdn_init, "r");
1009                 if (fp) {
1010                         while(fgets(line, sizeof(line), fp)) {
1011                                 if (!strncmp(line, "nt_ptp", 6)) {
1012                                         for (tok = strtok_r(line,",=", &p);
1013                                                  tok;
1014                                                  tok = strtok_r(NULL,",=", &p)) {
1015                                                 port = strtol(tok, &end, 10);
1016                                                 if (end != tok && misdn_cfg_is_port_valid(port)) {
1017                                                         misdn_cfg_lock();
1018                                                         ptp[port] = 1;
1019                                                         misdn_cfg_unlock();
1020                                                 }
1021                                         }
1022                                 }
1023                         }
1024                         fclose(fp);
1025                 } else {
1026                         ast_log(LOG_WARNING,"Couldn't open %s: %s\n", misdn_init, strerror(errno));
1027                 }
1028         }
1029 #else
1030         int i;
1031         int proto;
1032         char filename[128];
1033         FILE *fp;
1034
1035         for (i = 1; i <= max_ports; ++i) {
1036                 snprintf(filename, sizeof(filename), "/sys/class/mISDN-stacks/st-%08x/protocol", i << 8);
1037                 fp = fopen(filename, "r");
1038                 if (!fp) {
1039                         ast_log(LOG_WARNING, "Could not open %s: %s\n", filename, strerror(errno));
1040                         continue;
1041                 }
1042                 if (fscanf(fp, "0x%08x", &proto) != 1)
1043                         ast_log(LOG_WARNING, "Could not parse contents of %s!\n", filename);
1044                 else
1045                         ptp[i] = proto & 1<<5 ? 1 : 0;
1046                 fclose(fp);
1047         }
1048 #endif
1049 }
1050
1051 static void _fill_defaults (void)
1052 {
1053         int i;
1054
1055         for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
1056                 if (!port_cfg[0][i].any && strcasecmp(port_spec[i].def, NO_DEFAULT))
1057                         _parse(&(port_cfg[0][i]), (char *)port_spec[i].def, port_spec[i].type, port_spec[i].boolint_def);
1058         }
1059         for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
1060                 if (!general_cfg[i].any && strcasecmp(gen_spec[i].def, NO_DEFAULT))
1061                         _parse(&(general_cfg[i]), (char *)gen_spec[i].def, gen_spec[i].type, gen_spec[i].boolint_def);
1062         }
1063 }
1064
1065 void misdn_cfg_reload (void)
1066 {
1067         misdn_cfg_init(0, 1);
1068 }
1069
1070 void misdn_cfg_destroy (void)
1071 {
1072         misdn_cfg_lock();
1073
1074         _free_port_cfg();
1075         _free_general_cfg();
1076
1077         ast_free(port_cfg);
1078         ast_free(general_cfg);
1079         ast_free(ptp);
1080         ast_free(map);
1081
1082         misdn_cfg_unlock();
1083         ast_mutex_destroy(&config_mutex);
1084 }
1085
1086 int misdn_cfg_init(int this_max_ports, int reload)
1087 {
1088         char config[] = "misdn.conf";
1089         char *cat, *p;
1090         int i;
1091         struct ast_config *cfg;
1092         struct ast_variable *v;
1093         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1094
1095         if (!(cfg = ast_config_load2(config, "chan_misdn", config_flags))) {
1096                 ast_log(LOG_WARNING, "missing file: misdn.conf\n");
1097                 return -1;
1098         } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
1099                 return 0;
1100
1101         ast_mutex_init(&config_mutex);
1102
1103         /* Copy the default jb config over global_jbconf */
1104         memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
1105
1106         misdn_cfg_lock();
1107
1108         if (this_max_ports) {
1109                 /* this is the first run */
1110                 max_ports = this_max_ports;
1111                 map = ast_calloc(MISDN_GEN_LAST + 1, sizeof(int));
1112                 if (_enum_array_map())
1113                         return -1;
1114                 p = ast_calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
1115                                                    + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
1116                 port_cfg = (union misdn_cfg_pt **)p;
1117                 p += (max_ports + 1) * sizeof(union misdn_cfg_pt *);
1118                 for (i = 0; i <= max_ports; ++i) {
1119                         port_cfg[i] = (union misdn_cfg_pt *)p;
1120                         p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt);
1121                 }
1122                 general_cfg = ast_calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
1123                 ptp = ast_calloc(max_ports + 1, sizeof(int));
1124         }
1125         else {
1126                 /* misdn reload */
1127                 _free_port_cfg();
1128                 _free_general_cfg();
1129                 memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1));
1130                 memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
1131                 memset(ptp, 0, sizeof(int) * (max_ports + 1));
1132         }
1133
1134         cat = ast_category_browse(cfg, NULL);
1135
1136         while(cat) {
1137                 v = ast_variable_browse(cfg, cat);
1138                 if (!strcasecmp(cat, "general")) {
1139                         _build_general_config(v);
1140                 } else {
1141                         _build_port_config(v, cat);
1142                 }
1143                 cat = ast_category_browse(cfg, cat);
1144         }
1145
1146         _fill_defaults();
1147
1148         misdn_cfg_unlock();
1149         ast_config_destroy(cfg);
1150
1151         return 0;
1152 }
1153
1154 struct ast_jb_conf *misdn_get_global_jbconf() {
1155         return &global_jbconf;
1156 }