Add distinguishing between BUSY and FAILURE for outgoing spool calls. Always save...
authorMartin Pycko <martinp@digium.com>
Fri, 12 Sep 2003 16:51:35 +0000 (16:51 +0000)
committerMartin Pycko <martinp@digium.com>
Fri, 12 Sep 2003 16:51:35 +0000 (16:51 +0000)
"failed" extension in the specified context (only if you use context,extension,priority syntax) and execute it.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1499 65c4cc65-6c06-0410-ace0-fbb531ad65f3

cdr.c
channel.c
channels/chan_zap.c
include/asterisk/cdr.h
include/asterisk/channel.h
pbx.c

diff --git a/cdr.c b/cdr.c
index 20b3e2c..3cbaac4 100755 (executable)
--- 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, "");
index 2ecde4f..6d704d7 100755 (executable)
--- 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;
 }
 
-
index a0dded7..284f70f 100755 (executable)
@@ -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);
index 0b96810..3988832 100755 (executable)
@@ -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
index 815f882..f33bb62 100755 (executable)
@@ -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 5ad9209..8a7dd2f 100755 (executable)
--- 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));