Index: asterisk-1.6.1-chancauses/apps/app_dial.c =================================================================== --- asterisk-1.6.1-chancauses.orig/apps/app_dial.c 2009-04-02 12:01:50.000000000 +0200 +++ asterisk-1.6.1-chancauses/apps/app_dial.c 2009-04-02 12:29:01.000000000 +0200 @@ -371,6 +371,12 @@ #define AST_MAX_WATCHERS 256 +#define _DETAILBUFSIZE 30 +struct cause_details { + char tech[_DETAILBUFSIZE]; + char cause[_DETAILBUFSIZE]; +}; + /* * argument to handle_cause() and other functions. */ @@ -379,23 +385,45 @@ int busy; int congestion; int nochan; + struct cause_details busy_details; + struct cause_details cong_details; + struct cause_details noch_details; }; -static void handle_cause(int cause, struct cause_args *num) +static void handle_cause(int cause, struct cause_args *num, struct ast_channel *c) { struct ast_cdr *cdr = num->chan->cdr; + const char *detail_tech = NULL; + const char *detail_cause = NULL; + + + detail_tech = pbx_builtin_getvar_helper(c, "HANGUP_TECH"); + if (detail_tech) { + char varname[_DETAILBUFSIZE + 7]; + snprintf(varname, sizeof(varname), "%s_CAUSE", detail_tech); + detail_cause = pbx_builtin_getvar_helper(c, varname); + } switch(cause) { case AST_CAUSE_BUSY: if (cdr) ast_cdr_busy(cdr); num->busy++; + if (detail_tech) + ast_copy_string((char *) num->busy_details.tech, detail_tech, sizeof(num->busy_details.tech)); + if (detail_cause) + ast_copy_string((char *) num->busy_details.cause, detail_cause, sizeof(num->busy_details.cause)); + break; case AST_CAUSE_CONGESTION: if (cdr) ast_cdr_failed(cdr); num->congestion++; + if (detail_tech) + ast_copy_string((char *) num->cong_details.tech, detail_tech, sizeof(num->cong_details.tech)); + if (detail_cause) + ast_copy_string((char *) num->cong_details.cause, detail_cause, sizeof(num->cong_details.cause)); break; case AST_CAUSE_NO_ROUTE_DESTINATION: @@ -403,6 +431,10 @@ if (cdr) ast_cdr_failed(cdr); num->nochan++; + if (detail_tech) + ast_copy_string((char *) num->noch_details.tech, detail_tech, sizeof(num->noch_details.tech)); + if (detail_cause) + ast_copy_string((char *) num->noch_details.cause, detail_cause, sizeof(num->noch_details.cause)); break; case AST_CAUSE_NORMAL_CLEARING: @@ -410,6 +442,10 @@ default: num->nochan++; + if (detail_tech) + ast_copy_string((char *) num->noch_details.tech, detail_tech, sizeof(num->noch_details.tech)); + if (detail_cause) + ast_copy_string((char *) num->noch_details.cause, detail_cause, sizeof(num->noch_details.cause)); break; } } @@ -525,7 +561,7 @@ } if (!c) { ast_clear_flag64(o, DIAL_STILLGOING); - handle_cause(cause, num); + handle_cause(cause, num, NULL); ast_hangup(original); } else { char *new_cid_num, *new_cid_name; @@ -580,6 +616,8 @@ char privcid[256]; char privintro[1024]; char status[256]; + char hangup_tech[_DETAILBUFSIZE]; + char hangup_cause[_DETAILBUFSIZE]; }; static struct ast_channel *wait_for_answer(struct ast_channel *in, @@ -626,12 +664,21 @@ if (pos == 1) { /* only the input channel is available */ if (numlines == (num.busy + num.congestion + num.nochan)) { ast_verb(2, "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan); - if (num.busy) + + if (num.busy) { strcpy(pa->status, "BUSY"); - else if (num.congestion) + ast_copy_string((char *) pa->hangup_tech, (char *) num.busy_details.tech, sizeof(pa->hangup_tech)); + ast_copy_string((char *) pa->hangup_cause, (char *) num.busy_details.cause, sizeof(pa->hangup_cause)); + } else if (num.congestion) { + ast_verbose("cong cause: %s\n", num.cong_details.cause); strcpy(pa->status, "CONGESTION"); - else if (num.nochan) + ast_copy_string((char *) pa->hangup_tech, (char *) num.cong_details.tech, sizeof(pa->hangup_tech)); + ast_copy_string((char *) pa->hangup_cause, (char *) num.cong_details.cause, sizeof(pa->hangup_cause)); + } else if (num.nochan) { strcpy(pa->status, "CHANUNAVAIL"); + ast_copy_string((char *) pa->hangup_tech, (char *) num.noch_details.tech, sizeof(pa->hangup_tech)); + ast_copy_string((char *) pa->hangup_cause, (char *) num.noch_details.cause, sizeof(pa->hangup_cause)); + } } else { ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan); } @@ -670,14 +717,47 @@ } f = ast_read(winner); if (!f) { + char tech[20] = ""; + char cause[20] = ""; in->hangupcause = c->hangupcause; #ifdef HAVE_EPOLL ast_poll_channel_del(in, c); #endif - ast_hangup(c); + handle_cause(in->hangupcause, &num, c); + ast_hangup_cause(c, tech, sizeof(tech), cause, sizeof(cause)); c = o->chan = NULL; ast_clear_flag64(o, DIAL_STILLGOING); - handle_cause(in->hangupcause, &num); + /*switch(in->hangupcause) { + case AST_CAUSE_BUSY: + num.busy++; + ast_copy_string((char *) num.busy_details.tech, tech, sizeof(num.busy_details.tech)); + ast_copy_string((char *) num.busy_details.cause, cause, sizeof(num.busy_details.cause)); + + break; + + case AST_CAUSE_CONGESTION: + num.congestion++; + ast_copy_string((char *) num.cong_details.tech, tech, sizeof(num.cong_details.tech)); + ast_copy_string((char *) num.cong_details.cause, cause, sizeof(num.cong_details.cause)); + break; + + case AST_CAUSE_NO_ROUTE_DESTINATION: + case AST_CAUSE_UNREGISTERED: + num.nochan++; + ast_copy_string((char *) num.noch_details.tech, tech, sizeof(num.noch_details.tech)); + ast_copy_string((char *) num.noch_details.cause, cause, sizeof(num.noch_details.cause)); + break; + + case AST_CAUSE_NORMAL_CLEARING: + break; + + default: + num.nochan++; + ast_copy_string((char *) num.noch_details.tech, tech, sizeof(num.noch_details.tech)); + ast_copy_string((char *) num.noch_details.cause, cause, sizeof(num.noch_details.cause)); + break; + }*/ + continue; } if (f->frametype == AST_FRAME_CONTROL) { @@ -709,20 +789,37 @@ c->hangupcause = AST_CAUSE_NORMAL_CLEARING; break; case AST_CONTROL_BUSY: - ast_verb(3, "%s is busy\n", c->name); - in->hangupcause = c->hangupcause; - ast_hangup(c); - c = o->chan = NULL; - ast_clear_flag64(o, DIAL_STILLGOING); - handle_cause(AST_CAUSE_BUSY, &num); + { + char tech[20] = ""; + char cause[20] = ""; + + ast_verb(3, "%s is busy\n", c->name); + in->hangupcause = c->hangupcause; + handle_cause(AST_CAUSE_BUSY, &num, c); + + ast_hangup_cause(c, tech, sizeof(tech), cause, sizeof(cause)); + + c = o->chan = NULL; + ast_clear_flag64(o, DIAL_STILLGOING); + + ast_copy_string(num.busy_details.tech, tech, sizeof(num.busy_details.tech)); + ast_copy_string(num.busy_details.cause, cause, sizeof(num.busy_details.cause)); + } break; case AST_CONTROL_CONGESTION: - ast_verb(3, "%s is circuit-busy\n", c->name); - in->hangupcause = c->hangupcause; - ast_hangup(c); - c = o->chan = NULL; - ast_clear_flag64(o, DIAL_STILLGOING); - handle_cause(AST_CAUSE_CONGESTION, &num); + { + char tech[20] = ""; + char cause[20] = ""; + ast_verb(3, "%s is circuit-busy\n", c->name); + in->hangupcause = c->hangupcause; + handle_cause(AST_CAUSE_CONGESTION, &num, c); + ast_hangup_cause(c, tech, sizeof(tech), cause, sizeof(cause)); + c = o->chan = NULL; + ast_clear_flag64(o, DIAL_STILLGOING); + + ast_copy_string(num.cong_details.tech, tech, sizeof(num.cong_details.tech)); + ast_copy_string(num.cong_details.cause, cause, sizeof(num.cong_details.cause)); + } break; case AST_CONTROL_RINGING: ast_verb(3, "%s is ringing\n", c->name); @@ -1304,7 +1401,7 @@ struct chanlist *outgoing = NULL; /* list of destinations */ struct ast_channel *peer; int to; /* timeout */ - struct cause_args num = { chan, 0, 0, 0 }; + struct cause_args num = { chan, 0, 0, 0, { "", ""}, { "", ""}, { "", ""} }; int cause; char numsubst[256]; char cidname[AST_MAX_EXTENSION] = ""; @@ -1517,7 +1614,7 @@ /* If we can't, just go on to the next call */ ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n", tech, cause, ast_cause2str(cause)); - handle_cause(cause, &num); + handle_cause(cause, &num, NULL); if (!rest) /* we are on the last destination */ chan->hangupcause = cause; ast_free(tmp); @@ -1650,6 +1747,9 @@ if (!ast_channel_datastore_remove(chan, datastore)) ast_datastore_free(datastore); if (!peer) { + char *detail_tech = pa.hangup_tech; + char *detail_cause = pa.hangup_cause; + if (result) { res = result; } else if (to) { /* Musta gotten hung up */ @@ -1658,6 +1758,14 @@ res = 0; } + if (detail_tech && detail_tech[0]) { + char varname[_DETAILBUFSIZE + 7]; + snprintf(varname, sizeof(varname), "%s_CAUSE", detail_tech); + pbx_builtin_setvar_helper(chan, "HANGUP_TECH", detail_tech); + pbx_builtin_setvar_helper(chan, varname, detail_cause); + + } + /* SIP, in particular, sends back this error code to indicate an * overlap dialled number needs more digits. */ if (chan->hangupcause == AST_CAUSE_INVALID_NUMBER_FORMAT) { Index: asterisk-1.6.1-chancauses/channels/chan_local.c =================================================================== --- asterisk-1.6.1-chancauses.orig/channels/chan_local.c 2009-04-02 12:01:47.000000000 +0200 +++ asterisk-1.6.1-chancauses/channels/chan_local.c 2009-04-02 12:28:12.000000000 +0200 @@ -538,6 +538,9 @@ return -1; } + ast_log(LOG_ERROR, "old language: %s\n", p->owner->language); + ast_log(LOG_ERROR, "new language: %s\n", p->chan->language); + /* copy the channel variables from the incoming channel to the outgoing channel */ /* Note that due to certain assumptions, they MUST be in the same order */ AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { @@ -592,8 +595,20 @@ ast_mutex_lock(&p->lock); } if (p->owner) { + const char *hangup_tech = pbx_builtin_getvar_helper(ast, "HANGUP_TECH"); + const char *hangup_cause = NULL; pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); + //p->owner->hangupcause = ast->hangupcause; + if (hangup_tech) { + char varname[strlen(hangup_tech) + 7]; + snprintf(varname, sizeof(varname), "%s_CAUSE", hangup_tech); + hangup_cause = pbx_builtin_getvar_helper(ast, varname); + pbx_builtin_setvar_helper(p->owner, "HANGUP_TECH", hangup_tech); + pbx_builtin_setvar_helper(p->owner, varname, hangup_cause); + } ast_channel_unlock(p->owner); + } else { + ast_verbose("not setting CHANLOCALSTATUS\n"); } } p->chan = NULL; @@ -606,6 +621,15 @@ DEADLOCK_AVOIDANCE(&p->lock); } if (p->chan) { + const char *hangup_tech = pbx_builtin_getvar_helper(p->chan, "HANGUP_TECH"); + const char *hangup_cause = NULL; + if (hangup_tech) { + char varname[strlen(hangup_tech) + 7]; + snprintf(varname, sizeof(varname), "%s_CAUSE", hangup_tech); + hangup_cause = pbx_builtin_getvar_helper(p->chan, varname); + pbx_builtin_setvar_helper(ast, "HANGUP_TECH", hangup_tech); + pbx_builtin_setvar_helper(ast, varname, hangup_cause); + } ast_queue_hangup(p->chan); ast_channel_unlock(p->chan); } @@ -637,8 +661,10 @@ if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) /* Need to actually hangup since there is no PBX */ ochan = p->chan; - else + else { + ast_verbose("calling local_queue_frame\n"); res = local_queue_frame(p, isoutbound, &f, NULL, 1); + } if (!res) ast_mutex_unlock(&p->lock); if (ochan) Index: asterisk-1.6.1-chancauses/channels/chan_sip.c =================================================================== --- asterisk-1.6.1-chancauses.orig/channels/chan_sip.c 2009-04-02 12:01:58.000000000 +0200 +++ asterisk-1.6.1-chancauses/channels/chan_sip.c 2009-04-02 12:27:49.000000000 +0200 @@ -1755,6 +1755,7 @@ static int temp_pvt_init(void *); static void temp_pvt_cleanup(void *); +static void set_sip_error(struct ast_channel *c, unsigned int cause, const char *rest); /*! \brief A per-thread temporary pvt structure */ AST_THREADSTORAGE_CUSTOM(ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup); @@ -5251,8 +5252,13 @@ } } else { /* Incoming call, not up */ const char *res; - if (p->hangupcause && (res = hangup_cause2sip(p->hangupcause))) + const char *tech = pbx_builtin_getvar_helper(ast, "HANGUP_TECH"); + if (tech && !strcasecmp(tech, "SIP") && + (res = pbx_builtin_getvar_helper(ast, "SIP_CAUSE"))) { transmit_response_reliable(p, res, &p->initreq); + } else if (p->hangupcause && (res = hangup_cause2sip(p->hangupcause))) + transmit_response_reliable(p, res, &p->initreq); + else transmit_response_reliable(p, "603 Declined", &p->initreq); p->invitestate = INV_TERMINATED; @@ -16416,6 +16422,10 @@ sipmethod = find_sip_method(msg); + if (resp >= 400) { + set_sip_error(p->owner, resp, rest); + } + owner = p->owner; if (owner) owner->hangupcause = hangup_sip2cause(resp); @@ -21953,6 +21963,14 @@ return peer; } +static void set_sip_error(struct ast_channel *c, unsigned int cause, const char *rest) +{ + char causeString[20]; + snprintf(causeString, sizeof(causeString), "%d %s", cause, rest); + pbx_builtin_setvar_helper(c, "HANGUP_TECH", "SIP"); + pbx_builtin_setvar_helper(c, "SIP_CAUSE", causeString); +} + static int peer_markall_func(void *device, void *arg, int flags) { struct sip_peer *peer = device; Index: asterisk-1.6.1-chancauses/main/channel.c =================================================================== --- asterisk-1.6.1-chancauses.orig/main/channel.c 2009-04-02 12:01:43.000000000 +0200 +++ asterisk-1.6.1-chancauses/main/channel.c 2009-04-02 12:28:21.000000000 +0200 @@ -1580,9 +1580,14 @@ clonechan->rawreadformat = clonechan->nativeformats; } -/*! \brief Hangup a channel */ int ast_hangup(struct ast_channel *chan) { + return ast_hangup_cause(chan, NULL, 0, NULL, 0); +} + +/*! \brief Hangup a channel */ +int ast_hangup_cause(struct ast_channel *chan, char *hangup_tech, int tlen, char *hangup_cause, int clen) +{ int res = 0; /* Don't actually hang up a channel that will masquerade as someone else, or @@ -1672,6 +1677,21 @@ ast_cdr_detach(chan->cdr); chan->cdr = NULL; } + + if (hangup_cause && hangup_tech) { + const char *_t = pbx_builtin_getvar_helper(chan, "HANGUP_TECH"); + const char *_c; + char varname[20]; + + snprintf(varname, sizeof(varname), "%s_CAUSE", _t); + + _c = pbx_builtin_getvar_helper(chan, varname); + if (_c == NULL) _c = ""; + if (_t == NULL) _t = ""; + + ast_copy_string(hangup_tech, _t, tlen); + ast_copy_string(hangup_cause, _c, clen); + } ast_channel_free(chan); Index: asterisk-1.6.1-chancauses/include/asterisk/channel.h =================================================================== --- asterisk-1.6.1-chancauses.orig/include/asterisk/channel.h 2009-04-02 12:30:39.000000000 +0200 +++ asterisk-1.6.1-chancauses/include/asterisk/channel.h 2009-04-02 12:30:53.000000000 +0200 @@ -909,6 +909,7 @@ * \return Returns 0 on success, -1 on failure. */ int ast_hangup(struct ast_channel *chan); +int ast_hangup_cause(struct ast_channel *chan, char *hangup_tech, int tlen, char *hangup_cause, int clen); /*! * \brief Softly hangup up a channel