]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
automerge commit
authorAutomerge Script <automerge@asterisk.org>
Mon, 22 Jan 2007 17:22:37 +0000 (17:22 +0000)
committerAutomerge Script <automerge@asterisk.org>
Mon, 22 Jan 2007 17:22:37 +0000 (17:22 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.2-netsec@51403 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_voicemail.c
asterisk.c
channels/chan_h323.c
channels/chan_sip.c
channels/chan_zap.c
contrib/scripts/vmdb.sql
doc/voicemail_odbc_postgresql.txt [new file with mode: 0644]
res/res_features.c
stdtime/localtime.c
utils.c

index 4c49a2488ccb8517928f9757bce18a6949c71280..47896a0d618965af6170c137307cab4c93043a02 100644 (file)
@@ -932,7 +932,7 @@ static int retrieve_file(char *dir, int msgnum)
                        }
                        if (!strcasecmp(coltitle, "recording")) {
                                off_t offset;
-                               res = SQLGetData(stmt, x + 1, SQL_BINARY, NULL, 0, &colsize);
+                               res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize);
                                fdlen = colsize;
                                if (fd > -1) {
                                        char tmp[1]="";
@@ -944,14 +944,13 @@ static int retrieve_file(char *dir, int msgnum)
                                        }
                                        /* Read out in small chunks */
                                        for (offset = 0; offset < colsize; offset += CHUNKSIZE) {
-                                               /* +1 because SQLGetData likes null-terminating binary data */
-                                               if ((fdm = mmap(NULL, CHUNKSIZE + 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == -1) {
+                                               if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == (void *)-1) {
                                                        ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
                                                        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
                                                        goto yuck;
                                                } else {
-                                                       res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE + 1, NULL);
-                                                       munmap(fdm, 0);
+                                                       res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
+                                                       munmap(fdm, CHUNKSIZE);
                                                        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                                                                ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
                                                                unlink(full_fn);
index bc15eb5c7d569c1403b24fcd54538f8e070b48b3..d3b3989dea5278c8160751ade17d71c16c1452e2 100644 (file)
@@ -1656,7 +1656,9 @@ static char *cli_complete(EditLine *el, int ch)
                                retval = CC_REFRESH;
                        }
                }
-       free(matches);
+               for (i=0; matches[i]; i++)
+                       free(matches[i]);
+               free(matches);
        }
 
        return (char *)(long)retval;
index b86d684c87facfa372408661c9e162d72efe208f..1b4a616a5fae89f8f4a9115c551b43d85e897458 100644 (file)
@@ -2021,7 +2021,7 @@ int reload_config(void)
        memset(&global_options, 0, sizeof(global_options));
        global_options.dtmfcodec = 101;
        global_options.dtmfmode = H323_DTMF_RFC2833;
