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