diff --git a/cdr.c b/cdr.c index 20b3e2cfaaad5b89bb23d4e45dba2cd1aa67f801..3cbaac47ee8fcfe0b1069b3bb576232ffffdf24f 100755 --- a/cdr.c +++ b/cdr.c @@ -19,6 +19,7 @@ #include <asterisk/cdr.h> #include <asterisk/logger.h> #include <asterisk/callerid.h> +#include <asterisk/causes.h> #include <unistd.h> #include <stdlib.h> #include <string.h> @@ -163,6 +164,41 @@ void ast_cdr_busy(struct ast_cdr *cdr) } } +void ast_cdr_failed(struct ast_cdr *cdr) +{ + char *chan; + if (cdr) { + chan = strlen(cdr->channel) ? cdr->channel : "<unknown>"; + if (cdr->posted) + ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan); + cdr->disposition = AST_CDR_FAILED; + } +} + +int ast_cdr_disposition(struct ast_cdr *cdr, int cause) +{ + int res = 0; + if (cdr) { + switch(cause) { + case AST_CAUSE_BUSY: + ast_cdr_busy(cdr); + break; + case AST_CAUSE_FAILURE: + ast_cdr_failed(cdr); + break; + case AST_CAUSE_NORMAL: + break; + case AST_CAUSE_NOTDEFINED: + res = -1; + break; + default: + res = -1; + ast_log(LOG_WARNING, "We don't handle that cause yet\n"); + } + } + return res; +} + void ast_cdr_setdestchan(struct ast_cdr *cdr, char *chann) { char *chan; @@ -275,6 +311,8 @@ char *ast_cdr_disp2str(int disposition) switch (disposition) { case AST_CDR_NOANSWER: return "NO ANSWER"; + case AST_CDR_FAILED: + return "FAILED"; case AST_CDR_BUSY: return "BUSY"; case AST_CDR_ANSWERED: @@ -313,11 +351,15 @@ int ast_cdr_update(struct ast_channel *c) char *name, *num; char tmp[AST_MAX_EXTENSION] = ""; /* Grab source from ANI or normal Caller*ID */ + if (!cdr) { + ast_log(LOG_NOTICE, "The cdr pointer is not set\n"); + return -1; + } if (c->ani) strncpy(tmp, c->ani, sizeof(tmp) - 1); - else if (c->callerid) + else if (c->callerid && strlen(c->callerid)) strncpy(tmp, c->callerid, sizeof(tmp) - 1); - if (c->callerid) + if (c->callerid && strlen(c->callerid)) strncpy(cdr->clid, c->callerid, sizeof(cdr->clid) - 1); else strcpy(cdr->clid, ""); diff --git a/channel.c b/channel.c index 2ecde4feefa9afe9c6e498fff229ed3bd3df4343..6d704d742408db5aae48aa50d57e0c0f91d2f3a1 100755 --- a/channel.c +++ b/channel.c @@ -34,6 +34,7 @@ #include <asterisk/linkedlists.h> #include <asterisk/indications.h> #include <asterisk/monitor.h> +#include <asterisk/causes.h> #ifdef ZAPTEL_OPTIMIZATIONS #include <sys/ioctl.h> #include <linux/zaptel.h> @@ -1493,8 +1494,7 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int int state = 0; struct ast_channel *chan; struct ast_frame *f; - int res; - + int res = 0; chan = ast_request(type, format, data); if (chan) { if (callerid) @@ -1504,8 +1504,6 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int res = ast_waitfor(chan, timeout); if (res < 0) { /* Something not cool, or timed out */ - ast_hangup(chan); - chan = NULL; break; } /* If done, break out */ @@ -1516,8 +1514,7 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int f = ast_read(chan); if (!f) { state = AST_CONTROL_HANGUP; - ast_hangup(chan); - chan = NULL; + res = 0; break; } if (f->frametype == AST_FRAME_CONTROL) { @@ -1537,17 +1534,36 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int } ast_frfree(f); } - } else { - ast_hangup(chan); - chan = NULL; + } else ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); - } } else ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); if (chan && (chan->_state == AST_STATE_UP)) state = AST_CONTROL_ANSWER; if (outstate) *outstate = state; + if (chan && res <= 0) { + if (!chan->cdr) { + chan->cdr = ast_cdr_alloc(); + if (chan->cdr) + ast_cdr_init(chan->cdr, chan); + } + if (chan->cdr) { + char tmp[256]; + sprintf(tmp, "%s/%s",type,(char *)data); + ast_cdr_setapp(chan->cdr,"Dial",tmp); + ast_cdr_update(chan); + ast_cdr_start(chan->cdr); + ast_cdr_end(chan->cdr); + /* If the cause wasn't handled properly */ + if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) + ast_cdr_failed(chan->cdr); + ast_cdr_reset(chan->cdr,1); + } else + ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); + ast_hangup(chan); + chan = NULL; + } return chan; } @@ -2431,4 +2447,3 @@ int ast_tonepair(struct ast_channel *chan, int freq1, int freq2, int duration, i return 0; } - diff --git a/channels/chan_zap.c b/channels/chan_zap.c index a0dded75b5b8110e1179c54c4cc862fa3e3385d0..284f70f435d7c33ed23df96d8d192ba31a7fd475 100755 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -36,6 +36,7 @@ #include <asterisk/dsp.h> #include <asterisk/astdb.h> #include <asterisk/manager.h> +#include <asterisk/causes.h> #include <sys/signal.h> #include <sys/select.h> #include <errno.h> @@ -498,6 +499,23 @@ static int cidrings[] = { #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */) #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */) +/* translate between PRI causes and asterisk's */ +int hangup_pri2cause(int cause) +{ + switch(cause) { +#ifdef ZAPATA_PRI + case PRI_CAUSE_USER_BUSY: + return AST_CAUSE_BUSY; + case PRI_CAUSE_NORMAL_CLEARING: + return AST_CAUSE_NORMAL; +#endif + default: + return AST_CAUSE_FAILURE; + } + /* never reached */ + return 0; +} + static int zt_get_index(struct ast_channel *ast, struct zt_pvt *p, int nullok) { int res; @@ -6049,6 +6067,7 @@ static void *pri_dchannel(void *vpri) if (chan) { ast_mutex_lock(&pri->pvt[chan]->lock); if (pri->pvt[chan]->owner) { + pri->pvt[chan]->owner->hangupcause = hangup_pri2cause(e->hangup.cause); pri->pvt[chan]->owner->_softhangup |= AST_SOFTHANGUP_DEV; if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Channel %d, span %d got hangup\n", chan, pri->span); diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h index 0b9681035bfae9cc049191a074c3f1ad309efd2c..3988832df494bef45a059559c876656e0d0e21f5 100755 --- a/include/asterisk/cdr.h +++ b/include/asterisk/cdr.h @@ -23,6 +23,7 @@ #define AST_CDR_NOANSWER (1 << 0) #define AST_CDR_BUSY (1 << 1) #define AST_CDR_ANSWERED (1 << 2) +#define AST_CDR_FAILED (1 << 3) //! AMA Flags #define AST_CDR_OMIT (1) @@ -142,6 +143,21 @@ extern void ast_cdr_answer(struct ast_cdr *cdr); */ extern void ast_cdr_busy(struct ast_cdr *cdr); +//! Fail a call +/*! + * \param cdr the cdr you wish to associate with the call + * Returns nothing important + */ +extern void ast_cdr_failed(struct ast_cdr *cdr); + +//! Save the result of the call based on the AST_CAUSE_* +/*! + * \param cdr the cdr you wish to associate with the call + * Returns nothing important + * \param cause the AST_CAUSE_* + */ +extern int ast_cdr_disposition(struct ast_cdr *cdr, int cause); + //! End a call /*! * \param cdr the cdr you have associated the call with diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 815f882f471bb96dfac6b538e47b58c30190f122..f33bb62d321725191e62e7b6c552162cd61e3701 100755 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -213,6 +213,9 @@ struct ast_channel { /* Unique Channel Identifier */ char uniqueid[32]; + /* Why is the channel hanged up */ + int hangupcause; + /* A linked list for variables */ struct ast_var_t *vars; AST_LIST_HEAD(varshead,ast_var_t) varshead; diff --git a/pbx.c b/pbx.c index 5ad920948f63e2d33d60e554f4c83d09442cce72..8a7dd2fd7caaeab9d0e94390543e78dcf33fee2c 100755 --- a/pbx.c +++ b/pbx.c @@ -3779,7 +3779,7 @@ static void *async_wait(void *data) return NULL; } -int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char *context, char *exten, int priority, int *reason, int sync, char *callerid, char *variable ) +int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char *context, char *exten, int priority, int *reason, int sync, char *callerid, char *variable) { struct ast_channel *chan; struct async_stat *as; @@ -3828,6 +3828,27 @@ int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name); ast_hangup(chan); } + } else { + /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */ + /* check if "failed" exists */ + if (ast_exists_extension(chan, context, "failed", 1, NULL)) { + chan = ast_channel_alloc(0); + if (chan) { + strncpy(chan->name, "OutgoingSpoolFailed", sizeof(chan->name) - 1); + if (context && strlen(context)) + strncpy(chan->context, context, sizeof(chan->context) - 1); + strncpy(chan->exten, "failed", sizeof(chan->exten) - 1); + chan->priority = 1; + /* JDG chanvar */ + tmp = variable; + /* FIXME replace this call with strsep NOT*/ + while( (var = strtok_r(NULL, "|", &tmp)) ) { + pbx_builtin_setvar( chan, var ); + } /* /JDG */ + ast_pbx_run(chan); + } else + ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n"); + } } } else { as = malloc(sizeof(struct async_stat));