-       global_options.capability = ~0; /* All capabilities */
+       global_options.capability = AST_FORMAT_G723_1 | AST_FORMAT_GSM | AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_G729A | AST_FORMAT_H261;
        global_options.bridge = 1;              /* Do native bridging by default */
        v = ast_variable_browse(cfg, "general");
        while(v) {
index b088cba64859fa0ff3feba5e624422647ea9ccde..e54178fbef096f97bd9beb292e9118c42b9aecb5 100644 (file)
@@ -2820,11 +2820,11 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
        ast_mutex_unlock(&i->lock);
        /* Don't hold a sip pvt lock while we allocate a channel */
        tmp = ast_channel_alloc(1);
-       ast_mutex_lock(&i->lock);
        if (!tmp) {
                ast_log(LOG_WARNING, "Unable to allocate SIP channel structure\n");
                return NULL;
        }
+       ast_mutex_lock(&i->lock);
        tmp->tech = &sip_tech;
        /* Select our native format based on codec preference until we receive
           something from another device to the contrary. */
index 73cc62741c6663d6b9e06d77136a390e634104e5..e8a88579156c9ec87d9dbba8fd499f72d2dd163a 100644 (file)
@@ -195,112 +195,17 @@ static const char config[] = "zapata.conf";
 
 #define DCHAN_AVAILABLE        (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
 
-static char context[AST_MAX_CONTEXT] = "default";
-static char cid_num[256] = "";
-static char cid_name[256] = "";
 static char defaultcic[64] = "";
 static char defaultozz[64] = "";
 
 static char language[MAX_LANGUAGE] = "";
-static char musicclass[MAX_MUSICCLASS] = "";
 static char progzone[10]= "";
 
 static int usedistinctiveringdetection = 0;
 
-static int transfertobusy = 1;
-
-static int use_callerid = 1;
-static int cid_signalling = CID_SIG_BELL;
-static int cid_start = CID_START_RING;
-static int zaptrcallerid = 0;
-static int cur_signalling = -1;
-
-static ast_group_t cur_group = 0;
-static ast_group_t cur_callergroup = 0;
-static ast_group_t cur_pickupgroup = 0;
-static int relaxdtmf = 0;
-
-static int immediate = 0;
-
-static int stripmsd = 0;
-
-static int callwaiting = 0;
-
-static int callwaitingcallerid = 0;
-
-static int hidecallerid = 0;
-
-static int restrictcid = 0;
-
-static int use_callingpres = 0;
-
-static int callreturn = 0;
-
-static int threewaycalling = 0;
-
-static int transfer = 0;
-
-static int canpark = 0;
-
-static int cancallforward = 0;
-
-static float rxgain = 0.0;
-
-static float txgain = 0.0;
-
-static int tonezone = -1;
-
-static int echocancel;
-
-static int echotraining;
-
-static int pulse;
-
-static int echocanbridged = 0;
-
-static int busydetect = 0;
-
-static int busycount = 3;
-static int busy_tonelength = 0;
-static int busy_quietlength = 0;
-
-static int callprogress = 0;
-
-static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
-
-static char mailbox[AST_MAX_EXTENSION];
-
-static int amaflags = 0;
-
-static int adsi = 0;
-
 static int numbufs = 4;
 
-static int cur_prewink = -1;
-static int cur_preflash = -1;
-static int cur_wink = -1;
-static int cur_flash = -1;
-static int cur_start = -1;
-static int cur_rxwink = -1;
-static int cur_rxflash = -1;
-static int cur_debounce = -1;
-static int cur_priexclusive = 0;
-
-static int priindication_oob = 0;
-
 #ifdef ZAPATA_PRI
-static int minunused = 2;
-static int minidle = 0;
-static char idleext[AST_MAX_EXTENSION];
-static char idledial[AST_MAX_EXTENSION];
-static int overlapdial = 0;
-static int facilityenable = 0;
-static char internationalprefix[10] = "";
-static char nationalprefix[10] = "";
-static char localprefix[20] = "";
-static char privateprefix[20] = "";
-static char unknownprefix[20] = "";
-static long resetinterval = 3600;      /*!< How often (in seconds) to reset unused channels. Default 1 hour. */
 static struct ast_channel inuse = { "GR-303InUse" };
 #ifdef PRI_GETSET_TIMERS
 static int pritimers[PRI_MAX_TIMERS];
@@ -331,18 +236,6 @@ static int ifcount = 0;
 AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
 #endif
 
-/*! \brief Whether we answer on a Polarity Switch event */
-static int answeronpolarityswitch = 0;
-
-/*! \brief Whether we hang up on a Polarity Switch event */
-static int hanguponpolarityswitch = 0;
-
-/*! \brief How long (ms) to ignore Polarity Switch events after we answer a call */
-static int polarityonanswerdelay = 600;
-
-/*! \brief When to send the CallerID signals (rings) */
-static int sendcalleridafter = DEFAULT_CIDRINGS;
-
 /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
    when it's doing something critical. */
 AST_MUTEX_DEFINE_STATIC(monlock);
@@ -520,6 +413,264 @@ struct zt_subchannel {
 
 #define MAX_SLAVES     4
 
+/*! \brief The PRI part of the channel configuration.
+ * Separated as it is is applied to the span rather than to the channel.
+ */
+struct zt_pri_conf {
+#ifdef ZAPATA_PRI
+       int minunused;
+       int minidle;
+       char idleext[AST_MAX_EXTENSION];
+       char idledial[AST_MAX_EXTENSION];
+       int overlapdial;
+       int facilityenable;
+       char internationalprefix[10];
+       char nationalprefix[10];
+       char localprefix[20];
+       char privateprefix[20];
+       char unknownprefix[20];
+       long resetinterval;
+#endif
+};
+
+/*! \brief Channel configuration from zapata.conf .
+ * This struct is used for parsing the [channels] section of zapata.conf.
+ * Generally there is a field here for every possible configuration item.
+ *
+ * The state of fields is saved along the parsing and whenever a 'channel'
+ * statement is reached, the current zt_chan_conf is used to configure the 
+ * channel (struct zt_pvt)
+ *
+ * @seealso zt_chan_init for the default values.
+ */
+struct zt_chan_conf {
+       struct zt_pri_conf pri;
+       char context[AST_MAX_CONTEXT];
+       char cid_num[AST_MAX_EXTENSION];
+       char cid_name[AST_MAX_EXTENSION];
+       char musicclass[MAX_MUSICCLASS];
+       int transfertobusy;
+
+       int cid_signalling;
+       int cid_start;
+       int zaptrcallerid;
+       int use_callerid;
+       int signalling;
+       int outsignalling;
+       ast_group_t group;
+       ast_group_t callergroup;
+       ast_group_t pickupgroup;
+
+       int relaxdtmf;
+
+       int immediate; 
+
+       int stripmsd;
+
+       int callwaiting;
+
+       int callwaitingcallerid;
+
+       int hidecallerid;
+
+       int restrictcid;
+
+       int use_callingpres;
+
+       int callreturn;
+
+       int threewaycalling;
+
+       int transfer;
+
+       int canpark;
+
+       int cancallforward;
+
+       float rxgain;
+
+       float txgain;
+
+       int tonezone;
+
+       int echocancel;
+
+       int echotraining;
+
+       int pulse;
+
+       int echocanbridged;
+
+       int busydetect;
+
+       int busycount;
+       int busy_tonelength;
+       int busy_quietlength;
+
+       int callprogress;
+
+       char accountcode[AST_MAX_ACCOUNT_CODE];
+
+       char mailbox[AST_MAX_EXTENSION];
+
+       int amaflags;
+
+       int adsi;
+
+       int numbufs;
+
+       int prewink;
+       int preflash;
+       int wink;
+       int flash;
+       int start;
+       int rxwink;
+       int rxflash;
+       int debounce;
+       int priexclusive;
+
+       int answeronpolarityswitch;
+       int hanguponpolarityswitch;
+       int polarityonanswerdelay;
+       int sendcalleridafter;
+
+       int priindication_oob;
+       int radio;
+};
+
+/** returns a new zt_chan_conf with default values (by-value) */
+struct zt_chan_conf zt_chan_conf_default(void) {
+       struct zt_chan_conf chan_conf = {
+               .pri = {
+#ifdef ZAPATA_PRI
+                       .minunused = 2,
+                       .minidle = 0,
+                       .idleext = "",
+                       .idledial = "",
+                       .overlapdial = 0,
+                       .facilityenable = 0,
+                       .internationalprefix = "",
+                       .nationalprefix = "",
+                       .localprefix = "",
+                       .privateprefix = "",
+                       .unknownprefix = "",
+                       /*!< How often (in seconds) to reset unused channels. Default 1 hour. */
+                       .resetinterval = 3600,  
+#endif
+               },
+               .context = "default",
+               .cid_num = "",
+               .cid_name = "",
+               .musicclass = "",
+               .transfertobusy = 1,
+
+               .cid_signalling = CID_SIG_BELL,
+               .cid_start = CID_START_RING,
+               .zaptrcallerid = 0,
+               .use_callerid = 1,
+               .signalling = -1,
+               .group = 0,
+               .callergroup = 0,
+               .pickupgroup = 0,
+
+               .relaxdtmf = 0,
+               .immediate = 0,
+
+               .stripmsd = 0,
+
+               .callwaiting = 0,
+
+               .callwaitingcallerid = 0,
+
+               .hidecallerid = 0,
+
+               .restrictcid = 0,
+
+               .use_callingpres = 0,
+
+               .callreturn = 0,
+
+               .threewaycalling = 0,
+
+               .transfer = 0,
+
+               .canpark = 0,
+
+               .cancallforward = 0,
+
+               .rxgain = 0.0,
+
+               .txgain = 0.0,
+
+               .tonezone = -1,
+
+               /*! \brief Boolean: true to use echo cancelling. Default: True. */
+               .echocancel = 1,
+
+               /*! \brief Integer: Echo training time. True implies 400. */
+               .echotraining = 0,
+
+               /*! \brief Boolean: Use pulse dialing. Default: false. Right? */
+               .pulse = 0,
+               
+               /*! \brief Boolean: true to use echo cancelling even between zaptel 
+                * channels. Default: false. */
+               .echocanbridged = 0,
+
+               /*! \brief Boolean: hangup calls by detecting a busy tone. 
+                * Default: false. */
+               .busydetect = 0,
+
+               .busycount = 3,
+               .busy_tonelength = 0,
+               .busy_quietlength = 0,
+
+               .callprogress = 0,
+
+               .accountcode = "",
+
+               /*! \brief String. Voicemail box in which to check mail for 
+                * the channel (mailbox[@context]). Default: none. */
+               .mailbox = "",
+               .amaflags = 0,
+
+               .adsi = 0,
+               .numbufs = 4,
+
+               .prewink = -1,
+               .preflash = -1,
+               .wink = -1,
+               .flash = -1,
+               .start = -1,
+               .rxwink = -1,
+               .rxflash = -1,
+               .debounce = -1,
+               .priexclusive = 0,
+
+               /*! \brief Whether we answer on a Polarity Switch event */
+               .answeronpolarityswitch = 0,
+
+               /*! \brief Whether we hang up on a Polarity Switch event */
+               .hanguponpolarityswitch = 0,
+
+               /*! \brief How long (ms) to ignore Polarity Switch events after we answer a call */
+               .polarityonanswerdelay = 600,
+
+               /*! \brief When to send the CallerID signals (rings) */
+               .sendcalleridafter = DEFAULT_CIDRINGS,
+
+               .priindication_oob = 0,
+
+               /* Add fields above this comment. "radio" will be 
+                * kept as the one without the comma. for the moment, 
+                * until we add all fields.
+                */
+               .radio = 0
+       };
+
+       return chan_conf;
+}
+
 static struct zt_pvt {
        ast_mutex_t lock;
        struct ast_channel *owner;                      /*!< Our current active owner (if applicable) */
@@ -6808,7 +6959,7 @@ static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
 
 #endif
 
-static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_pri *pri, int reloading)
+static struct zt_pvt *mkintf(int channel, struct zt_chan_conf chan_conf, struct zt_pri *pri, int reloading)
 {
        /* Make a zt_pvt structure for this interface (or CRV if "pri" is specified) */
        struct zt_pvt *tmp = NULL, *tmp2,  *prev = NULL;
@@ -6888,8 +7039,8 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                                        destroy_zt_pvt(&tmp);
                                        return NULL;
                                }
-                               if (p.sigtype != (signalling & 0x3ffff)) {
-                                       ast_log(LOG_ERROR, "Signalling requested on channel %d is %s but line is in %s signalling\n", channel, sig2str(signalling), sig2str(p.sigtype));
+                               if (p.sigtype != (chan_conf.signalling & 0x3ffff)) {
+                                       ast_log(LOG_ERROR, "Signalling requested on channel %d is %s but line is in %s signalling\n", channel, sig2str(chan_conf.signalling), sig2str(p.sigtype));
                                        destroy_zt_pvt(&tmp);
                                        return tmp;
                                }
@@ -6898,20 +7049,20 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                                span = p.spanno - 1;
                        } else {
                                if (channel == CHAN_PSEUDO)
-                                       signalling = 0;
-                               else if ((signalling != SIG_FXOKS) && (signalling != SIG_FXSKS)) {
+                                       chan_conf.signalling = 0;
+                               else if ((chan_conf.signalling != SIG_FXOKS) && (chan_conf.signalling != SIG_FXSKS)) {
                                        ast_log(LOG_ERROR, "CRV's must use FXO/FXS Kewl Start (fxo_ks/fxs_ks) signalling only.\n");
                                        return NULL;
                                }
                        }
 #ifdef ZAPATA_PRI
-                       if ((signalling == SIG_PRI) || (signalling == SIG_GR303FXOKS) || (signalling == SIG_GR303FXSKS)) {
+                       if ((chan_conf.signalling == SIG_PRI) || (chan_conf.signalling == SIG_GR303FXOKS) || (chan_conf.signalling == SIG_GR303FXSKS)) {
                                int offset;
                                int myswitchtype;
                                int matchesdchan;
                                int x,y;
                                offset = 0;
-                               if ((signalling == SIG_PRI) && ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &offset)) {
+                               if ((chan_conf.signalling == SIG_PRI) && ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &offset)) {
                                        ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
                                        destroy_zt_pvt(&tmp);
                                        return NULL;
@@ -6935,7 +7086,7 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                                                destroy_zt_pvt(&tmp);
                                                return NULL;
                                        }
-                                       if (signalling == SIG_PRI)
+                                       if (chan_conf.signalling == SIG_PRI)
                                                myswitchtype = switchtype;
                                        else
                                                myswitchtype = PRI_SWITCH_GR303_TMC;
@@ -6966,23 +7117,23 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, idledial)) {
-                                                       ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, idledial);
+                                               if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, chan_conf.pri.idledial)) {
+                                                       ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, chan_conf.pri.idledial);
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, idleext)) {
-                                                       ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, idleext);
+                                               if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, chan_conf.pri.idleext)) {
+                                                       ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, chan_conf.pri.idleext);
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               if (pris[span].minunused && (pris[span].minunused != minunused)) {
-                                                       ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, minunused);
+                                               if (pris[span].minunused && (pris[span].minunused != chan_conf.pri.minunused)) {
+                                                       ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, chan_conf.pri.minunused);
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
-                                               if (pris[span].minidle && (pris[span].minidle != minidle)) {
-                                                       ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, minidle);
+                                               if (pris[span].minidle && (pris[span].minidle != chan_conf.pri.minidle)) {
+                                                       ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, chan_conf.pri.minidle);
                                                        destroy_zt_pvt(&tmp);
                                                        return NULL;
                                                }
@@ -6998,18 +7149,18 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                                                pris[span].dialplan = dialplan;
                                                pris[span].localdialplan = localdialplan;
                                                pris[span].pvts[pris[span].numchans++] = tmp;
-                                               pris[span].minunused = minunused;
-                                               pris[span].minidle = minidle;
-                                               pris[span].overlapdial = overlapdial;
-                                               pris[span].facilityenable = facilityenable;
-                                               ast_copy_string(pris[span].idledial, idledial, sizeof(pris[span].idledial));
-                                               ast_copy_string(pris[span].idleext, idleext, sizeof(pris[span].idleext));
-                                               ast_copy_string(pris[span].internationalprefix, internationalprefix, sizeof(pris[span].internationalprefix));
-                                               ast_copy_string(pris[span].nationalprefix, nationalprefix, sizeof(pris[span].nationalprefix));
-                                               ast_copy_string(pris[span].localprefix, localprefix, sizeof(pris[span].localprefix));
-                                               ast_copy_string(pris[span].privateprefix, privateprefix, sizeof(pris[span].privateprefix));
-                                               ast_copy_string(pris[span].unknownprefix, unknownprefix, sizeof(pris[span].unknownprefix));
-                                               pris[span].resetinterval = resetinterval;
+                                               pris[span].minunused = chan_conf.pri.minunused;
+                                               pris[span].minidle = chan_conf.pri.minidle;
+                                               pris[span].overlapdial = chan_conf.pri.overlapdial;
+                                               pris[span].facilityenable = chan_conf.pri.facilityenable;
+                                               ast_copy_string(pris[span].idledial, chan_conf.pri.idledial, sizeof(pris[span].idledial));
+                                               ast_copy_string(pris[span].idleext, chan_conf.pri.idleext, sizeof(pris[span].idleext));
+                                               ast_copy_string(pris[span].internationalprefix, chan_conf.pri.internationalprefix, sizeof(pris[span].internationalprefix));
+                                               ast_copy_string(pris[span].nationalprefix, chan_conf.pri.nationalprefix, sizeof(pris[span].nationalprefix));
+                                               ast_copy_string(pris[span].localprefix, chan_conf.pri.localprefix, sizeof(pris[span].localprefix));
+                                               ast_copy_string(pris[span].privateprefix, chan_conf.pri.privateprefix, sizeof(pris[span].privateprefix));
+                                               ast_copy_string(pris[span].unknownprefix, chan_conf.pri.unknownprefix, sizeof(pris[span].unknownprefix));
+                                               pris[span].resetinterval = chan_conf.pri.resetinterval;
                                                
                                                tmp->pri = &pris[span];
                                                tmp->prioffset = offset;
@@ -7025,7 +7176,7 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                        }
 #endif
 #ifdef ZAPATA_R2
