52fbe457c35d6786624dab9cc0405c035722feaf
[asterisk/asterisk.git] / channels / chan_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
30 #include "chan_misdn_config.h"
31
32 #include <asterisk/config.h>
33 #include <asterisk/channel.h>
34 #include <asterisk/logger.h>
35 #include <asterisk/lock.h>
36 #include <asterisk/strings.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include <asterisk/utils.h>
41 #define AST_LOAD_CFG ast_config_load
42 #define AST_DESTROY_CFG ast_config_destroy
43
44 #define DEF_ECHOCANCEL 128
45 #define DEF_ECHOTRAINING 1
46
47 struct msn_list {
48         char *msn;
49         struct msn_list *next;
50 };
51
52 struct port_config {
53         char *name;
54         int *rxgain;
55         int *txgain;
56         int *te_choose_channel;
57         char *context;
58         char *language;
59         char *callerid;
60         char *method;
61         int *dialplan; 
62         char *nationalprefix;
63         char *internationalprefix;
64         int *pres;
65         int *always_immediate;
66         int *immediate;
67         int *hold_allowed;
68         int *early_bconnect;
69         int *use_callingpres;
70         int *echocancel;
71         int *echocancelwhenbridged;
72         int *echotraining;
73         struct msn_list *msn_list;
74         ast_group_t *callgroup;         /* Call group */
75         ast_group_t *pickupgroup;       /* Pickup group */
76 };
77
78 struct general_config {
79         int *debug;
80         char *tracefile;
81         int *trace_calls;
82         char *trace_dir;
83         int *bridging;
84         int *stop_tone_after_first_digit;
85         int *append_digits2exten;
86         int *l1_info_ok;
87         int *clear_l3;
88         int *dynamic_crypt;
89         char *crypt_prefix;
90         char *crypt_keys;
91 };
92
93 /* array of port configs, default is at position 0. */
94 static struct port_config **port_cfg;
95 /* max number of available ports, is set on init */
96 static int max_ports;
97 /* general config */
98 static struct general_config *general_cfg;
99 /* storing the ptp flag separated to save memory */
100 static int *ptp;
101
102 static ast_mutex_t config_mutex; 
103
104
105 static inline void misdn_cfg_lock (void) {
106         ast_mutex_lock(&config_mutex);
107 }
108
109 static inline void misdn_cfg_unlock (void) {
110         ast_mutex_unlock(&config_mutex);
111 }
112
113 static void free_msn_list (struct msn_list* iter) {
114         if (iter->next)
115                 free_msn_list(iter->next);
116         if (iter->msn)
117                 free(iter->msn);
118         free(iter);
119 }
120
121 static void free_port_cfg (void) {
122
123         struct port_config **free_list = (struct port_config **)calloc(max_ports + 1, sizeof(struct port_config *));
124
125         int i, j;
126
127         for (i = 0; i < max_ports; i++) {
128                 if (port_cfg[i]) {
129                         for (j = 0; j < max_ports && free_list[j]; j++) {
130                                 if (free_list[j] && free_list[j] == port_cfg[i])
131                                         continue; /* already in list */
132                                 free_list[j] = port_cfg[i];
133                         }
134                 }
135         }
136
137 #define FREE_ELEM(elem) ({ \
138                 if (free_list[i]->elem) \
139                         free(free_list[i]->elem); \
140         })
141         
142         for (i = 0; i < max_ports; i++) {
143                 if (free_list[i]) {
144                         FREE_ELEM(name);
145                         FREE_ELEM(rxgain);
146                         FREE_ELEM(txgain);
147                         FREE_ELEM(te_choose_channel);
148                         FREE_ELEM(context);
149                         FREE_ELEM(language);
150                         FREE_ELEM(callerid);
151                         FREE_ELEM(method);
152                         FREE_ELEM(dialplan);
153                         FREE_ELEM(nationalprefix);
154                         FREE_ELEM(internationalprefix);
155                         FREE_ELEM(pres);
156                         FREE_ELEM(always_immediate);
157                         FREE_ELEM(immediate);
158                         FREE_ELEM(hold_allowed);
159                         FREE_ELEM(early_bconnect);
160                         FREE_ELEM(use_callingpres);
161                         FREE_ELEM(echocancel);
162                         FREE_ELEM(echocancelwhenbridged);
163                         FREE_ELEM(echotraining);
164                         if (free_list[i]->msn_list)
165                                 free_msn_list(free_list[i]->msn_list);
166                         FREE_ELEM(callgroup);
167                         FREE_ELEM(pickupgroup);
168                         free(free_list[i]);
169                 }
170         }
171         free(free_list);
172 }
173
174 static void free_general_cfg (void) {
175
176 #define FREE_GEN_ELEM(elem) ({ \
177                 if (general_cfg->elem) \
178                         free(general_cfg->elem); \
179         })
180         
181         FREE_GEN_ELEM(debug);
182         FREE_GEN_ELEM(tracefile);
183         FREE_GEN_ELEM(trace_calls);
184         FREE_GEN_ELEM(trace_dir);
185         FREE_GEN_ELEM(bridging);
186         FREE_GEN_ELEM(stop_tone_after_first_digit);
187         FREE_GEN_ELEM(append_digits2exten);
188         FREE_GEN_ELEM(l1_info_ok);
189         FREE_GEN_ELEM(clear_l3);
190         FREE_GEN_ELEM(dynamic_crypt);
191         FREE_GEN_ELEM(crypt_prefix);
192         FREE_GEN_ELEM(crypt_keys);
193 }
194
195 #define GET_PORTCFG_STRCPY(item) ({ \
196                 char *temp; \
197                 if (port_cfg[port] && port_cfg[port]->item) \
198                         temp = port_cfg[port]->item; \
199                 else \
200                         temp = port_cfg[0]->item; \
201                 if (!temp || !memccpy((void *)buf, (void *)temp, '\0', bufsize)) \
202                         memset(buf, 0, 1); \
203         })
204
205 #define GET_GENCFG_STRCPY(item) ({ \
206                 if (general_cfg && general_cfg->item) { \
207                         if (!memccpy((void *)buf, (void *)general_cfg->item, '\0', bufsize)) \
208                                 memset(buf, 0, 1); \
209                 } else \
210                         memset(buf, 0, 1); \
211         })
212
213 #define GET_PORTCFG_MEMCPY(item) ({ \
214                 typeof(port_cfg[0]->item) temp; \
215                 if (port_cfg[port] && port_cfg[port]->item) \
216                         temp = port_cfg[port]->item; \
217                 else \
218                         temp = port_cfg[0]->item; \
219                 if (temp) { \
220                         int l = sizeof(*temp); \
221                         if (l > bufsize) \
222                                 memset(buf, 0, bufsize); \
223                         else \
224                                 memcpy(buf, temp, l); \
225                 } else \
226                         memset(buf, 0, bufsize); \
227         })
228
229 #define GET_GENCFG_MEMCPY(item) ({ \
230                 if (general_cfg && general_cfg->item) { \
231                         typeof(general_cfg->item) temp = general_cfg->item; \
232                         int l = sizeof(*temp); \
233                         if (l > bufsize) \
234                                 memset(buf, 0, bufsize); \
235                         else \
236                                 memcpy(buf, temp, l); \
237                 } else \
238                         memset(buf, 0, bufsize); \
239         })
240
241 void misdn_cfg_get(int port, enum misdn_cfg_elements elem, void *buf, int bufsize) {
242         
243         if (!(elem > MISDN_GEN_FIRST) && !misdn_cfg_is_port_valid(port)) {
244                 memset(buf, 0, bufsize);
245                 ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Port number %d is not valid.\n", port);
246                 return;
247         }
248
249         misdn_cfg_lock();
250         
251         switch (elem) {
252                 
253                 /* port config elements */
254                         
255                 case MISDN_CFG_PTP:             if (sizeof(ptp[port]) <= bufsize)
256                                                         memcpy(buf, &ptp[port], sizeof(ptp[port]));
257                                                 else
258                                                         buf = 0; /* error, should not happen */
259                                                 break;
260                 case MISDN_CFG_GROUPNAME:       GET_PORTCFG_STRCPY(name);
261                                                 break;
262                 case MISDN_CFG_RXGAIN:          GET_PORTCFG_MEMCPY(rxgain);
263                                                 break;
264                 case MISDN_CFG_TXGAIN:          GET_PORTCFG_MEMCPY(txgain);
265                                                 break;
266                 case MISDN_CFG_TE_CHOOSE_CHANNEL:
267                                                 GET_PORTCFG_MEMCPY(te_choose_channel);
268                                                 break;
269                 case MISDN_CFG_CONTEXT:         GET_PORTCFG_STRCPY(context);
270                                                 break;
271                 case MISDN_CFG_LANGUAGE:        GET_PORTCFG_STRCPY(language);
272                                                 break;
273                 case MISDN_CFG_CALLERID:        GET_PORTCFG_STRCPY(callerid);
274                                                 break;
275                 case MISDN_CFG_METHOD:          GET_PORTCFG_STRCPY(method);
276                                                 break;
277                 case MISDN_CFG_DIALPLAN:        GET_PORTCFG_MEMCPY(dialplan);
278                                                 break;
279                 case MISDN_CFG_NATPREFIX:       GET_PORTCFG_STRCPY(nationalprefix);
280                                                 break;
281                 case MISDN_CFG_INTERNATPREFIX:
282                                                 GET_PORTCFG_STRCPY(internationalprefix);
283                                                 break;
284                 case MISDN_CFG_PRES:            GET_PORTCFG_MEMCPY(pres);
285                                                 break;
286                 case MISDN_CFG_ALWAYS_IMMEDIATE:
287                                                 GET_PORTCFG_MEMCPY(always_immediate);
288                                                 break;
289                 case MISDN_CFG_IMMEDIATE:       GET_PORTCFG_MEMCPY(immediate);
290                                                 break;
291                 case MISDN_CFG_HOLD_ALLOWED:
292                                                 GET_PORTCFG_MEMCPY(hold_allowed);
293                                                 break;
294                 case MISDN_CFG_EARLY_BCONNECT:
295                                                 GET_PORTCFG_MEMCPY(early_bconnect);
296                                                 break;
297                 case MISDN_CFG_USE_CALLINGPRES:
298                                                 GET_PORTCFG_MEMCPY(use_callingpres);
299                                                 break;
300                 case MISDN_CFG_ECHOCANCEL:
301                                                 GET_PORTCFG_MEMCPY(echocancel );
302                                                 break;
303                 case MISDN_CFG_ECHOCANCELWHENBRIDGED:
304                                                 GET_PORTCFG_MEMCPY(echocancelwhenbridged);
305                                                 break;
306                 case MISDN_CFG_ECHOTRAINING:
307                                                 GET_PORTCFG_MEMCPY(echotraining);
308                                                 break;
309                 case MISDN_CFG_CALLGROUP:       GET_PORTCFG_MEMCPY(callgroup);
310                                                 break;
311                 case MISDN_CFG_PICKUPGROUP:     GET_PORTCFG_MEMCPY(pickupgroup);
312                                                 break;
313                 
314                 /* general config elements */
315                         
316                 case MISDN_GEN_DEBUG:           GET_GENCFG_MEMCPY(debug);
317                                                 break;
318                 case MISDN_GEN_TRACEFILE:       GET_GENCFG_STRCPY(tracefile);
319                                                 break;
320                 case MISDN_GEN_TRACE_CALLS: GET_GENCFG_MEMCPY(trace_calls);
321                                                 break;
322                 case MISDN_GEN_TRACE_DIR:       GET_GENCFG_STRCPY(trace_dir);
323                                                 break;
324                 case MISDN_GEN_BRIDGING:        GET_GENCFG_MEMCPY(bridging);
325                                                 break;
326                 case MISDN_GEN_STOP_TONE:       GET_GENCFG_MEMCPY(stop_tone_after_first_digit);
327                                                 break;
328                 case MISDN_GEN_APPEND_DIGITS2EXTEN: 
329                                                 GET_GENCFG_MEMCPY(append_digits2exten);
330                                                 break;
331                 case MISDN_GEN_L1_INFO_OK:      GET_GENCFG_MEMCPY(l1_info_ok);
332                                                 break;
333                 case MISDN_GEN_CLEAR_L3:        GET_GENCFG_MEMCPY(clear_l3);
334                                                 break;
335                 case MISDN_GEN_DYNAMIC_CRYPT:   GET_GENCFG_MEMCPY(dynamic_crypt);
336                                                 break;
337                 case MISDN_GEN_CRYPT_PREFIX:    GET_GENCFG_STRCPY(crypt_prefix);
338                                                 break;
339                 case MISDN_GEN_CRYPT_KEYS:      GET_GENCFG_STRCPY(crypt_keys);
340                                                 break;
341                 default:                        memset(buf, 0, bufsize);
342         }
343         
344         misdn_cfg_unlock();
345 }
346
347 int misdn_cfg_is_msn_valid (int port, char* msn) {
348         
349         if (!misdn_cfg_is_port_valid(port)) {
350                 ast_log(LOG_WARNING, "Invalid call to misdn_cfg_is_msn_valid! Port number %d is not valid.\n", port);
351                 return 0;
352         }
353         
354         struct msn_list *iter;
355         
356         misdn_cfg_lock();
357         
358         if (port_cfg[port]->msn_list)
359                 iter = port_cfg[port]->msn_list;
360         else
361                 iter = port_cfg[0]->msn_list;
362         for (; iter; iter = iter->next) 
363                 if (*(iter->msn) == '*' || !strcasecmp(iter->msn, msn)) {
364                         misdn_cfg_unlock();
365                         return 1;
366                 }
367         
368         misdn_cfg_unlock();
369         
370         return 0;
371 }
372
373 int misdn_cfg_is_port_valid (int port) {
374         
375         misdn_cfg_lock();
376         
377         if (port < 1 || port > max_ports) {
378                 misdn_cfg_unlock();
379                 return 0;
380         }
381
382         int valid = (port_cfg[port] != NULL);
383
384         misdn_cfg_unlock();
385
386         return valid;
387 }
388
389 int misdn_cfg_is_group_method (char *group, enum misdn_cfg_method meth) {
390
391         int i, re = 0;
392         char *method = NULL;
393
394         misdn_cfg_lock();
395         
396         for (i = 0; i < max_ports; i++) {
397                 if (port_cfg[i]) {
398                         if (!strcasecmp(port_cfg[i]->name, group))
399                                 method = port_cfg[i]->method ? port_cfg[i]->method : port_cfg[0]->method;
400                 }
401         }
402
403         if (method) {
404                 switch (meth) {
405                 case METHOD_STANDARD:           re = !strcasecmp(method, "standard");
406                                                                         break;
407                 case METHOD_ROUND_ROBIN:        re = !strcasecmp(method, "round_robin");
408                                                                         break;
409                 }
410         }
411
412         misdn_cfg_unlock();
413
414         return re;
415 }
416
417 void misdn_cfg_get_ports_string (char *ports) {
418         *ports = 0;
419         char tmp[16];
420         int l;
421         
422         misdn_cfg_lock();
423
424         int i = 1;
425         for (; i <= max_ports; i++) {
426                 if (port_cfg[i]) {
427                         if (ptp[i])
428                                 sprintf(tmp, "%dptp,", i);
429                         else
430                                 sprintf(tmp, "%d,", i);
431                         strcat(ports, tmp);
432                 }
433         }
434         
435         misdn_cfg_unlock();
436
437         if ((l = strlen(ports)))
438                 ports[l-1] = 0;
439 }
440
441 #define GET_CFG_STRING(typestr, type) ({ \
442                 if (port_cfg[port] && port_cfg[port]->type) \
443                         snprintf(buf, bufsize, "%s " #typestr ": %s", begin, port_cfg[port]->type); \
444                 else \
445                         snprintf(buf, bufsize, "%s " #typestr ": %s", begin, port_cfg[0]->type); \
446         }) \
447
448 #define GET_GEN_STRING(typestr, type) ({ \
449                 snprintf(buf, bufsize, "%s " #typestr ": %s", begin, general_cfg->type ? general_cfg->type : "not set"); \
450         }) \
451
452 #define GET_CFG_INT(typestr, type) ({ \
453                 if (port_cfg[port] && port_cfg[port]->type) \
454                         snprintf(buf, bufsize, "%s " #typestr ": %d", begin, *port_cfg[port]->type); \
455                 else \
456                         snprintf(buf, bufsize, "%s " #typestr ": %d", begin, *port_cfg[0]->type); \
457         }) \
458
459 #define GET_GEN_INT(typestr, type) ({ \
460                 snprintf(buf, bufsize, "%s " #typestr ": %d", begin, general_cfg->type ? *general_cfg->type : 0); \
461         }) \
462
463 #define GET_CFG_BOOL(typestr, type, yes, no) ({ \
464                 int bool; \
465                 if (port_cfg[port] && port_cfg[port]->type) \
466                         bool = *port_cfg[port]->type; \
467                 else \
468                         bool = *port_cfg[0]->type; \
469                 snprintf(buf, bufsize, "%s " #typestr ": %s", begin, bool ? #yes : #no); \
470         }) \
471
472 #define GET_CFG_HYBRID(typestr, type, yes, no) ({ \
473                 int bool; \
474                 if (port_cfg[port] && port_cfg[port]->type) \
475                         bool = *port_cfg[port]->type; \
476                 else \
477                         bool = *port_cfg[0]->type; \
478                 if (bool == 1 || bool == 0) \
479                         snprintf(buf, bufsize, "%s " #typestr ": %s", begin, bool ? #yes : #no); \
480                 else \
481                         snprintf(buf, bufsize, "%s " #typestr ": %d", begin, bool); \
482         }) \
483
484 #define GET_GEN_BOOL(typestr, type, yes, no) ({ \
485                 snprintf(buf, bufsize, "%s " #typestr ": %s", begin, general_cfg->type ? (*general_cfg->type ? #yes : #no) : "not set"); \
486         }) \
487
488 #define GET_CFG_AST_GROUP_T(typestr, type) ({ \
489                 ast_group_t *tmp; \
490                 if (port_cfg[port] && port_cfg[port]->type) \
491                         tmp = port_cfg[port]->type; \
492                 else \
493                         tmp = port_cfg[0]->type; \
494                 if (tmp) { \
495                         char tmpbuf[256]; \
496                         snprintf(buf, bufsize, "%s " #typestr ": %s", begin, ast_print_group(tmpbuf, sizeof(tmpbuf), *tmp)); \
497                 } else \
498                         snprintf(buf, bufsize, "%s " #typestr ": %s", begin, "none"); \
499         }) \
500
501 void misdn_cfg_get_config_string(int port, enum misdn_cfg_elements elem, char* buf, int bufsize) {
502
503         if (!(elem > MISDN_GEN_FIRST) && !misdn_cfg_is_port_valid(port)) {
504                 *buf = 0;
505                 ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Port number %d is not valid.\n", port);
506                 return;
507         }
508         
509         char begin[] = " -> ";
510         
511         misdn_cfg_lock();
512         
513         switch (elem) {
514                 
515                 case MISDN_CFG_PTP:             snprintf(buf, bufsize, "%s PTP: %s", begin, ptp[port] ? "yes" : "no");
516                                                                         break;
517                 case MISDN_CFG_GROUPNAME:       GET_CFG_STRING(GROUPNAME, name);
518                                                                         break;
519                 case MISDN_CFG_RXGAIN:          GET_CFG_INT(RXGAIN, rxgain);
520                                                                         break;
521                 case MISDN_CFG_TXGAIN:          GET_CFG_INT(TXGAIN, txgain);
522                                                                         break;
523                 case MISDN_CFG_TE_CHOOSE_CHANNEL:
524                                                 GET_CFG_BOOL(TE_CHOOSE_CHANNEL, te_choose_channel, yes, no);
525                                                                         break;
526                 case MISDN_CFG_CONTEXT:         GET_CFG_STRING(CONTEXT, context);
527                                                                         break;
528                 case MISDN_CFG_LANGUAGE:        GET_CFG_STRING(LANGUAGE, language);
529                                                                         break;
530                 case MISDN_CFG_CALLERID:        GET_CFG_STRING(CALLERID, callerid);
531                                                                         break;
532                 case MISDN_CFG_METHOD:          GET_CFG_STRING(METHOD, method);
533                                                                         break;
534                 case MISDN_CFG_DIALPLAN:        GET_CFG_INT(DIALPLAN, dialplan);
535                                                                         break;
536                 case MISDN_CFG_NATPREFIX:       GET_CFG_STRING(NATIONALPREFIX, nationalprefix);
537                                                                         break;
538                 case MISDN_CFG_INTERNATPREFIX:
539                                                 GET_CFG_STRING(INTERNATIONALPREFIX, internationalprefix);
540                                                                         break;
541                 case MISDN_CFG_PRES:            GET_CFG_BOOL(PRESENTATION, pres, allowed, not_screened);
542                                                                         break;
543                 case MISDN_CFG_ALWAYS_IMMEDIATE:
544                                                 GET_CFG_BOOL(ALWAYS_IMMEDIATE, always_immediate, yes, no);
545                                                                         break;
546                 case MISDN_CFG_IMMEDIATE:       GET_CFG_BOOL(IMMEDIATE, immediate, yes, no);
547                                                                         break;
548                 case MISDN_CFG_HOLD_ALLOWED:
549                                                 GET_CFG_BOOL(HOLD_ALLOWED, hold_allowed, yes, no);
550                                                                         break;
551                 case MISDN_CFG_EARLY_BCONNECT:
552                                                 GET_CFG_BOOL(EARLY_BCONNECT, early_bconnect, yes, no);
553                                                                         break;
554                 case MISDN_CFG_USE_CALLINGPRES:
555                                                 GET_CFG_BOOL(USE_CALLINGPRES, use_callingpres, yes, no);
556                                                                         break;
557                 case MISDN_CFG_ECHOCANCEL:      GET_CFG_HYBRID(ECHOCANCEL, echocancel, yes, no);
558                                                                         break;
559                 case MISDN_CFG_ECHOCANCELWHENBRIDGED:
560                                                 GET_CFG_BOOL(ECHOCANCELWHENBRIDGED, echocancelwhenbridged, yes, no);
561                                                                         break;
562                 case MISDN_CFG_ECHOTRAINING:
563                                                 GET_CFG_HYBRID(ECHOTRAINING, echotraining, yes, no);
564                                                                         break;
565                 case MISDN_CFG_CALLGROUP:       GET_CFG_AST_GROUP_T(CALLINGGROUP, callgroup);
566                                                                         break;
567                 case MISDN_CFG_PICKUPGROUP:     GET_CFG_AST_GROUP_T(PICKUPGROUP, pickupgroup);
568                                                                         break;
569                 case MISDN_CFG_MSNS:            {
570                                                         char tmpbuffer[BUFFERSIZE];
571                                                         tmpbuffer[0] = 0;
572                                                         struct msn_list *iter;
573                                                         if (port_cfg[port]->msn_list)
574                                                                 iter = port_cfg[port]->msn_list;
575                                                         else
576                                                                 iter = port_cfg[0]->msn_list;
577                                                         if (iter) {
578                                                                 for (; iter; iter = iter->next)
579                                                                         sprintf(tmpbuffer, "%s%s, ", tmpbuffer, iter->msn);
580                                                                 tmpbuffer[strlen(tmpbuffer)-2] = 0;
581                                                         }
582                                                         snprintf(buf, bufsize, "%s MSNs: %s", begin, *tmpbuffer ? tmpbuffer : "none"); \
583                                                 }
584                                                 break;
585                 
586                 /* general config elements */
587                 
588                 case MISDN_GEN_DEBUG:           GET_GEN_INT(DEBUG_LEVEL, debug);
589                                                                         break;
590                 case MISDN_GEN_TRACEFILE:       GET_GEN_STRING(TRACEFILE, tracefile);
591                                                                         break;
592                 case MISDN_GEN_TRACE_CALLS: GET_GEN_BOOL(TRACE_CALLS, trace_calls, true, false);
593                                                                         break;
594                 case MISDN_GEN_TRACE_DIR:       GET_GEN_STRING(TRACE_DIR, trace_dir);
595                                                                         break;
596                 case MISDN_GEN_BRIDGING:        GET_GEN_BOOL(BRIDGING, bridging, yes, no);
597                                                                         break;
598                 case MISDN_GEN_STOP_TONE:       GET_GEN_BOOL(STOP_TONE_AFTER_FIRST_DIGIT, stop_tone_after_first_digit, yes, no);
599                                                                         break;
600                 case MISDN_GEN_APPEND_DIGITS2EXTEN: 
601                                                 GET_GEN_BOOL(APPEND_DIGITS2EXTEN, append_digits2exten, yes, no);
602                                                                         break;
603                 case MISDN_GEN_L1_INFO_OK:      GET_GEN_BOOL(L1_INFO_OK, l1_info_ok, yes, no);
604                                                                         break;
605                 case MISDN_GEN_CLEAR_L3:        GET_GEN_BOOL(CLEAR_L3, clear_l3, yes, no);
606                                                                         break;
607                 case MISDN_GEN_DYNAMIC_CRYPT:
608                                                 GET_GEN_BOOL(DYNAMIC_CRYPT,dynamic_crypt, yes, no);
609                                                                         break;
610                 case MISDN_GEN_CRYPT_PREFIX:
611                                                 GET_GEN_STRING(CRYPT_PREFIX, crypt_prefix);
612                                                                         break;
613                 case MISDN_GEN_CRYPT_KEYS:      GET_GEN_STRING(CRYPT_KEYS, crypt_keys);
614                                                                         break;
615                                                                         
616                 default:                        *buf = 0;
617                                                                         break;
618         }
619
620         misdn_cfg_unlock();
621 }
622
623 int misdn_cfg_get_next_port (int port) {
624         
625         misdn_cfg_lock();
626         
627         for (port++; port <= max_ports; port++) {
628                 if (port_cfg[port]) {
629                         misdn_cfg_unlock();
630                         return port;
631                 }
632         }
633         
634         misdn_cfg_unlock();
635         
636         return -1;
637 }
638
639 int misdn_cfg_get_next_port_spin (int port) {
640
641         int ret = misdn_cfg_get_next_port(port);
642
643         if (ret > 0)
644                 return ret;
645
646         return misdn_cfg_get_next_port(0);
647 }
648
649 #define PARSE_GEN_INT(item) ({ \
650                 if (!strcasecmp(v->name, #item)) { \
651                         int temp; \
652                         if (!sscanf(v->value, "%d", &temp)) { \
653                                 ast_log(LOG_WARNING, "Value \"%s\" for \"" #item "\" (generals section) invalid or out of range! Please edit your misdn.conf and then do a \"misdn reload\".\n", v->value); \
654                         } else { \
655                                 general_cfg->item = (int *)malloc(sizeof(int)); \
656                                 memcpy(general_cfg->item, &temp, sizeof(int)); \
657                         } \
658                         continue; \
659                 } \
660         }) \
661
662 #define PARSE_GEN_BOOL(item) ({ \
663                 if (!strcasecmp(v->name, #item)) { \
664                         general_cfg->item = (int *)malloc(sizeof(int)); \
665                         *(general_cfg->item) = ast_true(v->value)?1:0; \
666                         continue; \
667                 } \
668         })
669
670 #define PARSE_GEN_STR(item) ({ \
671                 if (!strcasecmp(v->name, #item)) { \
672                         int l = strlen(v->value); \
673                         if (l) { \
674                                 general_cfg->item = (char *)calloc(l+1, sizeof(char)); \
675                                 strncpy(general_cfg->item,v->value, l); \
676                         } \
677                         continue; \
678                 } \
679         })
680
681 static void build_general_config(struct ast_variable *v) {
682
683         if (!v) 
684                 return;
685
686         for (; v; v = v->next) {
687
688                 PARSE_GEN_INT(debug);
689                 PARSE_GEN_STR(tracefile);
690                 PARSE_GEN_BOOL(trace_calls);
691                 PARSE_GEN_STR(trace_dir);
692                 PARSE_GEN_BOOL(bridging);
693                 PARSE_GEN_BOOL(stop_tone_after_first_digit);
694                 PARSE_GEN_BOOL(append_digits2exten);
695                 PARSE_GEN_BOOL(l1_info_ok);
696                 PARSE_GEN_BOOL(clear_l3);
697                 PARSE_GEN_BOOL(dynamic_crypt);
698                 PARSE_GEN_STR(crypt_prefix);
699                 PARSE_GEN_STR(crypt_keys);
700                 
701         }
702 }
703
704 #define PARSE_CFG_HYBRID(item, def) ({ \
705                 if (!strcasecmp(v->name, #item)) { \
706                         new->item = (int *)malloc(sizeof(int)); \
707                         if (!sscanf(v->value, "%d", new->item)) { \
708                                 if (ast_true(v->value)) \
709                                         *new->item = def; \
710                                 else \
711                                         *new->item = 0; \
712                         } \
713                         continue; \
714                 } \
715         }) \
716
717 #define PARSE_CFG_INT(item) ({ \
718                 if (!strcasecmp(v->name, #item)) { \
719                         new->item = (int *)malloc(sizeof(int)); \
720                         if (!sscanf(v->value, "%d", new->item)) { \
721                                 ast_log(LOG_WARNING, "Value \"%s\" for \"" #item "\" of group \"%s\" invalid or out of range! Please edit your misdn.conf and then do a \"misdn reload\".\n", v->value, cat); \
722                                 free(new->item); \
723                                 new->item = NULL; \
724                         } \
725                         continue; \
726                 } \
727         }) \
728
729 #define PARSE_CFG_BOOL(item) ({ \
730                 if (!strcasecmp(v->name, #item)) { \
731                         new->item = (int *)malloc(sizeof(int)); \
732                         *(new->item) = ast_true(v->value)?1:0; \
733                         continue; \
734                 } \
735         })
736
737 #define PARSE_CFG_STR(item) ({ \
738                 if (!strcasecmp(v->name, #item)) { \
739                         int l = strlen(v->value); \
740                         if (l) { \
741                                 new->item = (char *)calloc(l+1, sizeof(char)); \
742                                 strncpy(new->item,v->value,l); \
743                         } \
744                         continue; \
745                 } \
746         })
747
748 static void build_port_config(struct ast_variable *v, char *cat) {
749         if (!v || !cat)
750                 return;
751
752         int cfg_for_ports[max_ports + 1];
753         int i = 0;
754         for (; i < (max_ports + 1); i++) {
755                 cfg_for_ports[i] = 0;
756         }
757         
758         /* we store the default config at position 0 */
759         if (!strcasecmp(cat, "default")) {
760                 cfg_for_ports[0] = 1;
761         }
762
763         struct port_config* new = (struct port_config *)calloc(1, sizeof(struct port_config));
764         
765         {
766                 int l = strlen(cat);
767                 new->name = (char *)calloc(l+1, sizeof(char));
768                 strncpy(new->name, cat, l);
769         }
770         
771         for (; v; v=v->next) {
772                 if (!strcasecmp(v->name, "ports")) {
773                         /* TODO check for value not beeing set, like PORTS= */
774                         char *iter;
775                         char *value = v->value;
776                         while ((iter = strchr(value, ',')) != NULL) {
777                                 *iter = 0;
778                                 /* strip spaces */
779                                 while (*value && *value == ' ') {
780                                         value++;
781                                 }
782                                 /* TODO check for char not 0-9 */
783
784                                 if (*value){
785                                         int p = atoi(value);
786                                         if (p <= max_ports && p > 0) {
787                                                 cfg_for_ports[p] = 1;
788                                                 if (strstr(value, "ptp"))
789                                                         ptp[p] = 1;
790                                         } else
791                                                 ast_log(LOG_WARNING, "Port value \"%s\" of group %s invalid or out of range! Please edit your misdn.conf and then do a \"misdn reload\".\n", value, cat);
792                                         value = ++iter;
793                                 }
794                         }
795                         /* the remaining or the only one */
796                         /* strip spaces */
797                         while (*value && *value == ' ') {
798                                 value++;
799                         }
800                         /* TODO check for char not 0-9 */
801                         if (*value) {
802                                 int p = atoi(value);
803                                 if (p <= max_ports && p > 0) {
804                                         cfg_for_ports[p] = 1;
805                                         if (strstr(value, "ptp"))
806                                                 ptp[p] = 1;
807                                 } else
808                                         ast_log(LOG_WARNING, "Port value \"%s\" of group %s invalid or out of range! Please edit your misdn.conf and then do a \"misdn reload\".\n", value, cat);
809                         }
810                         continue;
811                 }
812                 PARSE_CFG_STR(context);
813                 PARSE_CFG_INT(dialplan);
814                 PARSE_CFG_STR(nationalprefix);
815                 PARSE_CFG_STR(internationalprefix);
816                 PARSE_CFG_STR(language);
817                 if (!strcasecmp(v->name, "presentation")) {
818                         if (v->value && strlen(v->value)) {
819                                 new->pres = (int *)malloc(sizeof(int));
820                                 if (!strcasecmp(v->value, "allowed")) {
821                                         *(new->pres) = 1;
822                                 }
823                                 /* TODO: i assume if it is not "allowed", it is "not_screened" */
824                                 else {
825                                         *(new->pres) = 0;
826                                 }
827                         }
828                         continue;
829                 }
830                 PARSE_CFG_INT(rxgain);
831                 PARSE_CFG_INT(txgain);
832                 PARSE_CFG_BOOL(te_choose_channel);
833                 PARSE_CFG_BOOL(immediate);
834                 PARSE_CFG_BOOL(always_immediate);
835                 PARSE_CFG_BOOL(hold_allowed);
836                 PARSE_CFG_BOOL(early_bconnect);
837                 PARSE_CFG_BOOL(use_callingpres);
838                 PARSE_CFG_HYBRID(echocancel, DEF_ECHOCANCEL);
839                 PARSE_CFG_BOOL(echocancelwhenbridged);
840                 PARSE_CFG_HYBRID(echotraining, DEF_ECHOTRAINING);
841                 PARSE_CFG_STR(callerid);
842                 PARSE_CFG_STR(method);
843                 if (!strcasecmp(v->name, "msns")) {
844                         /* TODO check for value not beeing set, like msns= */
845                         char *iter;
846                         char *value = v->value;
847
848                         while ((iter = strchr(value, ',')) != NULL) {
849                                 *iter = 0;
850                                 /* strip spaces */
851                                 while (*value && *value == ' ') {
852                                         value++;
853                                 }
854                                 /* TODO check for char not 0-9 */
855                                 if (*value){
856                                         int l = strlen(value);
857                                         if (l) {
858                                                 struct msn_list *ml = (struct msn_list *)calloc(1, sizeof(struct msn_list));
859                                                 ml->msn = (char *)calloc(l+1, sizeof(char));
860                                                 strncpy(ml->msn,value,l);
861                                                 ml->next = new->msn_list;
862                                                 new->msn_list = ml;
863                                         }
864                                         value = ++iter;
865                                 }
866                         }
867                         /* the remaining or the only one */
868                         /* strip spaces */
869                         while (*value && *value == ' ') {
870                                 value++;
871                         }
872                         /* TODO check for char not 0-9 */
873                         if (*value) {
874                                 int l = strlen(value);
875                                 if (l) {
876                                         struct msn_list *ml = (struct msn_list *)calloc(1, sizeof(struct msn_list));
877                                         ml->msn = (char *)calloc(l+1, sizeof(char));
878                                         strncpy(ml->msn,value,l);
879                                         ml->next = new->msn_list;
880                                         new->msn_list = ml;
881                                 }
882                         }
883                         continue;
884                 }
885                 if (!strcasecmp(v->name, "callgroup")) {
886                         new->callgroup = (ast_group_t *)malloc(sizeof(ast_group_t));
887                         *(new->callgroup)=ast_get_group(v->value);
888                         continue;
889                 }
890                 if (!strcasecmp(v->name, "pickupgroup")) {
891                         new->pickupgroup = (ast_group_t *)malloc(sizeof(ast_group_t));
892                         *(new->pickupgroup)=ast_get_group(v->value);
893                         continue;
894                 }
895         }
896         /* store the new config in our array of port configs */
897         for (i = 0; i < (max_ports + 1); i++) {
898                 if (cfg_for_ports[i])
899                         port_cfg[i] = new;
900         }
901 }
902
903
904 static void fill_defaults (void) {
905         
906         /* general defaults */
907         if (!general_cfg->debug)
908                 general_cfg->debug = (int*)calloc(1, sizeof(int));
909         if (!general_cfg->trace_calls)
910                 general_cfg->trace_calls = (int*)calloc(1, sizeof(int));
911         if (!general_cfg->trace_dir) {
912                 general_cfg->trace_dir = (char *)malloc(10 * sizeof(char));
913                 sprintf(general_cfg->trace_dir, "/var/log/");
914         }
915         if (!general_cfg->bridging) {
916                 general_cfg->bridging = (int*)malloc(sizeof(int));
917                 *general_cfg->bridging = 1;
918         }
919         if (!general_cfg->stop_tone_after_first_digit) {
920                 general_cfg->stop_tone_after_first_digit = (int*)malloc(sizeof(int));
921                 *general_cfg->stop_tone_after_first_digit = 1;
922         }
923         if (!general_cfg->append_digits2exten) {
924                 general_cfg->append_digits2exten = (int*)malloc(sizeof(int));
925                 *general_cfg->append_digits2exten = 1;
926         }
927         if (!general_cfg->l1_info_ok) {
928                 general_cfg->l1_info_ok = (int*)malloc(sizeof(int));
929                 *general_cfg->l1_info_ok = 1;
930         }
931         if (!general_cfg->clear_l3)
932                 general_cfg->clear_l3 =(int*)calloc(1, sizeof(int));
933         if (!general_cfg->dynamic_crypt)
934                 general_cfg->dynamic_crypt = (int*)calloc(1, sizeof(int));
935
936         /* defaults for default port config */
937         if (!port_cfg[0])
938                 port_cfg[0] = (struct port_config*)calloc(1, sizeof(struct port_config));
939         if (!port_cfg[0]->name) {
940                 port_cfg[0]->name = (char *)malloc(8 * sizeof(char));
941                 sprintf(port_cfg[0]->name, "default");
942         }
943         if (!port_cfg[0]->rxgain)
944                 port_cfg[0]->rxgain = (int *)calloc(1, sizeof(int));
945         if (!port_cfg[0]->txgain)
946                 port_cfg[0]->txgain = (int *)calloc(1, sizeof(int));
947         if (!port_cfg[0]->te_choose_channel)
948                 port_cfg[0]->te_choose_channel = (int *)calloc(1, sizeof(int));
949         if (!port_cfg[0]->context) {
950                 port_cfg[0]->context = (char *)malloc(8 * sizeof(char));
951                 sprintf(port_cfg[0]->context, "default");
952         }
953         if (!port_cfg[0]->language) {
954                 port_cfg[0]->language = (char *)malloc(3 * sizeof(char));
955                 sprintf(port_cfg[0]->language, "en");
956         }
957         if (!port_cfg[0]->callerid)
958                 port_cfg[0]->callerid = (char *)calloc(1, sizeof(char));
959         if (!port_cfg[0]->method) {
960                 port_cfg[0]->method = (char *)malloc(9 * sizeof(char));
961                 sprintf(port_cfg[0]->method, "standard");
962         }
963         if (!port_cfg[0]->dialplan)
964                 port_cfg[0]->dialplan = (int *)calloc(1, sizeof(int));
965         if (!port_cfg[0]->nationalprefix) {
966                 port_cfg[0]->nationalprefix = (char *)malloc(2 * sizeof(char));
967                 sprintf(port_cfg[0]->nationalprefix, "0");
968         }
969         if (!port_cfg[0]->internationalprefix) {
970                 port_cfg[0]->internationalprefix = (char *)malloc(3 * sizeof(char));
971                 sprintf(port_cfg[0]->internationalprefix, "00");
972         }
973         if (!port_cfg[0]->pres) {
974                 port_cfg[0]->pres = (int *)malloc(sizeof(int));
975                 *port_cfg[0]->pres = 1;
976         }
977         if (!port_cfg[0]->always_immediate)
978                 port_cfg[0]->always_immediate = (int *)calloc(1, sizeof(int));
979         if (!port_cfg[0]->immediate)
980                 port_cfg[0]->immediate = (int *)calloc(1, sizeof(int));
981         if (!port_cfg[0]->hold_allowed)
982                 port_cfg[0]->hold_allowed = (int *)calloc(1, sizeof(int));
983         if (!port_cfg[0]->early_bconnect) {
984                 port_cfg[0]->early_bconnect = (int *)malloc(sizeof(int));
985                 *port_cfg[0]->early_bconnect = 1;
986         }
987         if (!port_cfg[0]->echocancel)
988                 port_cfg[0]->echocancel=(int *)calloc(1, sizeof(int));
989         if (!port_cfg[0]->echocancelwhenbridged)
990                 port_cfg[0]->echocancelwhenbridged=(int *)calloc(1, sizeof(int));
991         if (!port_cfg[0]->echotraining) {
992                 port_cfg[0]->echotraining=(int *)malloc(sizeof(int));
993                 *port_cfg[0]->echotraining = 1;
994         }
995         if (!port_cfg[0]->use_callingpres) {
996                 port_cfg[0]->use_callingpres = (int *)malloc(sizeof(int));
997                 *port_cfg[0]->use_callingpres = 1;
998         }
999         if (!port_cfg[0]->msn_list) {
1000                 port_cfg[0]->msn_list = (struct msn_list *)malloc(sizeof(struct msn_list));
1001                 port_cfg[0]->msn_list->next = NULL;
1002                 port_cfg[0]->msn_list->msn = (char *)calloc(2, sizeof(char));
1003                 *(port_cfg[0]->msn_list->msn) = '*';
1004         }
1005 }
1006
1007 void misdn_cfg_reload (void) {
1008         misdn_cfg_init (0);
1009 }
1010
1011 void misdn_cfg_destroy (void) {
1012
1013         misdn_cfg_lock();
1014         
1015         free_port_cfg();
1016         free_general_cfg();
1017         
1018         free(port_cfg);
1019         free(general_cfg);
1020         free(ptp);
1021
1022         misdn_cfg_unlock();
1023         ast_mutex_destroy(&config_mutex);
1024 }
1025
1026 void misdn_cfg_init (int this_max_ports)
1027 {
1028         char config[]="misdn.conf";
1029         
1030         struct ast_config *cfg;
1031         cfg = AST_LOAD_CFG(config);
1032         if (!cfg) {
1033                 ast_log(LOG_WARNING,"no misdn.conf ?\n");
1034                 return;
1035         }
1036
1037         misdn_cfg_lock();
1038         
1039         if (this_max_ports) {
1040                 /* this is the first run */
1041                 max_ports = this_max_ports;
1042                 port_cfg = (struct port_config **)calloc(max_ports + 1, sizeof(struct port_config *));
1043                 general_cfg = (struct general_config*)calloc(1, sizeof(struct general_config));
1044                 ptp = (int *)calloc(max_ports + 1, sizeof(int));
1045         }
1046         else {
1047                 free_port_cfg();
1048                 free_general_cfg();
1049                 port_cfg = memset(port_cfg, 0, sizeof(struct port_config *) * (max_ports + 1));
1050                 general_cfg = memset(general_cfg, 0, sizeof(struct general_config));
1051                 ptp = memset(ptp, 0, sizeof(int) * (max_ports + 1));
1052         }
1053         
1054         char *cat;
1055         cat = ast_category_browse(cfg, NULL);
1056
1057         while(cat) {
1058                 struct ast_variable *v=ast_variable_browse(cfg,cat);
1059                 if (!strcasecmp(cat,"general")) {
1060                         build_general_config (v);
1061                 } else {
1062                         build_port_config (v, cat);
1063                 }
1064                 cat=ast_category_browse(cfg,cat);
1065         }
1066
1067         fill_defaults();
1068         
1069         misdn_cfg_unlock();
1070         
1071         AST_DESTROY_CFG(cfg);
1072 }