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