diff options
-rw-r--r-- | apps/app_voicemail.c | 9 | ||||
-rw-r--r-- | asterisk.c | 4 | ||||
-rw-r--r-- | channels/chan_h323.c | 2 | ||||
-rw-r--r-- | channels/chan_sip.c | 2 | ||||
-rw-r--r-- | channels/chan_zap.c | 923 | ||||
-rw-r--r-- | contrib/scripts/vmdb.sql | 63 | ||||
-rw-r--r-- | doc/voicemail_odbc_postgresql.txt | 436 | ||||
-rw-r--r-- | res/res_features.c | 2 | ||||
-rw-r--r-- | stdtime/localtime.c | 7 | ||||
-rw-r--r-- | utils.c | 2 |
10 files changed, 1039 insertions, 411 deletions
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 4c49a2488..47896a0d6 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -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); diff --git a/asterisk.c b/asterisk.c index bc15eb5c7..d3b3989de 100644 --- a/asterisk.c +++ b/asterisk.c @@ -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; diff --git a/channels/chan_h323.c b/channels/chan_h323.c index b86d684c8..1b4a616a5 100644 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -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) { diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b088cba64..e54178fbe 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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. */ diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 73cc62741..e8a885791 100644 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -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) diff --git a/contrib/scripts/vmdb.sql b/contrib/scripts/vmdb.sql index 59238c659..9435d855e 100644 --- a/contrib/scripts/vmdb.sql +++ b/contrib/scripts/vmdb.sql @@ -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 index 000000000..98a8af7c3 --- /dev/null +++ b/doc/voicemail_odbc_postgresql.txt @@ -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 diff --git a/res/res_features.c b/res/res_features.c index b1eb6f16c..41d2d30c2 100644 --- a/res/res_features.c +++ b/res/res_features.c @@ -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 */ diff --git a/stdtime/localtime.c b/stdtime/localtime.c index db125d9e6..e620d27be 100644 --- a/stdtime/localtime.c +++ b/stdtime/localtime.c @@ -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 @@ -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++; |