-                       if (signalling == SIG_R2) {
+                       if (chan_conf.signalling == SIG_R2) {
                                if (r2prot < 0) {
                                        ast_log(LOG_WARNING, "R2 Country not specified for channel %d -- Assuming China\n", tmp->channel);
                                        tmp->r2prot = MFCR2_PROT_CHINA;
@@ -7045,23 +7196,23 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                        }
 #endif
                } else {
-                       signalling = tmp->sig;
-                       radio = tmp->radio;
+                       chan_conf.signalling = tmp->sig;
+                       chan_conf.radio = tmp->radio;
                        memset(&p, 0, sizeof(p));
                        if (tmp->subs[SUB_REAL].zfd > -1)
                                res = ioctl(tmp->subs[SUB_REAL].zfd, ZT_GET_PARAMS, &p);
                }
                /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
-               if ((signalling == SIG_FXSKS) || (signalling == SIG_FXSLS) ||
-                   (signalling == SIG_EM) || (signalling == SIG_EM_E1) ||  (signalling == SIG_EMWINK) ||
-                       (signalling == SIG_FEATD) || (signalling == SIG_FEATDMF) || (signalling == SIG_FEATDMF_TA) ||
-                         (signalling == SIG_FEATB) || (signalling == SIG_E911) ||
-                   (signalling == SIG_SF) || (signalling == SIG_SFWINK) ||
-                       (signalling == SIG_SF_FEATD) || (signalling == SIG_SF_FEATDMF) ||
-                         (signalling == SIG_SF_FEATB)) {
+               if ((chan_conf.signalling == SIG_FXSKS) || (chan_conf.signalling == SIG_FXSLS) ||
+                   (chan_conf.signalling == SIG_EM) || (chan_conf.signalling == SIG_EM_E1) ||  (chan_conf.signalling == SIG_EMWINK) ||
+                       (chan_conf.signalling == SIG_FEATD) || (chan_conf.signalling == SIG_FEATDMF) || (chan_conf.signalling == SIG_FEATDMF_TA) ||
+                         (chan_conf.signalling == SIG_FEATB) || (chan_conf.signalling == SIG_E911) ||
+                   (chan_conf.signalling == SIG_SF) || (chan_conf.signalling == SIG_SFWINK) ||
+                       (chan_conf.signalling == SIG_SF_FEATD) || (chan_conf.signalling == SIG_SF_FEATDMF) ||
+                         (chan_conf.signalling == SIG_SF_FEATB)) {
                        p.starttime = 250;
                }
-               if (radio) {
+               if (chan_conf.radio) {
                        /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
                        p.channo = channel;
                        p.rxwinktime = 1;
@@ -7069,25 +7220,25 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                        p.starttime = 1;
                        p.debouncetime = 5;
                }
-               if (!radio) {
+               if (!chan_conf.radio) {
                        p.channo = channel;
                        /* Override timing settings based on config file */
-                       if (cur_prewink >= 0)
-                               p.prewinktime = cur_prewink;
-                       if (cur_preflash >= 0)
-                               p.preflashtime = cur_preflash;
-                       if (cur_wink >= 0)
-                               p.winktime = cur_wink;
-                       if (cur_flash >= 0)
-                               p.flashtime = cur_flash;
-                       if (cur_start >= 0)
-                               p.starttime = cur_start;
-                       if (cur_rxwink >= 0)
-                               p.rxwinktime = cur_rxwink;
-                       if (cur_rxflash >= 0)
-                               p.rxflashtime = cur_rxflash;
-                       if (cur_debounce >= 0)
-                               p.debouncetime = cur_debounce;
+                       if (chan_conf.prewink >= 0)
+                               p.prewinktime = chan_conf.prewink;
+                       if (chan_conf.preflash >= 0)
+                               p.preflashtime = chan_conf.preflash;
+                       if (chan_conf.wink >= 0)
+                               p.winktime = chan_conf.wink;
+                       if (chan_conf.flash >= 0)
+                               p.flashtime = chan_conf.flash;
+                       if (chan_conf.start >= 0)
+                               p.starttime = chan_conf.start;
+                       if (chan_conf.rxwink >= 0)
+                               p.rxwinktime = chan_conf.rxwink;
+                       if (chan_conf.rxflash >= 0)
+                               p.rxflashtime = chan_conf.rxflash;
+                       if (chan_conf.debounce >= 0)
+                               p.debouncetime = chan_conf.debounce;
                }
                
                /* dont set parms on a pseudo-channel (or CRV) */
@@ -7116,48 +7267,48 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                                ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d\n", channel);
                }
 #endif
-               tmp->immediate = immediate;
-               tmp->transfertobusy = transfertobusy;
-               tmp->sig = signalling;
-               tmp->radio = radio;
+               tmp->immediate = chan_conf.immediate;
+               tmp->transfertobusy = chan_conf.transfertobusy;
+               tmp->sig = chan_conf.signalling;
+               tmp->radio = chan_conf.radio;
                tmp->ringt_base = ringt_base;
                tmp->firstradio = 0;
-               if ((signalling == SIG_FXOKS) || (signalling == SIG_FXOLS) || (signalling == SIG_FXOGS))
-                       tmp->permcallwaiting = callwaiting;
+               if ((chan_conf.signalling == SIG_FXOKS) || (chan_conf.signalling == SIG_FXOLS) || (chan_conf.signalling == SIG_FXOGS))
+                       tmp->permcallwaiting = chan_conf.callwaiting;
                else
                        tmp->permcallwaiting = 0;
                /* Flag to destroy the channel must be cleared on new mkif.  Part of changes for reload to work */
                tmp->destroy = 0;
                tmp->drings = drings;
                tmp->usedistinctiveringdetection = usedistinctiveringdetection;
-               tmp->callwaitingcallerid = callwaitingcallerid;
-               tmp->threewaycalling = threewaycalling;
-               tmp->adsi = adsi;
-               tmp->permhidecallerid = hidecallerid;
-               tmp->callreturn = callreturn;
-               tmp->echocancel = echocancel;
-               tmp->echotraining = echotraining;
-               tmp->pulse = pulse;
-               tmp->echocanbridged = echocanbridged;
-               tmp->busydetect = busydetect;
-               tmp->busycount = busycount;
-               tmp->busy_tonelength = busy_tonelength;
-               tmp->busy_quietlength = busy_quietlength;
-               tmp->callprogress = callprogress;
-               tmp->cancallforward = cancallforward;
-               tmp->dtmfrelax = relaxdtmf;
+               tmp->callwaitingcallerid = chan_conf.callwaitingcallerid;
+               tmp->threewaycalling = chan_conf.threewaycalling;
+               tmp->adsi = chan_conf.adsi;
+               tmp->permhidecallerid = chan_conf.hidecallerid;
+               tmp->callreturn = chan_conf.callreturn;
+               tmp->echocancel = chan_conf.echocancel;
+               tmp->echotraining = chan_conf.echotraining;
+               tmp->pulse = chan_conf.pulse;
+               tmp->echocanbridged = chan_conf.echocanbridged;
+               tmp->busydetect = chan_conf.busydetect;
+               tmp->busycount = chan_conf.busycount;
+               tmp->busy_tonelength = chan_conf.busy_tonelength;
+               tmp->busy_quietlength = chan_conf.busy_quietlength;
+               tmp->callprogress = chan_conf.callprogress;
+               tmp->cancallforward = chan_conf.cancallforward;
+               tmp->dtmfrelax = chan_conf.relaxdtmf;
                tmp->callwaiting = tmp->permcallwaiting;
                tmp->hidecallerid = tmp->permhidecallerid;
                tmp->channel = channel;
-               tmp->stripmsd = stripmsd;
-               tmp->use_callerid = use_callerid;
-               tmp->cid_signalling = cid_signalling;
-               tmp->cid_start = cid_start;
-               tmp->zaptrcallerid = zaptrcallerid;
-               tmp->restrictcid = restrictcid;
-               tmp->use_callingpres = use_callingpres;
-               tmp->priindication_oob = priindication_oob;
-               tmp->priexclusive = cur_priexclusive;
+               tmp->stripmsd = chan_conf.stripmsd;
+               tmp->use_callerid = chan_conf.use_callerid;
+               tmp->cid_signalling = chan_conf.cid_signalling;
+               tmp->cid_start = chan_conf.cid_start;
+               tmp->zaptrcallerid = chan_conf.zaptrcallerid;
+               tmp->restrictcid = chan_conf.restrictcid;
+               tmp->use_callingpres = chan_conf.use_callingpres;
+               tmp->priindication_oob = chan_conf.priindication_oob;
+               tmp->priexclusive = chan_conf.priexclusive;
                if (tmp->usedistinctiveringdetection) {
                        if (!tmp->use_callerid) {
                                ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
@@ -7165,29 +7316,29 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                        }
                }
 
-               ast_copy_string(tmp->accountcode, accountcode, sizeof(tmp->accountcode));
-               tmp->amaflags = amaflags;
+               ast_copy_string(tmp->accountcode, chan_conf.accountcode, sizeof(tmp->accountcode));
+               tmp->amaflags = chan_conf.amaflags;
                if (!here) {
                        tmp->confno = -1;
                        tmp->propconfno = -1;
                }
-               tmp->canpark = canpark;
-               tmp->transfer = transfer;
-               ast_copy_string(tmp->defcontext,context,sizeof(tmp->defcontext));
+               tmp->canpark = chan_conf.canpark;
+               tmp->transfer = chan_conf.transfer;
+               ast_copy_string(tmp->defcontext,chan_conf.context,sizeof(tmp->defcontext));
                ast_copy_string(tmp->language, language, sizeof(tmp->language));
-               ast_copy_string(tmp->musicclass, musicclass, sizeof(tmp->musicclass));
-               ast_copy_string(tmp->context, context, sizeof(tmp->context));
-               ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num));
+               ast_copy_string(tmp->musicclass, chan_conf.musicclass, sizeof(tmp->musicclass));
+               ast_copy_string(tmp->context, chan_conf.context, sizeof(tmp->context));
+               ast_copy_string(tmp->cid_num, chan_conf.cid_num, sizeof(tmp->cid_num));
                tmp->cid_ton = 0;
-               ast_copy_string(tmp->cid_name, cid_name, sizeof(tmp->cid_name));
-               ast_copy_string(tmp->mailbox, mailbox, sizeof(tmp->mailbox));
+               ast_copy_string(tmp->cid_name, chan_conf.cid_name, sizeof(tmp->cid_name));
+               ast_copy_string(tmp->mailbox, chan_conf.mailbox, sizeof(tmp->mailbox));
                tmp->msgstate = -1;
-               tmp->group = cur_group;
-               tmp->callgroup=cur_callergroup;
-               tmp->pickupgroup=cur_pickupgroup;
-               tmp->rxgain = rxgain;
-               tmp->txgain = txgain;
-               tmp->tonezone = tonezone;
+               tmp->group = chan_conf.group;
+               tmp->callgroup=chan_conf.callergroup;
+               tmp->pickupgroup=chan_conf.pickupgroup;
+               tmp->rxgain = chan_conf.rxgain;
+               tmp->txgain = chan_conf.txgain;
+               tmp->tonezone = chan_conf.tonezone;
                tmp->onhooktime = time(NULL);
                if (tmp->subs[SUB_REAL].zfd > -1) {
                        set_actual_gain(tmp->subs[SUB_REAL].zfd, 0, tmp->rxgain, tmp->txgain, tmp->law);
@@ -7195,7 +7346,7 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                                ast_dsp_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
                        update_conf(tmp);
                        if (!here) {
-                               if ((signalling != SIG_PRI) && (signalling != SIG_R2))
+                               if ((chan_conf.signalling != SIG_PRI) && (chan_conf.signalling != SIG_R2))
                                        /* Hang it up to be sure it's good */
                                        zt_set_hook(tmp->subs[SUB_REAL].zfd, ZT_ONHOOK);
                        }
@@ -7216,10 +7367,10 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
                        if (si.alarms) tmp->inalarm = 1;
                }
 
-               tmp->polarityonanswerdelay = polarityonanswerdelay;
-               tmp->answeronpolarityswitch = answeronpolarityswitch;
-               tmp->hanguponpolarityswitch = hanguponpolarityswitch;
-               tmp->sendcalleridafter = sendcalleridafter;
+               tmp->polarityonanswerdelay = chan_conf.polarityonanswerdelay;
+               tmp->answeronpolarityswitch = chan_conf.answeronpolarityswitch;
+               tmp->hanguponpolarityswitch = chan_conf.hanguponpolarityswitch;
+               tmp->sendcalleridafter = chan_conf.sendcalleridafter;
 
        }
        if (tmp && !here) {
@@ -10131,7 +10282,7 @@ static int setup_zap(int reload)
        int start, finish,x;
        int y;
        int found_pseudo = 0;
-       int cur_radio = 0;
+       struct zt_chan_conf chan_conf = zt_chan_conf_default();
 #ifdef ZAPATA_PRI
        int spanno;
        int i;
@@ -10224,7 +10375,7 @@ static int setup_zap(int reload)
 #endif                 
                                        ) {
                        if (reload == 0) {
-                               if (cur_signalling < 0) {
+                               if (chan_conf.signalling < 0) {
                                        ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
                                        ast_config_destroy(cfg);
                                        ast_mutex_unlock(&iflock);
@@ -10287,9 +10438,9 @@ static int setup_zap(int reload)
                                }
                                for (x=start;x<=finish;x++) {
 #ifdef ZAPATA_PRI
-                                       tmp = mkintf(x, cur_signalling, cur_radio, pri, reload);
+                                       tmp = mkintf(x, chan_conf, pri, reload);
 #else                                  
-                                       tmp = mkintf(x, cur_signalling, cur_radio, NULL, reload);
+                                       tmp = mkintf(x, chan_conf, NULL, reload);
 #endif                                 
 
                                        if (tmp) {
@@ -10332,278 +10483,272 @@ static int setup_zap(int reload)
                        ringc = v->value;
                        sscanf(ringc, "%d,%d,%d", &drings.ringnum[2].ring[0], &drings.ringnum[2].ring[1], &drings.ringnum[2].ring[2]);
                } else if (!strcasecmp(v->name, "usecallerid")) {
-                       use_callerid = ast_true(v->value);
+                       chan_conf.use_callerid = ast_true(v->value);
                } else if (!strcasecmp(v->name, "cidsignalling")) {
                        if (!strcasecmp(v->value, "bell"))
-                               cid_signalling = CID_SIG_BELL;
+                               chan_conf.cid_signalling = CID_SIG_BELL;
                        else if (!strcasecmp(v->value, "v23"))
-                               cid_signalling = CID_SIG_V23;
+                               chan_conf.cid_signalling = CID_SIG_V23;
                        else if (!strcasecmp(v->value, "dtmf"))
-                               cid_signalling = CID_SIG_DTMF;
+                               chan_conf.cid_signalling = CID_SIG_DTMF;
                        else if (ast_true(v->value))
-                               cid_signalling = CID_SIG_BELL;
+                               chan_conf.cid_signalling = CID_SIG_BELL;
                } else if (!strcasecmp(v->name, "cidstart")) {
                        if (!strcasecmp(v->value, "ring"))
-                               cid_start = CID_START_RING;
+                               chan_conf.cid_start = CID_START_RING;
                        else if (!strcasecmp(v->value, "polarity"))
-                               cid_start = CID_START_POLARITY;
+                               chan_conf.cid_start = CID_START_POLARITY;
                        else if (ast_true(v->value))
-                               cid_start = CID_START_RING;
+                               chan_conf.cid_start = CID_START_RING;
                } else if (!strcasecmp(v->name, "threewaycalling")) {
-                       threewaycalling = ast_true(v->value);
+                       chan_conf.threewaycalling = ast_true(v->value);
                } else if (!strcasecmp(v->name, "cancallforward")) {
-                       cancallforward = ast_true(v->value);
+                       chan_conf.cancallforward = ast_true(v->value);
                } else if (!strcasecmp(v->name, "relaxdtmf")) {
                        if (ast_true(v->value)) 
-                               relaxdtmf = DSP_DIGITMODE_RELAXDTMF;
+                               chan_conf.relaxdtmf = DSP_DIGITMODE_RELAXDTMF;
                        else
-                               relaxdtmf = 0;
+                               chan_conf.relaxdtmf = 0;
                } else if (!strcasecmp(v->name, "mailbox")) {
-                       ast_copy_string(mailbox, v->value, sizeof(mailbox));
+                       ast_copy_string(chan_conf.mailbox, v->value, sizeof(chan_conf.mailbox));
                } else if (!strcasecmp(v->name, "adsi")) {
-                       adsi = ast_true(v->value);
+                       chan_conf.adsi = ast_true(v->value);
                } else if (!strcasecmp(v->name, "transfer")) {
-                       transfer = ast_true(v->value);
+                       chan_conf.transfer = ast_true(v->value);
                } else if (!strcasecmp(v->name, "canpark")) {
-                       canpark = ast_true(v->value);
+                       chan_conf.canpark = ast_true(v->value);
                } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
-                       echocanbridged = ast_true(v->value);
+                       chan_conf.echocanbridged = ast_true(v->value);
                } else if (!strcasecmp(v->name, "busydetect")) {
-                       busydetect = ast_true(v->value);
+                       chan_conf.busydetect = ast_true(v->value);
                } else if (!strcasecmp(v->name, "busycount")) {
-                       busycount = atoi(v->value);
+                       chan_conf.busycount = atoi(v->value);
                } else if (!strcasecmp(v->name, "busypattern")) {
-                       if (sscanf(v->value, "%d,%d", &busy_tonelength, &busy_quietlength) != 2) {
+                       if (sscanf(v->value, "%d,%d", &chan_conf.busy_tonelength, &chan_conf.busy_quietlength) != 2) {
                                ast_log(LOG_ERROR, "busypattern= expects busypattern=tonelength,quietlength\n");
                        }
                } else if (!strcasecmp(v->name, "callprogress")) {
                        if (ast_true(v->value))
-                               callprogress |= 1;
+                               chan_conf.callprogress |= 1;
                        else
-                               callprogress &= ~1;
+                               chan_conf.callprogress &= ~1;
                } else if (!strcasecmp(v->name, "faxdetect")) {
                        if (!strcasecmp(v->value, "incoming")) {
-                               callprogress |= 4;
-                               callprogress &= ~2;
+                               chan_conf.callprogress |= 4;
+                               chan_conf.callprogress &= ~2;
                        } else if (!strcasecmp(v->value, "outgoing")) {
-                               callprogress &= ~4;
-                               callprogress |= 2;
+                               chan_conf.callprogress &= ~4;
+                               chan_conf.callprogress |= 2;
                        } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
-                               callprogress |= 6;
+                               chan_conf.callprogress |= 6;
                        else
-                               callprogress &= ~6;
+                               chan_conf.callprogress &= ~6;
                } else if (!strcasecmp(v->name, "echocancel")) {
                        if (!ast_strlen_zero(v->value)) {
                                y = atoi(v->value);
                        } else
                                y = 0;
-                       if ((y == 32) || (y == 64) || (y == 128) || (y == 256))
-                               echocancel = y;
+                       if ((y == 32) || (y == 64) || (y == 128) || (y == 256) || (y == 512) || (y == 1024))
+                               chan_conf.echocancel = y;
                        else {
-                               echocancel = ast_true(v->value);
-                               if (echocancel)
-                                       echocancel=128;
+                               chan_conf.echocancel = ast_true(v->value);
+                               if (chan_conf.echocancel)
+                                       chan_conf.echocancel=128;
                        }
                } else if (!strcasecmp(v->name, "echotraining")) {
                        if (sscanf(v->value, "%d", &y) == 1) {
                                if ((y < 10) || (y > 4000)) {
                                        ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 2000 ms at line %d\n", v->lineno);                                   
                                } else {
-                                       echotraining = y;
+                                       chan_conf.echotraining = y;
                                }
                        } else if (ast_true(v->value)) {
-                               echotraining = 400;
+                               chan_conf.echotraining = 400;
                        } else
-                               echotraining = 0;
+                               chan_conf.echotraining = 0;
                } else if (!strcasecmp(v->name, "hidecallerid")) {
-                       hidecallerid = ast_true(v->value);
+                       chan_conf.hidecallerid = ast_true(v->value);
                } else if (!strcasecmp(v->name, "pulsedial")) {
-                       pulse = ast_true(v->value);
+                       chan_conf.pulse = ast_true(v->value);
                } else if (!strcasecmp(v->name, "callreturn")) {
-                       callreturn = ast_true(v->value);
+                       chan_conf.callreturn = ast_true(v->value);
                } else if (!strcasecmp(v->name, "callwaiting")) {
-                       callwaiting = ast_true(v->value);
+                       chan_conf.callwaiting = ast_true(v->value);
                } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
-                       callwaitingcallerid = ast_true(v->value);
+                       chan_conf.callwaitingcallerid = ast_true(v->value);
                } else if (!strcasecmp(v->name, "context")) {
-                       ast_copy_string(context, v->value, sizeof(context));
+                       ast_copy_string(chan_conf.context, v->value, sizeof(chan_conf.context));
                } else if (!strcasecmp(v->name, "language")) {
                        ast_copy_string(language, v->value, sizeof(language));
                } else if (!strcasecmp(v->name, "progzone")) {
                        ast_copy_string(progzone, v->value, sizeof(progzone));
                } else if (!strcasecmp(v->name, "musiconhold")) {
-                       ast_copy_string(musicclass, v->value, sizeof(musicclass));
+                       ast_copy_string(chan_conf.musicclass, v->value, sizeof(chan_conf.musicclass));
                } else if (!strcasecmp(v->name, "stripmsd")) {
-                       stripmsd = atoi(v->value);
+                       chan_conf.stripmsd = atoi(v->value);
                } else if (!strcasecmp(v->name, "jitterbuffers")) {
                        numbufs = atoi(v->value);
                } else if (!strcasecmp(v->name, "group")) {
-                       cur_group = ast_get_group(v->value);
+                       chan_conf.group = ast_get_group(v->value);
                } else if (!strcasecmp(v->name, "callgroup")) {
-                       if (!strcasecmp(v->value, "none"))
-                               cur_callergroup = 0;
-                       else
-                               cur_callergroup = ast_get_group(v->value);
+                       chan_conf.callergroup = ast_get_group(v->value);
                } else if (!strcasecmp(v->name, "pickupgroup")) {
-                       if (!strcasecmp(v->value, "none"))
-                               cur_pickupgroup = 0;
-                       else
-                               cur_pickupgroup = ast_get_group(v->value);
+                       chan_conf.pickupgroup = ast_get_group(v->value);
                } else if (!strcasecmp(v->name, "immediate")) {
-                       immediate = ast_true(v->value);
+                       chan_conf.immediate = ast_true(v->value);
                } else if (!strcasecmp(v->name, "transfertobusy")) {
-                       transfertobusy = ast_true(v->value);
+                       chan_conf.transfertobusy = ast_true(v->value);
                } else if (!strcasecmp(v->name, "rxgain")) {
-                       if (sscanf(v->value, "%f", &rxgain) != 1) {
+                       if (sscanf(v->value, "%f", &chan_conf.rxgain) != 1) {
                                ast_log(LOG_WARNING, "Invalid rxgain: %s\n", v->value);
                        }
                } else if (!strcasecmp(v->name, "txgain")) {
-                       if (sscanf(v->value, "%f", &txgain) != 1) {
+                       if (sscanf(v->value, "%f", &chan_conf.txgain) != 1) {
                                ast_log(LOG_WARNING, "Invalid txgain: %s\n", v->value);
                        }
                } else if (!strcasecmp(v->name, "tonezone")) {
-                       if (sscanf(v->value, "%d", &tonezone) != 1) {
+                       if (sscanf(v->value, "%d", &chan_conf.tonezone) != 1) {
                                ast_log(LOG_WARNING, "Invalid tonezone: %s\n", v->value);
                        }
                } else if (!strcasecmp(v->name, "callerid")) {
                        if (!strcasecmp(v->value, "asreceived")) {
-                               cid_num[0] = '\0';
-                               cid_name[0] = '\0';
+                               chan_conf.cid_num[0] = '\0';
+                               chan_conf.cid_name[0] = '\0';
                        } else {
-                               ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
+                               ast_callerid_split(v->value, chan_conf.cid_name, sizeof(chan_conf.cid_name), chan_conf.cid_num, sizeof(chan_conf.cid_num));
                        }
                } else if (!strcasecmp(v->name, "useincomingcalleridonzaptransfer")) {
-                       zaptrcallerid = ast_true(v->value);
+                       chan_conf.zaptrcallerid = ast_true(v->value);
                } else if (!strcasecmp(v->name, "restrictcid")) {
-                       restrictcid = ast_true(v->value);
+                       chan_conf.restrictcid = ast_true(v->value);
                } else if (!strcasecmp(v->name, "usecallingpres")) {
-                       use_callingpres = ast_true(v->value);
+                       chan_conf.use_callingpres = ast_true(v->value);
                } else if (!strcasecmp(v->name, "accountcode")) {
-                       ast_copy_string(accountcode, v->value, sizeof(accountcode));
+                       ast_copy_string(chan_conf.accountcode, v->value, sizeof(chan_conf.accountcode));
                } else if (!strcasecmp(v->name, "amaflags")) {
                        y = ast_cdr_amaflags2int(v->value);
                        if (y < 0) 
                                ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
                        else
-                               amaflags = y;
+                               chan_conf.amaflags = y;
                } else if(!reload){ 
                         if (!strcasecmp(v->name, "signalling")) {
                                if (!strcasecmp(v->value, "em")) {
-                                       cur_signalling = SIG_EM;
+                                       chan_conf.signalling = SIG_EM;
                                } else if (!strcasecmp(v->value, "em_e1")) {
-                                       cur_signalling = SIG_EM_E1;
+                                       chan_conf.signalling = SIG_EM_E1;
                                } else if (!strcasecmp(v->value, "em_w")) {
-                                       cur_signalling = SIG_EMWINK;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_EMWINK;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "fxs_ls")) {
-                                       cur_signalling = SIG_FXSLS;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FXSLS;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "fxs_gs")) {
-                                       cur_signalling = SIG_FXSGS;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FXSGS;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "fxs_ks")) {
-                                       cur_signalling = SIG_FXSKS;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FXSKS;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "fxo_ls")) {
-                                       cur_signalling = SIG_FXOLS;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FXOLS;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "fxo_gs")) {
-                                       cur_signalling = SIG_FXOGS;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FXOGS;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "fxo_ks")) {
-                                       cur_signalling = SIG_FXOKS;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FXOKS;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "fxs_rx")) {
-                                       cur_signalling = SIG_FXSKS;
-                                       cur_radio = 1;
+                                       chan_conf.signalling = SIG_FXSKS;
+                                       chan_conf.radio = 1;
                                } else if (!strcasecmp(v->value, "fxo_rx")) {
-                                       cur_signalling = SIG_FXOLS;
-                                       cur_radio = 1;
+                                       chan_conf.signalling = SIG_FXOLS;
+                                       chan_conf.radio = 1;
                                } else if (!strcasecmp(v->value, "fxs_tx")) {
-                                       cur_signalling = SIG_FXSLS;
-                                       cur_radio = 1;
+                                       chan_conf.signalling = SIG_FXSLS;
+                                       chan_conf.radio = 1;
                                } else if (!strcasecmp(v->value, "fxo_tx")) {
-                                       cur_signalling = SIG_FXOGS;
-                                       cur_radio = 1;
+                                       chan_conf.signalling = SIG_FXOGS;
+                                       chan_conf.radio = 1;
                                } else if (!strcasecmp(v->value, "em_rx")) {
-                                       cur_signalling = SIG_EM;
-                                       cur_radio = 1;
+                                       chan_conf.signalling = SIG_EM;
+                                       chan_conf.radio = 1;
                                } else if (!strcasecmp(v->value, "em_tx")) {
-                                       cur_signalling = SIG_EM;
-                                       cur_radio = 1;
+                                       chan_conf.signalling = SIG_EM;
+                                       chan_conf.radio = 1;
                                } else if (!strcasecmp(v->value, "em_rxtx")) {
-                                       cur_signalling = SIG_EM;
-                                       cur_radio = 2;
+                                       chan_conf.signalling = SIG_EM;
+                                       chan_conf.radio = 2;
                                } else if (!strcasecmp(v->value, "em_txrx")) {
-                                       cur_signalling = SIG_EM;
-                                       cur_radio = 2;
+                                       chan_conf.signalling = SIG_EM;
+                                       chan_conf.radio = 2;
                                } else if (!strcasecmp(v->value, "sf")) {
-                                       cur_signalling = SIG_SF;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_SF;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "sf_w")) {
-                                       cur_signalling = SIG_SFWINK;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_SFWINK;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "sf_featd")) {
-                                       cur_signalling = SIG_FEATD;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FEATD;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "sf_featdmf")) {
-                                       cur_signalling = SIG_FEATDMF;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FEATDMF;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "sf_featb")) {
-                                       cur_signalling = SIG_SF_FEATB;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_SF_FEATB;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "sf")) {
-                                       cur_signalling = SIG_SF;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_SF;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "sf_rx")) {
-                                       cur_signalling = SIG_SF;
-                                       cur_radio = 1;
+                                       chan_conf.signalling = SIG_SF;
+                                       chan_conf.radio = 1;
                                } else if (!strcasecmp(v->value, "sf_tx")) {
-                                       cur_signalling = SIG_SF;
-                                       cur_radio = 1;
+                                       chan_conf.signalling = SIG_SF;
+                                       chan_conf.radio = 1;
                                } else if (!strcasecmp(v->value, "sf_rxtx")) {
-                                       cur_signalling = SIG_SF;
-                                       cur_radio = 2;
+                                       chan_conf.signalling = SIG_SF;
+                                       chan_conf.radio = 2;
                                } else if (!strcasecmp(v->value, "sf_txrx")) {
-                                       cur_signalling = SIG_SF;
-                                       cur_radio = 2;
+                                       chan_conf.signalling = SIG_SF;
+                                       chan_conf.radio = 2;
                                } else if (!strcasecmp(v->value, "featd")) {
-                                       cur_signalling = SIG_FEATD;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FEATD;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "featdmf")) {
-                                       cur_signalling = SIG_FEATDMF;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FEATDMF;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "featdmf_ta")) {
-                                       cur_signalling = SIG_FEATDMF_TA;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FEATDMF_TA;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "e911")) {
-                                       cur_signalling = SIG_E911;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_E911;
+                                       chan_conf.radio = 0;
                                } else if (!strcasecmp(v->value, "featb")) {
-                                       cur_signalling = SIG_FEATB;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_FEATB;
+                                       chan_conf.radio = 0;
 #ifdef ZAPATA_PRI
                                } else if (!strcasecmp(v->value, "pri_net")) {
-                                       cur_radio = 0;
-                                       cur_signalling = SIG_PRI;
+                                       chan_conf.radio = 0;
+                                       chan_conf.signalling = SIG_PRI;
                                        pritype = PRI_NETWORK;
                                } else if (!strcasecmp(v->value, "pri_cpe")) {
-                                       cur_signalling = SIG_PRI;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_PRI;
+                                       chan_conf.radio = 0;
                                        pritype = PRI_CPE;
                                } else if (!strcasecmp(v->value, "gr303fxoks_net")) {
-                                       cur_signalling = SIG_GR303FXOKS;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_GR303FXOKS;
+                                       chan_conf.radio = 0;
                                        pritype = PRI_NETWORK;
                                } else if (!strcasecmp(v->value, "gr303fxsks_cpe")) {
-                                       cur_signalling = SIG_GR303FXSKS;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_GR303FXSKS;
+                                       chan_conf.radio = 0;
                                        pritype = PRI_CPE;
 #endif
 #ifdef ZAPATA_R2
                                } else if (!strcasecmp(v->value, "r2")) {
-                                       cur_signalling = SIG_R2;
-                                       cur_radio = 0;
+                                       chan_conf.signalling = SIG_R2;
+                                       chan_conf.radio = 0;
 #endif                 
                                } else {
                                        ast_log(LOG_ERROR, "Unknown signalling method '%s'\n", v->value);
@@ -10684,42 +10829,42 @@ static int setup_zap(int reload)
                                }
                        } else if (!strcasecmp(v->name, "priindication")) {
                                if (!strcasecmp(v->value, "outofband"))
-                                       priindication_oob = 1;
+                                       chan_conf.priindication_oob = 1;
                                else if (!strcasecmp(v->value, "inband"))
-                                       priindication_oob = 0;
+                                       chan_conf.priindication_oob = 0;
                                else
                                        ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d\n",
                                                v->value, v->lineno);
                        } else if (!strcasecmp(v->name, "priexclusive")) {
-                               cur_priexclusive = ast_true(v->value);
+                               chan_conf.priexclusive = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "internationalprefix")) {
-                               ast_copy_string(internationalprefix, v->value, sizeof(internationalprefix));
+                               ast_copy_string(chan_conf.pri.internationalprefix, v->value, sizeof(chan_conf.pri.internationalprefix));
                        } else if (!strcasecmp(v->name, "nationalprefix")) {
-                               ast_copy_string(nationalprefix, v->value, sizeof(nationalprefix));
+                               ast_copy_string(chan_conf.pri.nationalprefix, v->value, sizeof(chan_conf.pri.nationalprefix));
                        } else if (!strcasecmp(v->name, "localprefix")) {
-                               ast_copy_string(localprefix, v->value, sizeof(localprefix));
+                               ast_copy_string(chan_conf.pri.localprefix, v->value, sizeof(chan_conf.pri.localprefix));
                        } else if (!strcasecmp(v->name, "privateprefix")) {
-                               ast_copy_string(privateprefix, v->value, sizeof(privateprefix));
+                               ast_copy_string(chan_conf.pri.privateprefix, v->value, sizeof(chan_conf.pri.privateprefix));
                        } else if (!strcasecmp(v->name, "unknownprefix")) {
-                               ast_copy_string(unknownprefix, v->value, sizeof(unknownprefix));
+                               ast_copy_string(chan_conf.pri.unknownprefix, v->value, sizeof(chan_conf.pri.unknownprefix));
                        } else if (!strcasecmp(v->name, "resetinterval")) {
                                if (!strcasecmp(v->value, "never"))
-                                       resetinterval = -1;
+                                       chan_conf.pri.resetinterval = -1;
                                else if( atoi(v->value) >= 60 )
-                                       resetinterval = atoi(v->value);
+                                       chan_conf.pri.resetinterval = atoi(v->value);
                                else
                                        ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d\n",
                                                v->value, v->lineno);
                        } else if (!strcasecmp(v->name, "minunused")) {
-                               minunused = atoi(v->value);
+                               chan_conf.pri.minunused = atoi(v->value);
                        } else if (!strcasecmp(v->name, "minidle")) {
-                               minidle = atoi(v->value); 
+                               chan_conf.pri.minidle = atoi(v->value); 
                        } else if (!strcasecmp(v->name, "idleext")) {
-                               ast_copy_string(idleext, v->value, sizeof(idleext));
+                               ast_copy_string(chan_conf.pri.idleext, v->value, sizeof(chan_conf.pri.idleext));
                        } else if (!strcasecmp(v->name, "idledial")) {
-                               ast_copy_string(idledial, v->value, sizeof(idledial));
+                               ast_copy_string(chan_conf.pri.idledial, v->value, sizeof(chan_conf.pri.idledial));
                        } else if (!strcasecmp(v->name, "overlapdial")) {
-                               overlapdial = ast_true(v->value);
+                               chan_conf.pri.overlapdial = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "pritimer")) {
 #ifdef PRI_GETSET_TIMERS
                                char *timerc;
@@ -10740,7 +10885,7 @@ static int setup_zap(int reload)
                                        ast_log(LOG_WARNING, "'%s' is not a valid ISDN timer configuration string\n", v->value);
 
                        } else if (!strcasecmp(v->name, "facilityenable")) {
-                               facilityenable = ast_true(v->value);
+                               chan_conf.pri.facilityenable = ast_true(v->value);
 #endif /* PRI_GETSET_TIMERS */
 #endif /* ZAPATA_PRI */
                        } else if (!strcasecmp(v->name, "cadence")) {
@@ -10827,21 +10972,21 @@ static int setup_zap(int reload)
                        } else if (!strcasecmp(v->name, "ringtimeout")) {
                                ringt_base = (atoi(v->value) * 8) / READ_SIZE;
                        } else if (!strcasecmp(v->name, "prewink")) {
-                               cur_prewink = atoi(v->value);
+                               chan_conf.prewink = atoi(v->value);
                        } else if (!strcasecmp(v->name, "preflash")) {
-                               cur_preflash = atoi(v->value);
+                               chan_conf.preflash = atoi(v->value);
                        } else if (!strcasecmp(v->name, "wink")) {
-                               cur_wink = atoi(v->value);
+                               chan_conf.wink = atoi(v->value);
                        } else if (!strcasecmp(v->name, "flash")) {
-                               cur_flash = atoi(v->value);
+                               chan_conf.flash = atoi(v->value);
                        } else if (!strcasecmp(v->name, "start")) {
-                               cur_start = atoi(v->value);
+                               chan_conf.start = atoi(v->value);
                        } else if (!strcasecmp(v->name, "rxwink")) {
-                               cur_rxwink = atoi(v->value);
+                               chan_conf.rxwink = atoi(v->value);
                        } else if (!strcasecmp(v->name, "rxflash")) {
-                               cur_rxflash = atoi(v->value);
+                               chan_conf.rxflash = atoi(v->value);
                        } else if (!strcasecmp(v->name, "debounce")) {
-                               cur_debounce = atoi(v->value);
+                               chan_conf.debounce = atoi(v->value);
                        } else if (!strcasecmp(v->name, "toneduration")) {
                                int toneduration;
                                int ctlfd;
@@ -10865,13 +11010,13 @@ static int setup_zap(int reload)
                                }
                                close(ctlfd);
                        } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
