Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:54 2009

## Asterisk developer's documentation

# misdn_config.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 2005, Christian Richter
    00005  *
    00006  * Christian Richter <crich@beronet.com>
    00007  *
    00008  * See http://www.asterisk.org for more information about
    00009  * the Asterisk project. Please do not directly contact
    00010  * any of the maintainers of this project for assistance;
    00011  * the project provides a web site, mailing lists and IRC
    00012  * channels for your use.
    00013  *
    00014  * This program is free software, distributed under the terms of
    00015  * the GNU General Public License Version 2. See the LICENSE file
    00016  * at the top of the source tree.
    00017  *
    00018  */
    00019
    00020 /*!
    00021  * \file
    00022  *
    00023  * \brief chan_misdn configuration management
    00024  * \author Christian Richter <crich@beronet.com>
    00025  *
    00026  * \ingroup channel_drivers
    00027  */
    00028
    00029 #include <stdlib.h>
    00030 #include <stdio.h>
    00031 #include <string.h>
    00032 #include <errno.h>
    00033
    00034 #include "chan_misdn_config.h"
    00035
    00036 #include <asterisk/config.h>
    00037 #include <asterisk/channel.h>
    00038 #include <asterisk/logger.h>
    00039 #include <asterisk/lock.h>
    00040 #include <asterisk/pbx.h>
    00041 #include <asterisk/strings.h>
    00042 #include <asterisk/utils.h>
    00043
    00044 #define AST_LOAD_CFG ast_config_load
    00045 #define AST_DESTROY_CFG ast_config_destroy
    00046
    00047 #define NO_DEFAULT "<>"
    00048 #define NONE 0
    00049
    00050 #define GEN_CFG 1
    00051 #define PORT_CFG 2
    00052 #define NUM_GEN_ELEMENTS (sizeof(gen_spec) / sizeof(struct misdn_cfg_spec))
    00053 #define NUM_PORT_ELEMENTS (sizeof(port_spec) / sizeof(struct misdn_cfg_spec))
    00054
    00055 enum misdn_cfg_type {
    00056    MISDN_CTYPE_STR,
    00057    MISDN_CTYPE_INT,
    00058    MISDN_CTYPE_BOOL,
    00059    MISDN_CTYPE_BOOLINT,
    00060    MISDN_CTYPE_MSNLIST,
    00061    MISDN_CTYPE_ASTGROUP
    00062 };
    00063
    00064 struct msn_list {
    00065    char *msn;
    00066    struct msn_list *next;
    00067 };
    00068
    00069 union misdn_cfg_pt {
    00070    char *str;
    00071    int *num;
    00072    struct msn_list *ml;
    00073    ast_group_t *grp;
    00074    void *any;
    00075 };
    00076
    00077 struct misdn_cfg_spec {
    00078    char name[BUFFERSIZE];
    00079    enum misdn_cfg_elements elem;
    00080    enum misdn_cfg_type type;
    00081    char def[BUFFERSIZE];
    00082    int boolint_def;
    00083 };
    00084
    00085 static const struct misdn_cfg_spec port_spec[] = {
    00086    { "name", MISDN_CFG_GROUPNAME, MISDN_CTYPE_STR, "default", NONE },
    00087    { "allowed_bearers", MISDN_CFG_ALLOWED_BEARERS, MISDN_CTYPE_STR, "all", NONE },
    00088    { "rxgain", MISDN_CFG_RXGAIN, MISDN_CTYPE_INT, "0", NONE },
    00089    { "txgain", MISDN_CFG_TXGAIN, MISDN_CTYPE_INT, "0", NONE },
    00090    { "te_choose_channel", MISDN_CFG_TE_CHOOSE_CHANNEL, MISDN_CTYPE_BOOL, "no", NONE },
    00091    { "far_alerting", MISDN_CFG_FAR_ALERTING, MISDN_CTYPE_BOOL, "no", NONE },
    00092    { "pmp_l1_check", MISDN_CFG_PMP_L1_CHECK, MISDN_CTYPE_BOOL, "no", NONE },
    00093    { "reject_cause", MISDN_CFG_REJECT_CAUSE, MISDN_CTYPE_INT, "21", NONE },
    00094    { "block_on_alarm", MISDN_CFG_ALARM_BLOCK, MISDN_CTYPE_BOOL, "no", NONE },
    00095    { "hdlc", MISDN_CFG_HDLC, MISDN_CTYPE_BOOL, "no", NONE },
    00096    { "context", MISDN_CFG_CONTEXT, MISDN_CTYPE_STR, "default", NONE },
    00097    { "language", MISDN_CFG_LANGUAGE, MISDN_CTYPE_STR, "en", NONE },
    00098    { "musicclass", MISDN_CFG_MUSICCLASS, MISDN_CTYPE_STR, "default", NONE },
    00099    { "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE },
    00100    { "method", MISDN_CFG_METHOD, MISDN_CTYPE_STR, "standard", NONE },
    00101    { "dialplan", MISDN_CFG_DIALPLAN, MISDN_CTYPE_INT, "0", NONE },
    00102    { "localdialplan", MISDN_CFG_LOCALDIALPLAN, MISDN_CTYPE_INT, "0", NONE },
    00103    { "cpndialplan", MISDN_CFG_CPNDIALPLAN, MISDN_CTYPE_INT, "0", NONE },
    00104    { "nationalprefix", MISDN_CFG_NATPREFIX, MISDN_CTYPE_STR, "0", NONE },
    00105    { "internationalprefix", MISDN_CFG_INTERNATPREFIX, MISDN_CTYPE_STR, "00", NONE },
    00106    { "presentation", MISDN_CFG_PRES, MISDN_CTYPE_INT, "-1", NONE },
    00107    { "screen", MISDN_CFG_SCREEN, MISDN_CTYPE_INT, "-1", NONE },
    00108    { "always_immediate", MISDN_CFG_ALWAYS_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE },
    00109    { "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE },
    00110    { "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE },
    00111    { "senddtmf", MISDN_CFG_SENDDTMF, MISDN_CTYPE_BOOL, "no", NONE },
    00112    { "hold_allowed", MISDN_CFG_HOLD_ALLOWED, MISDN_CTYPE_BOOL, "no", NONE },
    00113    { "early_bconnect", MISDN_CFG_EARLY_BCONNECT, MISDN_CTYPE_BOOL, "yes", NONE },
    00114    { "incoming_early_audio", MISDN_CFG_INCOMING_EARLY_AUDIO, MISDN_CTYPE_BOOL, "no", NONE },
    00115    { "echocancel", MISDN_CFG_ECHOCANCEL, MISDN_CTYPE_BOOLINT, "0", 128 },
    00116 #ifdef MISDN_1_2
    00117    { "pipeline", MISDN_CFG_PIPELINE, MISDN_CTYPE_STR, NO_DEFAULT, NONE },
    00118 #endif
    00119    { "need_more_infos", MISDN_CFG_NEED_MORE_INFOS, MISDN_CTYPE_BOOL, "0", NONE },
    00120    { "noautorespond_on_setup", MISDN_CFG_NOAUTORESPOND_ON_SETUP, MISDN_CTYPE_BOOL, "0", NONE },
    00121    { "overlapdial", MISDN_CFG_OVERLAP_DIAL, MISDN_CTYPE_BOOLINT, "0", 4 },
    00122    { "nttimeout", MISDN_CFG_NTTIMEOUT, MISDN_CTYPE_BOOL, "no", NONE },
    00123    { "bridging", MISDN_CFG_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE },
    00124    { "jitterbuffer", MISDN_CFG_JITTERBUFFER, MISDN_CTYPE_INT, "4000", NONE },
    00125    { "jitterbuffer_upper_threshold", MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, MISDN_CTYPE_INT, "0", NONE },
    00126    { "callgroup", MISDN_CFG_CALLGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE },
    00127    { "pickupgroup", MISDN_CFG_PICKUPGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE },
    00128    { "msns", MISDN_CFG_MSNS, MISDN_CTYPE_MSNLIST, "*", NONE }
    00129 };
    00130
    00131 static const struct misdn_cfg_spec gen_spec[] = {
    00132    { "debug", MISDN_GEN_DEBUG, MISDN_CTYPE_INT, "0", NONE },
    00133 #ifndef MISDN_1_2
    00134    { "misdn_init", MISDN_GEN_MISDN_INIT, MISDN_CTYPE_STR, "/etc/misdn-init.conf", NONE },
    00135 #endif
    00136    { "tracefile", MISDN_GEN_TRACEFILE, MISDN_CTYPE_STR, "/var/log/asterisk/misdn.log", NONE },
    00137    { "bridging", MISDN_GEN_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE },
    00138    { "stop_tone_after_first_digit", MISDN_GEN_STOP_TONE, MISDN_CTYPE_BOOL, "yes", NONE },
    00139    { "append_digits2exten", MISDN_GEN_APPEND_DIGITS2EXTEN, MISDN_CTYPE_BOOL, "yes", NONE },
    00140    { "dynamic_crypt", MISDN_GEN_DYNAMIC_CRYPT, MISDN_CTYPE_BOOL, "no", NONE },
    00141    { "crypt_prefix", MISDN_GEN_CRYPT_PREFIX, MISDN_CTYPE_STR, NO_DEFAULT, NONE },
    00142    { "crypt_keys", MISDN_GEN_CRYPT_KEYS, MISDN_CTYPE_STR, NO_DEFAULT, NONE },
    00143    { "ntdebugflags", MISDN_GEN_NTDEBUGFLAGS, MISDN_CTYPE_INT, "0", NONE },
    00144    { "ntdebugfile", MISDN_GEN_NTDEBUGFILE, MISDN_CTYPE_STR, "/var/log/misdn-nt.log", NONE }
    00145 };
    00146
    00147 /* array of port configs, default is at position 0. */
    00148 static union misdn_cfg_pt **port_cfg;
    00149 /* max number of available ports, is set on init */
    00150 static int max_ports;
    00151 /* general config */
    00152 static union misdn_cfg_pt *general_cfg;
    00153 /* storing the ptp flag separated to save memory */
    00154 static int *ptp;
    00155 /* maps enum config elements to array positions */
    00156 static int *map;
    00157
    00158 static ast_mutex_t config_mutex;
    00159
    00160 #define CLI_ERROR(name, value, section) ({ \
    00161    ast_log(LOG_WARNING, "misdn.conf: \"%s=%s\" (section: %s) invalid or out of range. " \
    00162       "Please edit your misdn.conf and then do a \"misdn reload\".\n", name, value, section); \
    00163 })
    00164
    00165 static void _enum_array_map (void)
    00166 {
    00167    int i, j;
    00168
    00169    for (i = MISDN_CFG_FIRST + 1; i < MISDN_CFG_LAST; ++i) {
    00170       if (i == MISDN_CFG_PTP)
    00171          continue;
    00172       for (j = 0; j < NUM_PORT_ELEMENTS; ++j) {
    00173          if (port_spec[j].elem == i) {
    00174             map[i] = j;
    00175             break;
    00176          }
    00177       }
    00178    }
    00179    for (i = MISDN_GEN_FIRST + 1; i < MISDN_GEN_LAST; ++i) {
    00180       for (j = 0; j < NUM_GEN_ELEMENTS; ++j) {
    00181          if (gen_spec[j].elem == i) {
    00182             map[i] = j;
    00183             break;
    00184          }
    00185       }
    00186    }
    00187 }
    00188
    00189 static int get_cfg_position (char *name, int type)
    00190 {
    00191    int i;
    00192
    00193    switch (type) {
    00194    case PORT_CFG:
    00195       for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
    00196          if (!strcasecmp(name, port_spec[i].name))
    00197             return i;
    00198       }
    00199       break;
    00200    case GEN_CFG:
    00201       for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
    00202          if (!strcasecmp(name, gen_spec[i].name))
    00203             return i;
    00204       }
    00205    }
    00206
    00207    return -1;
    00208 }
    00209
    00210 static inline void misdn_cfg_lock (void)
    00211 {
    00212    ast_mutex_lock(&config_mutex);
    00213 }
    00214
    00215 static inline void misdn_cfg_unlock (void)
    00216 {
    00217    ast_mutex_unlock(&config_mutex);
    00218 }
    00219
    00220 static void _free_msn_list (struct msn_list* iter)
    00221 {
    00222    if (iter->next)
    00223       _free_msn_list(iter->next);
    00224    if (iter->msn)
    00225       free(iter->msn);
    00226    free(iter);
    00227 }
    00228
    00229 static void _free_port_cfg (void)
    00230 {
    00231    int i, j;
    00232    int gn = map[MISDN_CFG_GROUPNAME];
    00233    union misdn_cfg_pt* free_list[max_ports + 2];
    00234
    00235    memset(free_list, 0, sizeof(free_list));
    00236    free_list[0] = port_cfg[0];
    00237    for (i = 1; i <= max_ports; ++i) {
    00238       if (port_cfg[i][gn].str) {
    00239          /* we always have a groupname in the non-default case, so this is fine */
    00240          for (j = 1; j <= max_ports; ++j) {
    00241             if (free_list[j] && free_list[j][gn].str == port_cfg[i][gn].str)
    00242                break;
    00243             else if (!free_list[j]) {
    00244                free_list[j] = port_cfg[i];
    00245                break;
    00246             }
    00247          }
    00248       }
    00249    }
    00250    for (j = 0; free_list[j]; ++j) {
    00251       for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
    00252          if (free_list[j][i].any) {
    00253             if (port_spec[i].type == MISDN_CTYPE_MSNLIST)
    00254                _free_msn_list(free_list[j][i].ml);
    00255             else
    00256                free(free_list[j][i].any);
    00257          }
    00258       }
    00259    }
    00260 }
    00261
    00262 static void _free_general_cfg (void)
    00263 {
    00264    int i;
    00265
    00266    for (i = 0; i < NUM_GEN_ELEMENTS; i++)
    00267       if (general_cfg[i].any)
    00268          free(general_cfg[i].any);
    00269 }
    00270
    00271 void misdn_cfg_get (int port, enum misdn_cfg_elements elem, void *buf, int bufsize)
    00272 {
    00273    int place;
    00274
    00275    if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
    00276       memset(buf, 0, bufsize);
    00277       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Port number %d is not valid.\n", port);
    00278       return;
    00279    }
    00280
    00281    misdn_cfg_lock();
    00282    if (elem == MISDN_CFG_PTP) {
    00283       if (!memcpy(buf, &ptp[port], (bufsize > ptp[port]) ? sizeof(ptp[port]) : bufsize))
    00284          memset(buf, 0, bufsize);
    00285    } else {
    00286       if ((place = map[elem]) < 0) {
    00287          memset (buf, 0, bufsize);
    00288          ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Invalid element (%d) requested.\n", elem);
    00289       } else {
    00290          if (elem < MISDN_CFG_LAST) {
    00291             switch (port_spec[place].type) {
    00292             case MISDN_CTYPE_STR:
    00293                if (port_cfg[port][place].str) {
    00294                   if (!memccpy(buf, port_cfg[port][place].str, 0, bufsize))
    00295                      memset(buf, 0, 1);
    00296                } else if (port_cfg[0][place].str) {
    00297                   if (!memccpy(buf, port_cfg[0][place].str, 0, bufsize))
    00298                      memset(buf, 0, 1);
    00299                }
    00300                break;
    00301             default:
    00302                if (port_cfg[port][place].any)
    00303                   memcpy(buf, port_cfg[port][place].any, bufsize);
    00304                else if (port_cfg[0][place].any)
    00305                   memcpy(buf, port_cfg[0][place].any, bufsize);
    00306                else
    00307                   memset(buf, 0, bufsize);
    00308             }
    00309          } else {
    00310             switch (gen_spec[place].type) {
    00311             case MISDN_CTYPE_STR:
    00312                if (!general_cfg[place].str || !memccpy(buf, general_cfg[place].str, 0, bufsize))
    00313                   memset(buf, 0, 1);
    00314                break;
    00315             default:
    00316                if (general_cfg[place].any)
    00317                   memcpy(buf, general_cfg[place].any, bufsize);
    00318                else
    00319                   memset(buf, 0, bufsize);
    00320             }
    00321          }
    00322       }
    00323    }
    00324    misdn_cfg_unlock();
    00325 }
    00326
    00327 int misdn_cfg_is_msn_valid (int port, char* msn)
    00328 {
    00329    int re = 0;
    00330    struct msn_list *iter;
    00331
    00332    if (!misdn_cfg_is_port_valid(port)) {
    00333       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_is_msn_valid! Port number %d is not valid.\n", port);
    00334       return 0;
    00335    }
    00336
    00337    misdn_cfg_lock();
    00338    if (port_cfg[port][map[MISDN_CFG_MSNS]].ml)
    00339       iter = port_cfg[port][map[MISDN_CFG_MSNS]].ml;
    00340    else
    00341       iter = port_cfg[0][map[MISDN_CFG_MSNS]].ml;
    00342    for (; iter; iter = iter->next)
    00343       if (*(iter->msn) == '*' || ast_extension_match(iter->msn, msn)) {
    00344          re = 1;
    00345          break;
    00346       }
    00347    misdn_cfg_unlock();
    00348
    00349    return re;
    00350 }
    00351
    00352 int misdn_cfg_is_port_valid (int port)
    00353 {
    00354    return (port >= 1 && port <= max_ports);
    00355 }
    00356
    00357 int misdn_cfg_is_group_method (char *group, enum misdn_cfg_method meth)
    00358 {
    00359    int i, re = 0;
    00360    char *method ;
    00361
    00362    misdn_cfg_lock();
    00363
    00364    method = port_cfg[0][map[MISDN_CFG_METHOD]].str;
    00365
    00366    for (i = 1; i <= max_ports; i++) {
    00367       if (port_cfg[i] && port_cfg[i][map[MISDN_CFG_GROUPNAME]].str) {
    00368          if (!strcasecmp(port_cfg[i][map[MISDN_CFG_GROUPNAME]].str, group))
    00369             method = (port_cfg[i][map[MISDN_CFG_METHOD]].str ?
    00370                     port_cfg[i][map[MISDN_CFG_METHOD]].str : port_cfg[0][map[MISDN_CFG_METHOD]].str);
    00371       }
    00372    }
    00373
    00374    if (method) {
    00375       switch (meth) {
    00376       case METHOD_STANDARD:      re = !strcasecmp(method, "standard");
    00377                            break;
    00378       case METHOD_ROUND_ROBIN:   re = !strcasecmp(method, "round_robin");
    00379                            break;
    00380       case METHOD_STANDARD_DEC:  re = !strcasecmp(method, "standard_dec");
    00381                            break;
    00382       }
    00383    }
    00384    misdn_cfg_unlock();
    00385
    00386    return re;
    00387 }
    00388
    00389 void misdn_cfg_get_ports_string (char *ports)
    00390 {
    00391    char tmp[16];
    00392    int l, i;
    00393    int gn = map[MISDN_CFG_GROUPNAME];
    00394
    00395    *ports = 0;
    00396
    00397    misdn_cfg_lock();
    00398    for (i = 1; i <= max_ports; i++) {
    00399       if (port_cfg[i][gn].str) {
    00400          if (ptp[i])
    00401             sprintf(tmp, "%dptp,", i);
    00402          else
    00403             sprintf(tmp, "%d,", i);
    00404          strcat(ports, tmp);
    00405       }
    00406    }
    00407    misdn_cfg_unlock();
    00408
    00409    if ((l = strlen(ports)))
    00410       ports[l-1] = 0;
    00411 }
    00412
    00413 void misdn_cfg_get_config_string (int port, enum misdn_cfg_elements elem, char* buf, int bufsize)
    00414 {
    00415    int place;
    00416    char tempbuf[BUFFERSIZE] = "";
    00417    struct msn_list *iter;
    00418
    00419    if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
    00420       *buf = 0;
    00421       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Port number %d is not valid.\n", port);
    00422       return;
    00423    }
    00424
    00425    place = map[elem];
    00426
    00427    misdn_cfg_lock();
    00428    if (elem == MISDN_CFG_PTP) {
    00429       snprintf(buf, bufsize, " -> ptp: %s", ptp[port] ? "yes" : "no");
    00430    }
    00431    else if (elem > MISDN_CFG_FIRST && elem < MISDN_CFG_LAST) {
    00432       switch (port_spec[place].type) {
    00433       case MISDN_CTYPE_INT:
    00434       case MISDN_CTYPE_BOOLINT:
    00435          if (port_cfg[port][place].num)
    00436             snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[port][place].num);
    00437          else if (port_cfg[0][place].num)
    00438             snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[0][place].num);
    00439          else
    00440             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
    00441          break;
    00442       case MISDN_CTYPE_BOOL:
    00443          if (port_cfg[port][place].num)
    00444             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[port][place].num ? "yes" : "no");
    00445          else if (port_cfg[0][place].num)
    00446             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[0][place].num ? "yes" : "no");
    00447          else
    00448             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
    00449          break;
    00450       case MISDN_CTYPE_ASTGROUP:
    00451          if (port_cfg[port][place].grp)
    00452             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
    00453                    ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[port][place].grp));
    00454          else if (port_cfg[0][place].grp)
    00455             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
    00456                    ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[0][place].grp));
    00457          else
    00458             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
    00459          break;
    00460       case MISDN_CTYPE_MSNLIST:
    00461          if (port_cfg[port][place].ml)
    00462             iter = port_cfg[port][place].ml;
    00463          else
    00464             iter = port_cfg[0][place].ml;
    00465          if (iter) {
    00466             for (; iter; iter = iter->next)
    00467                sprintf(tempbuf, "%s%s, ", tempbuf, iter->msn);
    00468             tempbuf[strlen(tempbuf)-2] = 0;
    00469          }
    00470          snprintf(buf, bufsize, " -> msns: %s", *tempbuf ? tempbuf : "none");
    00471          break;
    00472       case MISDN_CTYPE_STR:
    00473          if ( port_cfg[port][place].str) {
    00474             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[port][place].str);
    00475          } else if (port_cfg[0][place].str) {
    00476             snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[0][place].str);
    00477          } else {
    00478             snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
    00479          }
    00480          break;
    00481       }
    00482    } else if (elem > MISDN_GEN_FIRST && elem < MISDN_GEN_LAST) {
    00483       switch (gen_spec[place].type) {
    00484       case MISDN_CTYPE_INT:
    00485       case MISDN_CTYPE_BOOLINT:
    00486          if (general_cfg[place].num)
    00487             snprintf(buf, bufsize, " -> %s: %d", gen_spec[place].name, *general_cfg[place].num);
    00488          else
    00489             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
    00490          break;
    00491       case MISDN_CTYPE_BOOL:
    00492          if (general_cfg[place].num)
    00493             snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, *general_cfg[place].num ? "yes" : "no");
    00494          else
    00495             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
    00496          break;
    00497       case MISDN_CTYPE_STR:
    00498          if ( general_cfg[place].str) {
    00499             snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, general_cfg[place].str);
    00500          } else {
    00501             snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
    00502          }
    00503          break;
    00504       default:
    00505          snprintf(buf, bufsize, " -> type of %s not handled yet", gen_spec[place].name);
    00506          break;
    00507       }
    00508    } else {
    00509       *buf = 0;
    00510       ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Invalid config element (%d) requested.\n", elem);
    00511    }
    00512    misdn_cfg_unlock();
    00513 }
    00514
    00515 int misdn_cfg_get_next_port (int port)
    00516 {
    00517    int p = -1;
    00518    int gn = map[MISDN_CFG_GROUPNAME];
    00519
    00520    misdn_cfg_lock();
    00521    for (port++; port <= max_ports; port++) {
    00522       if (port_cfg[port][gn].str) {
    00523          p = port;
    00524          break;
    00525       }
    00526    }
    00527    misdn_cfg_unlock();
    00528
    00529    return p;
    00530 }
    00531
    00532 int misdn_cfg_get_next_port_spin (int port)
    00533 {
    00534    int p = misdn_cfg_get_next_port(port);
    00535    return (p > 0) ? p : misdn_cfg_get_next_port(0);
    00536 }
    00537
    00538 static int _parse (union misdn_cfg_pt *dest, char *value, enum misdn_cfg_type type, int boolint_def)
    00539 {
    00540    int re = 0;
    00541    int len, tmp;
    00542    char *valtmp;
    00543
    00544    switch (type) {
    00545    case MISDN_CTYPE_STR:
    00546       if ((len = strlen(value))) {
    00547          dest->str = (char *)malloc((len + 1) * sizeof(char));
    00548          strncpy(dest->str, value, len);
    00549          dest->str[len] = 0;
    00550       } else {
    00551          dest->str = (char *)malloc( sizeof(char));
    00552          dest->str[0] = 0;
    00553       }
    00554       break;
    00555    case MISDN_CTYPE_INT:
    00556    {
    00557       char *pat;
    00558       if (strchr(value,'x'))
    00559          pat="%30x";
    00560       else
    00561          pat="%30d";
    00562       if (sscanf(value, pat, &tmp)) {
    00563          dest->num = (int *)malloc(sizeof(int));
    00564          memcpy(dest->num, &tmp, sizeof(int));
    00565       } else
    00566          re = -1;
    00567    }
    00568       break;
    00569    case MISDN_CTYPE_BOOL:
    00570       dest->num = (int *)malloc(sizeof(int));
    00571       *(dest->num) = (ast_true(value) ? 1 : 0);
    00572       break;
    00573    case MISDN_CTYPE_BOOLINT:
    00574       dest->num = (int *)malloc(sizeof(int));
    00575       if (sscanf(value, "%30d", &tmp)) {
    00576          memcpy(dest->num, &tmp, sizeof(int));
    00577       } else {
    00578          *(dest->num) = (ast_true(value) ? boolint_def : 0);
    00579       }
    00580       break;
    00581    case MISDN_CTYPE_MSNLIST:
    00582       for (valtmp = strsep(&value, ","); valtmp; valtmp = strsep(&value, ",")) {
    00583          if ((len = strlen(valtmp))) {
    00584             struct msn_list *ml = (struct msn_list *)malloc(sizeof(struct msn_list));
    00585             ml->msn = (char *)calloc(len+1, sizeof(char));
    00586             strncpy(ml->msn, valtmp, len);
    00587             ml->next = dest->ml;
    00588             dest->ml = ml;
    00589          }
    00590       }
    00591       break;
    00592    case MISDN_CTYPE_ASTGROUP:
    00593       dest->grp = (ast_group_t *)malloc(sizeof(ast_group_t));
    00594       *(dest->grp) = ast_get_group(value);
    00595       break;
    00596    }
    00597
    00598    return re;
    00599 }
    00600
    00601 static void _build_general_config (struct ast_variable *v)
    00602 {
    00603    int pos;
    00604
    00605    for (; v; v = v->next) {
    00606       if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) ||
    00607          (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0))
    00608          CLI_ERROR(v->name, v->value, "general");
    00609    }
    00610 }
    00611
    00612 static void _build_port_config (struct ast_variable *v, char *cat)
    00613 {
    00614    int pos, i;
    00615    union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS];
    00616    int cfg_for_ports[max_ports + 1];
    00617
    00618    if (!v || !cat)
    00619       return;
    00620
    00621    memset(cfg_tmp, 0, sizeof(cfg_tmp));
    00622    memset(cfg_for_ports, 0, sizeof(cfg_for_ports));
    00623
    00624    if (!strcasecmp(cat, "default")) {
    00625       cfg_for_ports[0] = 1;
    00626    }
    00627
    00628    if (((pos = get_cfg_position("name", PORT_CFG)) < 0) ||
    00629       (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
    00630       CLI_ERROR(v->name, v->value, cat);
    00631       return;
    00632    }
    00633
    00634    for (; v; v = v->next) {
    00635       if (!strcasecmp(v->name, "ports")) {
    00636          char *token;
    00637          char ptpbuf[BUFFERSIZE] = "";
    00638          int start, end;
    00639          for (token = strsep(&v->value, ","); token; token = strsep(&v->value, ","), *ptpbuf = 0) {
    00640             if (!*token)
    00641                continue;
    00642             if (sscanf(token, "%30d-%30d%511s", &start, &end, ptpbuf) >= 2) {
    00643                for (; start <= end; start++) {
    00644                   if (start <= max_ports && start > 0) {
    00645                      cfg_for_ports[start] = 1;
    00646                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
    00647                   } else
    00648                      CLI_ERROR(v->name, v->value, cat);
    00649                }
    00650             } else {
    00651                if (sscanf(token, "%30d%511s", &start, ptpbuf)) {
    00652                   if (start <= max_ports && start > 0) {
    00653                      cfg_for_ports[start] = 1;
    00654                      ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
    00655                   } else
    00656                      CLI_ERROR(v->name, v->value, cat);
    00657                } else
    00658                   CLI_ERROR(v->name, v->value, cat);
    00659             }
    00660          }
    00661       } else {
    00662          if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) ||
    00663             (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
    00664             CLI_ERROR(v->name, v->value, cat);
    00665       }
    00666    }
    00667
    00668    for (i = 0; i < (max_ports + 1); ++i) {
    00669       if (cfg_for_ports[i]) {
    00670          memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp));
    00671       }
    00672    }
    00673 }
    00674
    00675 void misdn_cfg_update_ptp (void)
    00676 {
    00677 #ifndef MISDN_1_2
    00678    char misdn_init[BUFFERSIZE];
    00679    char line[BUFFERSIZE];
    00680    FILE *fp;
    00681    char *tok, *p, *end;
    00682    int port;
    00683
    00684    misdn_cfg_get(0, MISDN_GEN_MISDN_INIT, &misdn_init, sizeof(misdn_init));
    00685
    00686    if (misdn_init) {
    00687       fp = fopen(misdn_init, "r");
    00688       if (fp) {
    00689          while(fgets(line, sizeof(line), fp)) {
    00690             if (!strncmp(line, "nt_ptp", 6)) {
    00691                for (tok = strtok_r(line,",=", &p);
    00692                    tok;
    00693                    tok = strtok_r(NULL,",=", &p)) {
    00694                   port = strtol(tok, &end, 10);
    00695                   if (end != tok && misdn_cfg_is_port_valid(port)) {
    00696                      misdn_cfg_lock();
    00697                      ptp[port] = 1;
    00698                      misdn_cfg_unlock();
    00699                   }
    00700                }
    00701             }
    00702          }
    00703          fclose(fp);
    00704       } else {
    00705          ast_log(LOG_WARNING,"Couldn't open %s: %s\n", misdn_init, strerror(errno));
    00706       }
    00707    }
    00708 #else
    00709    int i;
    00710    int proto;
    00711    char filename[128];
    00712    FILE *fp;
    00713
    00714    for (i = 1; i <= max_ports; ++i) {
    00715       snprintf(filename, sizeof(filename), "/sys/class/mISDN-stacks/st-%08x/protocol", i << 8);
    00716       fp = fopen(filename, "r");
    00717       if (!fp) {
    00718          ast_log(LOG_WARNING, "Could not open %s: %s\n", filename, strerror(errno));
    00719          continue;
    00720       }
    00721       if (fscanf(fp, "0x%08x", &proto) != 1)
    00722          ast_log(LOG_WARNING, "Could not parse contents of %s!\n", filename);
    00723       else
    00724          ptp[i] = proto & 1<<5 ? 1 : 0;
    00725       fclose(fp);
    00726    }
    00727 #endif
    00728 }
    00729
    00730 static void _fill_defaults (void)
    00731 {
    00732    int i;
    00733
    00734    for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
    00735       if (!port_cfg[0][i].any && strcasecmp(port_spec[i].def, NO_DEFAULT))
    00736          _parse(&(port_cfg[0][i]), (char *)port_spec[i].def, port_spec[i].type, port_spec[i].boolint_def);
    00737    }
    00738    for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
    00739       if (!general_cfg[i].any && strcasecmp(gen_spec[i].def, NO_DEFAULT))
    00740          _parse(&(general_cfg[i]), (char *)gen_spec[i].def, gen_spec[i].type, gen_spec[i].boolint_def);
    00741    }
    00742 }
    00743
    00744 void misdn_cfg_reload (void)
    00745 {
    00746    misdn_cfg_init (0);
    00747 }
    00748
    00749 void misdn_cfg_destroy (void)
    00750 {
    00751    misdn_cfg_lock();
    00752
    00753    _free_port_cfg();
    00754    _free_general_cfg();
    00755
    00756    free(port_cfg);
    00757    free(general_cfg);
    00758    free(ptp);
    00759    free(map);
    00760
    00761    misdn_cfg_unlock();
    00762    ast_mutex_destroy(&config_mutex);
    00763 }
    00764
    00765 int misdn_cfg_init (int this_max_ports)
    00766 {
    00767    char config[] = "misdn.conf";
    00768    char *cat, *p;
    00769    int i;
    00770    struct ast_config *cfg;
    00771    struct ast_variable *v;
    00772
    00773    if (!(cfg = AST_LOAD_CFG(config))) {
    00774       ast_log(LOG_WARNING,"no misdn.conf ?\n");
    00775       return -1;
    00776    }
    00777
    00778    misdn_cfg_lock();
    00779
    00780    if (this_max_ports) {
    00781       /* this is the first run */
    00782       max_ports = this_max_ports;
    00783       p = (char *)calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
    00784                      + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
    00785       port_cfg = (union misdn_cfg_pt **)p;
    00786       p += (max_ports + 1) * sizeof(union misdn_cfg_pt *);
    00787       for (i = 0; i <= max_ports; ++i) {
    00788          port_cfg[i] = (union misdn_cfg_pt *)p;
    00789          p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt);
    00790       }
    00791       general_cfg = (union misdn_cfg_pt *)calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
    00792       ptp = (int *)calloc(max_ports + 1, sizeof(int));
    00793       map = (int *)calloc(MISDN_GEN_LAST + 1, sizeof(int));
    00794       _enum_array_map();
    00795    }
    00796    else {
    00797       /* misdn reload */
    00798       _free_port_cfg();
    00799       _free_general_cfg();
    00800       memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1));
    00801       memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
    00802       memset(ptp, 0, sizeof(int) * (max_ports + 1));
    00803    }
    00804
    00805    cat = ast_category_browse(cfg, NULL);
    00806
    00807    while(cat) {
    00808       v = ast_variable_browse(cfg, cat);
    00809       if (!strcasecmp(cat,"general")) {
    00810          _build_general_config(v);
    00811       } else {
    00812          _build_port_config(v, cat);
    00813       }
    00814       cat = ast_category_browse(cfg,cat);
    00815    }
    00816
    00817    _fill_defaults();
    00818
    00819    misdn_cfg_unlock();
    00820    AST_DESTROY_CFG(cfg);
    00821
    00822    return 0;
    00823 }