-                               polarityonanswerdelay = atoi(v->value);
+                               chan_conf.polarityonanswerdelay = atoi(v->value);
                        } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
-                               answeronpolarityswitch = ast_true(v->value);
+                               chan_conf.answeronpolarityswitch = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
-                               hanguponpolarityswitch = ast_true(v->value);
+                               chan_conf.hanguponpolarityswitch = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "sendcalleridafter")) {
-                               sendcalleridafter = atoi(v->value);
+                               chan_conf.sendcalleridafter = atoi(v->value);
                        } else if (!strcasecmp(v->name, "defaultcic")) {
                                ast_copy_string(defaultcic, v->value, sizeof(defaultcic));
                        } else if (!strcasecmp(v->name, "defaultozz")) {
@@ -10885,11 +11030,11 @@ static int setup_zap(int reload)
        
                /* Make sure pseudo isn't a member of any groups if
                   we're automatically making it. */    
-               cur_group = 0;
-               cur_callergroup = 0;
-               cur_pickupgroup = 0;
+               chan_conf.group = 0;
+               chan_conf.callergroup = 0;
+               chan_conf.pickupgroup = 0;
        
-               tmp = mkintf(CHAN_PSEUDO, cur_signalling, cur_radio, NULL, reload);
+               tmp = mkintf(CHAN_PSEUDO, chan_conf, NULL, reload);
 
                if (tmp) {
                        if (option_verbose > 2)
index 59238c659fe72961261300aa44ad093c501139a3..9435d855e56fa5f516bc98dedc71562e17f544be 100644 (file)
@@ -1,11 +1,54 @@
-drop table if exists users;
-create table users (
-context VARCHAR(80) NOT NULL,
-mailbox VARCHAR(80) NOT NULL,
-password VARCHAR(80) NOT NULL DEFAULT '',
-fullname VARCHAR(80) NOT NULL DEFAULT '',
-email VARCHAR(80) NOT NULL DEFAULT '',
-pager VARCHAR(80) NOT NULL DEFAULT '',
-options VARCHAR(160) NOT NULL DEFAULT '',
-PRIMARY KEY (context, mailbox)
+DROP TABLE IF EXISTS voicemail;
+CREATE TABLE voicemail (
+       -- All of these column names are very specific, including "uniqueid".  Do not change them if you wish voicemail to work.
+       uniqueid INT(5) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+       -- Mailbox context.
+       context CHAR(80) NOT NULL DEFAULT 'default',
+       -- Mailbox number.  Should be numeric.
+       mailbox CHAR(80) NOT NULL,
+       -- Must be numeric.  Negative if you don't want it to be changed from VoicemailMain
+       password CHAR(80) NOT NULL,
+       -- Used in email and for Directory app
+       fullname CHAR(80),
+       -- Email address (will get sound file if attach=yes)
+       email CHAR(80),
+       -- Email address (won't get sound file)
+       pager CHAR(80),
+       -- Attach sound file to email - YES/no
+       attach CHAR(3),
+       -- Send email from this address
+       serveremail CHAR(80),
+       -- Prompts in alternative language
+       language CHAR(20),
+       -- Alternative timezone, as defined in voicemail.conf
+       tz CHAR(30),
+       -- Delete voicemail from server after sending email notification - yes/NO
+       deletevoicemail CHAR(3),
+       -- Read back CallerID information during playback - yes/NO
+       saycid CHAR(3),
+       -- Allow user to send voicemail from within VoicemailMain - YES/no
+       sendvoicemail CHAR(3),
+       -- Listen to voicemail and approve before sending - yes/NO
+       review CHAR(3),
+       -- Allow '0' to jump out during greeting - yes/NO
+       operator CHAR(3),
+       -- Hear date/time of message within VoicemailMain - YES/no
+       envelope CHAR(3),
+       -- Hear length of message within VoicemailMain - yes/NO
+       sayduration CHAR(3),
+       -- Minimum duration in minutes to say
+       saydurationm INT(3),
+       -- Force new user to record name when entering voicemail - yes/NO
+       forcename CHAR(3),
+       -- Force new user to record greetings when entering voicemail - yes/NO
+       forcegreetings CHAR(3),
+       -- Context in which to dial extension for callback
+       callback CHAR(80),
+       -- Context in which to dial extension (from advanced menu)
+       dialout CHAR(80),
+       -- Context in which to execute 0 or * escape during greeting
+       exitcontext CHAR(80),
+       -- Maximum messages in a folder (100 if not specified)
+       maxmsg INT(5),
+       stamp timestamp
 );
diff --git a/doc/voicemail_odbc_postgresql.txt b/doc/voicemail_odbc_postgresql.txt
new file mode 100644 (file)
index 0000000..98a8af7
--- /dev/null
@@ -0,0 +1,436 @@
+GETTING ODBC STORAGE WITH POSTGRESQL WORKING WITH VOICEMAIL
+
+
+1) Install PostgreSQL, PostgreSQL-devel, unixODBC, and unixODBC-devel, and
+PostgreSQL-ODBC.  Make sure PostgreSQL is listening on a TCP socket, and that
+you are using md5 authentication for the database user.  The line in my
+pg_hba.conf looks like:
+
+# "local" is for Unix domain socket connections only
+local   jsmith2     jsmith2                           md5
+local   all         all                               ident sameuser
+# IPv4 local connections:
+host    all         all         127.0.0.1/32          md5
+
+
+2) Make sure you have the PostgreSQL odbc driver setup in /etc/odbcinst.ini.
+Mine looks like:
+
+[PostgreSQL]
+Description     = ODBC for PostgreSQL
+Driver          = /usr/lib/libodbcpsql.so
+Setup           = /usr/lib/libodbcpsqlS.so
+FileUsage       = 1
+
+You can confirm that unixODBC is seeing the driver by typing:
+
+[jsmith2@localhost tmp]$ odbcinst -q -d
+[PostgreSQL]
+
+
+3) Setup a DSN in /etc/odbc.ini, pointing at the PostgreSQL database and
+driver.  Mine looks like:
+
+[testing]
+Description           = ODBC Testing
+Driver                = PostgreSQL
+Trace                 = No
+TraceFile             = sql.log
+Database              = jsmith2
+Servername            = 127.0.0.1
+UserName              = jsmith2
+Password              = supersecret
+Port                  = 5432
+ReadOnly              = No
+RowVersioning         = No
+ShowSystemTables      = No
+ShowOidColumn         = No
+FakeOidIndex          = No
+ConnSettings          =
+
+You can confirm that unixODBC sees your DSN by typing:
+
+[jsmith2@localhost tmp]$ odbcinst -q -s
+[testing]
+
+
+4) Test your database connectivity through ODBC.  If this doesn't work,
+something is wrong with your ODBC setup.
+
+[jsmith2@localhost tmp]$ echo "select 1" | isql -v testing
++---------------------------------------+
+| Connected!                            |
+|                                       |
+| sql-statement                         |
+| help [tablename]                      |
+| quit                                  |
+|                                       |
++---------------------------------------+
+SQL> +------------+
+| ?column?   |
++------------+
+| 1          |
++------------+
+SQLRowCount returns 1
+1 rows fetched
+
+If your ODBC connectivity to PostgreSQL isn't working, you'll see an error
+message instead, like this:
+
+[jsmith2@localhost tmp]$ echo "select 1" | isql -v testing
+[S1000][unixODBC]Could not connect to the server;
+Could not connect to remote socket.
+[ISQL]ERROR: Could not SQLConnect
+bash: echo: write error: Broken pipe
+
+5) Compile Asterisk with support for ODBC voicemail.  Go to your Asterisk
+source directory and edit apps/Makefile, and uncomment the two lines as shown
+below:
+
+#
+# If you have UnixODBC you can use ODBC voicemail
+# storage
+#
+# Uncomment to use ODBC storage
+CFLAGS+=-DUSE_ODBC_STORAGE
+# Uncomment for extended ODBC voicemail storage
+CFLAGS+=-DEXTENDED_ODBC_STORAGE
+# See doc/README.odbcstorage for more information
+
+Recompile Asterisk and install the new version.
+
+
+6) Once you've recompiled and re-installed Asterisk, check to make sure
+res_odbc.so has been compiled.
+
+localhost*CLI> show modules like res_odbc.so
+Module                         Description                              Use Count 
+res_odbc.so                    ODBC Resource                            0         
+1 modules loaded
+
+
+7) Now it's time to get Asterisk configured.  First, we need to tell Asterisk
+about our ODBC setup.  Open /etc/asterisk/res_odbc.conf and add the following:
+
+[postgres]
+enabled => yes
+dsn => testing
+pre-connect => yes
+
+8) At the Asterisk CLI, unload and then load the res_odbc.so module.  (You
+could restart Asterisk as well, but this way makes it easier to tell what's
+happening.)  Notice how it says it's connected to "postgres", which is our ODBC
+connection as defined in res_odbc.conf, which points to the "testing" DSN in
+ODBC.
+
+localhost*CLI> unload res_odbc.so
+Jan  2 21:19:36 WARNING[8130]: res_odbc.c:498 odbc_obj_disconnect: res_odbc: disconnected 0 from postgres [testing]
+Jan  2 21:19:36 NOTICE[8130]: res_odbc.c:589 unload_module: res_odbc unloaded.
+localhost*CLI> load res_odbc.so
+ Loaded /usr/lib/asterisk/modules/res_odbc.so => (ODBC Resource)
+  == Parsing '/etc/asterisk/res_odbc.conf': Found
+Jan  2 21:19:40 NOTICE[8130]: res_odbc.c:266 load_odbc_config: Adding ENV var: INFORMIXSERVER=my_special_database
+Jan  2 21:19:40 NOTICE[8130]: res_odbc.c:266 load_odbc_config: Adding ENV var: INFORMIXDIR=/opt/informix
+Jan  2 21:19:40 NOTICE[8130]: res_odbc.c:295 load_odbc_config: registered database handle 'postgres' dsn->[testing]
+Jan  2 21:19:40 NOTICE[8130]: res_odbc.c:555 odbc_obj_connect: Connecting postgres
+Jan  2 21:19:40 NOTICE[8130]: res_odbc.c:570 odbc_obj_connect: res_odbc: Connected to postgres [testing]
+Jan  2 21:19:40 NOTICE[8130]: res_odbc.c:600 load_module: res_odbc loaded.
+
+You can also check the status of your ODBC connection at any time from the
+Asterisk CLI:
+
+localhost*CLI> odbc show
+Name: postgres 
+DSN: testing
+Connected: yes
+
+9) Now we can setup our voicemail table in PostgreSQL.  Log into PostgreSQL and
+type (or copy and paste) the following:
+
+--
+-- First, let's create our large object type, called "lo"
+--
+CREATE FUNCTION loin (cstring) RETURNS lo AS 'oidin' LANGUAGE internal IMMUTABLE STRICT;
+CREATE FUNCTION loout (lo) RETURNS cstring AS 'oidout' LANGUAGE internal IMMUTABLE STRICT;
+CREATE FUNCTION lorecv (internal) RETURNS lo AS 'oidrecv' LANGUAGE internal IMMUTABLE STRICT;
+CREATE FUNCTION losend (lo) RETURNS bytea AS 'oidrecv' LANGUAGE internal IMMUTABLE STRICT;
+
+CREATE TYPE lo ( INPUT = loin, OUTPUT = loout, RECEIVE = lorecv, SEND = losend, INTERNALLENGTH = 4, PASSEDBYVALUE );
+CREATE CAST (lo AS oid) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (oid AS lo) WITHOUT FUNCTION AS IMPLICIT;
+
+--
+-- If we're not already using plpgsql, then let's use it!
+--
+CREATE TRUSTED LANGUAGE plpgsql;
+
+--
+-- Next, let's create a trigger to cleanup the large object table
+-- whenever we update or delete a row from the voicemessages table
+--
+
+CREATE FUNCTION vm_lo_cleanup() RETURNS "trigger"
+    AS $$
+    declare
+      msgcount INTEGER;
+    begin
+      --    raise notice 'Starting lo_cleanup function for large object with oid %',old.recording;
+      -- If it is an update action but the BLOB (lo) field was not changed, dont do anything
+      if (TG_OP = 'UPDATE') then
+        if ((old.recording = new.recording) or (old.recording is NULL)) then
+          raise notice 'Not cleaning up the large object table, as recording has not changed';
+          return new;
+        end if;
+      end if;
+      if (old.recording IS NOT NULL) then
+        SELECT INTO msgcount COUNT(*) AS COUNT FROM voicemessages WHERE recording = old.recording;
+        if (msgcount > 0) then
+          raise notice 'Not deleting record from the large object table, as object is still referenced';
+          return new;
+        else
+          perform lo_unlink(old.recording);
+          if found then
+            raise notice 'Cleaning up the large object table';
+            return new;
+          else
+            raise exception 'Failed to cleanup the large object table';
+            return old;
+          end if;
+        end if;
+      else
+        raise notice 'No need to cleanup the large object table, no recording on old row';
+        return new;
+      end if;
+    end$$
+    LANGUAGE plpgsql;
+
+--
+-- Now, let's create our voicemessages table
+-- This is what holds the voicemail from Asterisk
+--
+
+CREATE TABLE voicemessages
+(
+  uniqueid serial PRIMARY KEY,
+  msgnum int4,
+  dir varchar(80),
+  context varchar(80),
+  macrocontext varchar(80),
+  callerid varchar(40),
+  origtime varchar(40),
+  duration varchar(20),
+  mailboxuser varchar(80),
+  mailboxcontext varchar(80),
+  recording lo,
+  label varchar(30),
+  "read" bool DEFAULT false
+);
+
+--
+-- Let's not forget to make the voicemessages table use the trigger
+--
+
+CREATE TRIGGER vm_cleanup AFTER DELETE OR UPDATE ON voicemessages FOR EACH ROW EXECUTE PROCEDURE vm_lo_cleanup();
+
+
+10) Just as a sanity check, make sure you check the voicemessages table via the
+isql utility.
+
+[jsmith2@localhost ODBC]$ echo "SELECT id, msgnum, dir, duration FROM voicemessages WHERE msgnum = 1" | isql testing
++---------------------------------------+
+| Connected!                            |
+|                                       |
+| sql-statement                         |
+| help [tablename]                      |
+| quit                                  |
+|                                       |
++---------------------------------------+
+SQL> +------------+------------+---------------------------------------------------------------------------------+---------------------+
+| id         | msgnum     | dir                                                                             | duration            |
++------------+------------+---------------------------------------------------------------------------------+---------------------+
++------------+------------+---------------------------------------------------------------------------------+---------------------+
+SQLRowCount returns 0
+
+
+11) Now we can finally configure voicemail in Asterisk to use our database.
+Open /etc/asterisk/voicemail.conf, and look in the [general] section.  I've
+changed the format to gsm (as I can't seem to get WAV or wav working), and
+specify both the odbc connection and database table to use.
+
+[general]
+; Default formats for writing Voicemail
+;format=g723sf|wav49|wav
+format=gsm
+odbcstorage=postgres
+odbctable=voicemessages
+
+You'll also want to create a new voicemail context called "odbctest" to do some
+testing, and create a sample mailbox inside that context.  Add the following to
+the very bottom of voicemail.conf:
+
+[odbctest]
+101 => 5555,Example Mailbox
+
+
+12) Once you've updated voicemail.conf, let's make the changes take effect:
+
+localhost*CLI> unload app_voicemail.so
+  == Unregistered application 'VoiceMail'
+  == Unregistered application 'VoiceMailMain'
+  == Unregistered application 'MailboxExists'
+  == Unregistered application 'VMAuthenticate'
+localhost*CLI> load app_voicemail.so
+ Loaded /usr/lib/asterisk/modules/app_voicemail.so => (Comedian Mail (Voicemail System))
+  == Registered application 'VoiceMail'
+  == Registered application 'VoiceMailMain'
+  == Registered application 'MailboxExists'
+  == Registered application 'VMAuthenticate'
+  == Parsing '/etc/asterisk/voicemail.conf': Found
+
+You can check to make sure your new mailbox exists by typing:
+
+localhost*CLI> show voicemail users for odbctest 
+Context    Mbox  User                      Zone       NewMsg
+odbctest   101   Example Mailbox                           0
+
+
+13) Now, let's add a new context called "odbc" to extensions.conf.  We'll use
+these extensions to do some testing:
+
+[odbc]
+exten => 100,1,Voicemail(101@odbctest)
+exten => 200,1,VoicemailMain(101@odbctest)
+
+
+14) Next, we need to point a phone at the odbc context.  In my case, I've got a
+SIP phone called "linksys" that is registering to Asterisk, so I'm setting its
+context to the [odbc] context we created in the previous step.  The relevant
+section of my sip.conf file looks like:
+
+[linksys]
+type=friend
+secret=verysecret
+disallow=all
+allow=ulaw
+allow=gsm
+context=odbc
+host=dynamic
+qualify=yes
+
+I can check to see that my linksys phone is registered with Asterisk correctly:
+
+localhost*CLI> sip show peers like linksys
+Name/username              Host            Dyn Nat ACL Port     Status    
+linksys/linksys            192.168.0.103    D          5060     OK (9 ms) 
+1 sip peers [1 online , 0 offline]
+
+
+15) At last, we're finally ready to leave a voicemail message and have it
+stored in our database!  (Who'd have guessed it would be this much trouble?!?)
+Pick up the phone, dial extension 100, and leave yourself a voicemail message.
+In my case, this is what appeared on the Asterisk CLI:
+
+localhost*CLI> 
+    -- Executing VoiceMail("SIP/linksys-10228cac", "101@odbctest") in new stack
+    -- Playing 'vm-intro' (language 'en')
+    -- Playing 'beep' (language 'en')
+    -- Recording the message
+    -- x=0, open writing:  /var/spool/asterisk/voicemail/odbctest/101/tmp/dlZunm format: gsm, 0x101f6534
+    -- User ended message by pressing #
+    -- Playing 'auth-thankyou' (language 'en')
+  == Parsing '/var/spool/asterisk/voicemail/odbctest/101/INBOX/msg0000.txt': Found
+
+Now, we can check the database and make sure the record actually made it into
+PostgreSQL, from within the psql utility.
+
+[jsmith2@localhost ~]$ psql
+Password: 
+Welcome to psql 8.1.4, the PostgreSQL interactive terminal.
+
+Type:  \copyright for distribution terms
+       \h for help with SQL commands
+       \? for help with psql commands
+       \g or terminate with semicolon to execute query
+       \q to quit
+
+jsmith2=# SELECT * FROM voicemessages;
+ id | msgnum |                       dir                        | context | macrocontext |       callerid        |  origtime  | duration | mailboxuser | mailboxcontext | recording | label | read | sip_id | pabx_id | iax_id 
+----+--------+--------------------------------------------------+---------+--------------+-----------------------+------------+----------+-------------+----------------+-----------+-------+------+--------+---------+--------
+ 26 |      0 | /var/spool/asterisk/voicemail/odbctest/101/INBOX | odbc    |              | "linksys" <linksys> | 1167794179 | 7        | 101         | odbctest       | 16599     |       | f    |        |         |       
+(1 row)
+
+Did you notice the the recording column is just a number?  When a recording
+gets stuck in the database, the audio isn't actually stored in the
+voicemessages table.  It's stored in a system table called the large object
+table.  We can look in the large object table and verify that the object
+actually exists there:
+
+jsmith2=# \lo_list
+    Large objects
+  ID   | Description 
+-------+-------------
+ 16599 | 
+(1 row)
+
+In my case, the OID is 16599.  Your OID will almost surely be different.  Just
+make sure the OID number in the recording column in the voicemessages table
+corresponds with a record in the large object table.  (The trigger we added to
+our voicemessages table was designed to make sure this is always the case.)
+
+We can also pull a copy of the voicemail message back out of the database and
+write it to a file, to help us as we debug things:
+
+jsmith2=# \lo_export 16599 /tmp/odcb-16599.gsm
+lo_export
+
+We can even listen to the file from the Linux command line:
+
+[jsmith2@localhost tmp]$ play /tmp/odcb-16599.gsm
+
+Input Filename : /tmp/odcb-16599.gsm
+Sample Size    : 8-bits
+Sample Encoding: gsm
+Channels       : 1
+Sample Rate    : 8000
+
+Time: 00:06.22 [00:00.00] of 00:00.00 (  0.0%) Output Buffer: 298.36K
+
+Done.
+
+
+16) Last but not least, we can pull the voicemail message back out of the
+database by dialing extension 200 and entering "5555" at the password prompt.
+You should see something like this on the Asterisk CLI:
+
+localhost*CLI> 
+    -- Executing VoiceMailMain("SIP/linksys-10228cac", "101@odbctest") in new stack
+    -- Playing 'vm-password' (language 'en')
+    -- Playing 'vm-youhave' (language 'en')
+    -- Playing 'digits/1' (language 'en')
+    -- Playing 'vm-INBOX' (language 'en')
+    -- Playing 'vm-message' (language 'en')
+    -- Playing 'vm-onefor' (language 'en')
+    -- Playing 'vm-INBOX' (language 'en')
+    -- Playing 'vm-messages' (language 'en')
+    -- Playing 'vm-opts' (language 'en')
+    -- Playing 'vm-first' (language 'en')
+    -- Playing 'vm-message' (language 'en')
+  == Parsing '/var/spool/asterisk/voicemail/odbctest/101/INBOX/msg0000.txt': Found
+    -- Playing 'vm-received' (language 'en')
+    -- Playing 'digits/at' (language 'en')
+    -- Playing 'digits/10' (language 'en')
+    -- Playing 'digits/16' (language 'en')
+    -- Playing 'digits/p-m' (language 'en')
+    -- Playing '/var/spool/asterisk/voicemail/odbctest/101/INBOX/msg0000' (language 'en')
+    -- Playing 'vm-advopts' (language 'en')
+    -- Playing 'vm-repeat' (language 'en')
+    -- Playing 'vm-delete' (language 'en')
+    -- Playing 'vm-toforward' (language 'en')
+    -- Playing 'vm-savemessage' (language 'en')
+    -- Playing 'vm-helpexit' (language 'en')
+    -- Playing 'vm-goodbye' (language 'en')
+
+That's it!
+
+Jared Smith
+2 Jan 2006
index b1eb6f16c547ad258346be40f914ddc63fe65fd1..41d2d30c232290f46cfbe9693a83e844e63d22c6 100644 (file)
@@ -1774,6 +1774,8 @@ static int park_exec(struct ast_channel *chan, void *data)
                        ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
 
                memset(&config, 0, sizeof(struct ast_bridge_config));
+               ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
+               ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
                res = ast_bridge_call(chan, peer, &config);
 
                /* Simulate the PBX hanging up */
index db125d9e6991716cc5b986f5660c67364a35e88c..e620d27be9c60e1ff9baa195cc926d495e3c09fb 100644 (file)
@@ -56,6 +56,7 @@
 #include "tzfile.h"
 #include "asterisk/lock.h"
 #include "asterisk/localtime.h"
+#include "asterisk/strings.h"
 
 
 #ifndef lint
@@ -1051,7 +1052,7 @@ const char * const        zone;
 #ifdef _THREAD_SAFE
        ast_mutex_lock(&lcl_mutex);
 #endif
-       ast_tzset(zone);
+       ast_tzset(ast_strlen_zero(zone) ? "/etc/localtime" : zone);
        localsub(timep, 0L, p_tm, zone);
 #ifdef _THREAD_SAFE
        ast_mutex_unlock(&lcl_mutex);
@@ -1495,8 +1496,8 @@ const char * const        zone;
 #ifdef _THREAD_SAFE
        ast_mutex_lock(&lcl_mutex);
 #endif
-       ast_tzset(zone);
-       mktime_return_value = time1(tmp, localsub, 0L, zone);
+       ast_tzset(!ast_strlen_zero(zone) ? zone : "/etc/localtime");
+       mktime_return_value = time1(tmp, localsub, 0L, !ast_strlen_zero(zone) ? zone : "/etc/localtime");
 #ifdef _THREAD_SAFE
        ast_mutex_unlock(&lcl_mutex);
 #endif
diff --git a/utils.c b/utils.c
index e712ebe665cc9f30d44b02237951c0dea82546aa..6b3680b8fa29bb5254af16d7df5b0537e4cdb644 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -520,7 +520,7 @@ char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
        char *q;
 
        s = ast_strip(s);
-       if ((q = strchr(beg_quotes, *s))) {
+       if ((q = strchr(beg_quotes, *s)) && *q != '\0') {
                e = s + strlen(s) - 1;
                if (*e == *(end_quotes + (q - beg_quotes))) {
                        s++;