From b6aac885be2d1afbaf8524a81f1ef953213958d9 Mon Sep 17 00:00:00 2001 From: Jason Parker Date: Wed, 22 May 2013 18:11:57 +0000 Subject: Add dial events to app_queue and app_followme. Also fixes an issue in app_dial, where the channels were swapped on dial events. (closes issue ASTERISK-21551) (closes issue ASTERISK-21550) Review: https://reviewboard.asterisk.org/r/2549/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@389492 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_dial.c | 33 ++++++++++---------------- apps/app_followme.c | 21 +++++++++++++++++ apps/app_queue.c | 61 ++++++++++++++++++++++++++++++++++++++++--------- include/asterisk/dial.h | 5 ++++ main/dial.c | 7 ++---- 5 files changed, 90 insertions(+), 37 deletions(-) diff --git a/apps/app_dial.c b/apps/app_dial.c index 35c9ad8bf..b6f1ce872 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -66,8 +66,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/ccss.h" #include "asterisk/indications.h" #include "asterisk/framehook.h" -#include "asterisk/bridging.h" +#include "asterisk/dial.h" #include "asterisk/stasis_channels.h" +#include "asterisk/bridging.h" /*** DOCUMENTATION @@ -1014,9 +1015,15 @@ static void do_forward(struct chanlist *o, struct cause_args *num, num->nochan++; } else { ast_channel_lock_both(c, in); - ast_channel_publish_dial(c, in, stuff, NULL); + ast_channel_publish_dial(in, c, stuff, NULL); ast_channel_unlock(in); ast_channel_unlock(c); + + ast_channel_lock_both(original, in); + ast_channel_publish_dial(in, original, NULL, "CANCEL"); + ast_channel_unlock(in); + ast_channel_unlock(original); + /* Hangup the original channel now, in case we needed it */ ast_hangup(original); } @@ -1035,22 +1042,6 @@ struct privacy_args { char status[256]; }; -static const char *hangup_cause_to_dial_status(int hangup_cause) -{ - switch(hangup_cause) { - case AST_CAUSE_BUSY: - return "BUSY"; - case AST_CAUSE_CONGESTION: - return "CONGESTION"; - case AST_CAUSE_NO_ROUTE_DESTINATION: - case AST_CAUSE_UNREGISTERED: - return "CHANUNAVAIL"; - case AST_CAUSE_NO_ANSWER: - default: - return "NOANSWER"; - } -} - static void publish_dial_end_event(struct ast_channel *in, struct dial_head *out_chans, struct ast_channel *exception, const char *status) { struct chanlist *outgoing; @@ -1266,7 +1257,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, #ifdef HAVE_EPOLL ast_poll_channel_del(in, c); #endif - ast_channel_publish_dial(in, c, NULL, hangup_cause_to_dial_status(ast_channel_hangupcause(c))); + ast_channel_publish_dial(in, c, NULL, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(c))); ast_hangup(c); c = o->chan = NULL; ast_clear_flag64(o, DIAL_STILLGOING); @@ -1334,7 +1325,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, case AST_CONTROL_BUSY: ast_verb(3, "%s is busy\n", ast_channel_name(c)); ast_channel_hangupcause_set(in, ast_channel_hangupcause(c)); - ast_channel_publish_dial(in, c, NULL, hangup_cause_to_dial_status(ast_channel_hangupcause(c))); + ast_channel_publish_dial(in, c, NULL, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(c))); ast_hangup(c); c = o->chan = NULL; ast_clear_flag64(o, DIAL_STILLGOING); @@ -1343,7 +1334,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, case AST_CONTROL_CONGESTION: ast_verb(3, "%s is circuit-busy\n", ast_channel_name(c)); ast_channel_hangupcause_set(in, ast_channel_hangupcause(c)); - ast_channel_publish_dial(in, c, NULL, hangup_cause_to_dial_status(ast_channel_hangupcause(c))); + ast_channel_publish_dial(in, c, NULL, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(c))); ast_hangup(c); c = o->chan = NULL; ast_clear_flag64(o, DIAL_STILLGOING); diff --git a/apps/app_followme.c b/apps/app_followme.c index 43f196708..66980009d 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -63,6 +63,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astdb.h" #include "asterisk/dsp.h" #include "asterisk/app.h" +#include "asterisk/stasis_channels.h" /*** DOCUMENTATION @@ -556,6 +557,17 @@ static int reload_followme(int reload) return 1; } +static void publish_dial_end_event(struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status) +{ + struct findme_user *tmpuser; + + AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) { + if (tmpuser->ochan && tmpuser->ochan != exception) { + ast_channel_publish_dial(in, tmpuser->ochan, NULL, status); + } + } +} + static void clear_caller(struct findme_user *tmpuser) { struct ast_channel *outbound; @@ -777,6 +789,7 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us } if (!tmpuser) { ast_verb(3, "The calling channel hungup. Need to drop everyone.\n"); + publish_dial_end_event(caller, findme_user_list, NULL, "CANCEL"); ast_frfree(f); return NULL; } @@ -788,6 +801,8 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us break; } ast_verb(3, "%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller)); + ast_channel_publish_dial(caller, winner, NULL, "ANSWER"); + publish_dial_end_event(caller, findme_user_list, winner, "CANCEL"); tmpuser->answered = 1; /* If call has been answered, then the eventual hangup is likely to be normal hangup */ ast_channel_hangupcause_set(winner, AST_CAUSE_NORMAL_CLEARING); @@ -815,6 +830,7 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us ast_verb(3, "%s is busy\n", ast_channel_name(winner)); if (tmpuser) { /* Outbound call was busy. Drop it. */ + ast_channel_publish_dial(caller, winner, NULL, "BUSY"); clear_caller(tmpuser); } break; @@ -822,6 +838,7 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us ast_verb(3, "%s is circuit-busy\n", ast_channel_name(winner)); if (tmpuser) { /* Outbound call was congested. Drop it. */ + ast_channel_publish_dial(caller, winner, NULL, "CONGESTION"); clear_caller(tmpuser); } break; @@ -970,6 +987,7 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us return NULL; } /* Outgoing channel hung up. */ + ast_channel_publish_dial(caller, winner, NULL, "NOANSWER"); clear_caller(tmpuser); } } else { @@ -1141,7 +1159,10 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel } ast_channel_unlock(tmpuser->ochan); destroy_calling_node(tmpuser); + continue; } + + ast_channel_publish_dial(caller, tmpuser->ochan, tmpuser->dialarg, NULL); } AST_LIST_TRAVERSE_SAFE_END; diff --git a/apps/app_queue.c b/apps/app_queue.c index 8a5bedb65..bc9321695 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -106,6 +106,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/cel.h" #include "asterisk/data.h" #include "asterisk/term.h" +#include "asterisk/dial.h" +#include "asterisk/stasis_channels.h" #include "asterisk/bridging.h" /* Define, to debug reference counts on queues, without debugging reference counts on queue members */ @@ -3330,8 +3332,19 @@ static void callattempt_free(struct callattempt *doomed) ast_free(doomed); } +static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status) +{ + struct callattempt *cur; + + for (cur = outgoing; cur; cur = cur->q_next) { + if (cur->chan && cur->chan != exception) { + ast_channel_publish_dial(in, cur->chan, NULL, status); + } + } +} + /*! \brief Hang up a list of outgoing calls */ -static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere) +static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere) { struct callattempt *oo; @@ -3342,6 +3355,7 @@ static void hangupcalls(struct callattempt *outgoing, struct ast_channel *except if (exception || cancel_answered_elsewhere) { ast_channel_hangupcause_set(outgoing->chan, AST_CAUSE_ANSWERED_ELSEWHERE); } + ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL"); ast_hangup(outgoing->chan); } oo = outgoing; @@ -3712,11 +3726,11 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies return 0; } + ast_channel_lock_both(tmp->chan, qe->chan); + if (qe->parent->eventwhencalled) { char vars[2048]; - ast_channel_lock_both(tmp->chan, qe->chan); - /*** DOCUMENTATION Raised when an Agent is notified of a member in the queue. @@ -3761,12 +3775,14 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"), ast_channel_context(qe->chan), ast_channel_exten(qe->chan), ast_channel_priority(qe->chan), ast_channel_uniqueid(qe->chan), qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); + } - ast_channel_unlock(tmp->chan); - ast_channel_unlock(qe->chan); + ast_channel_publish_dial(qe->chan, tmp->chan, tmp->interface, NULL); - ast_verb(3, "Called %s\n", tmp->interface); - } + ast_channel_unlock(tmp->chan); + ast_channel_unlock(qe->chan); + + ast_verb(3, "Called %s\n", tmp->interface); member_call_pending_clear(tmp->member); return 1; @@ -4334,6 +4350,15 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte numnochan++; } } + ast_channel_lock_both(qe->chan, o->chan); + ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL); + ast_channel_unlock(o->chan); + ast_channel_unlock(qe->chan); + + ast_channel_lock_both(qe->chan, original); + ast_channel_publish_dial(qe->chan, original, NULL, "CANCEL"); + ast_channel_unlock(original); + ast_channel_unlock(qe->chan); /* Hangup the original channel now, in case we needed it */ ast_hangup(winner); continue; @@ -4346,6 +4371,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte /* This is our guy if someone answered. */ if (!peer) { ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); + ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER"); + publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL"); if (!o->block_connected_update) { if (o->pending_connected_update) { if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) && @@ -4380,6 +4407,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte if (ast_channel_cdr(in)) { ast_cdr_busy(ast_channel_cdr(in)); } + ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY"); do_hang(o); endtime = (long) time(NULL); endtime -= starttime; @@ -4401,6 +4429,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte if (ast_channel_cdr(in)) { ast_cdr_failed(ast_channel_cdr(in)); } + ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION"); endtime = (long) time(NULL); endtime -= starttime; rna(endtime * 1000, qe, on, membername, qe->parent->autopauseunavail); @@ -4498,6 +4527,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_frfree(f); } else { /* ast_read() returned NULL */ endtime = (long) time(NULL) - starttime; + ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER"); rna(endtime * 1000, qe, on, membername, 1); do_hang(o); if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { @@ -4519,6 +4549,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) { /* Got hung up */ *to = -1; + publish_dial_end_event(in, outgoing, NULL, "CANCEL"); if (f) { if (f->data.uint32) { ast_channel_hangupcause_set(in, f->data.uint32); @@ -4531,6 +4562,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) { ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer); *to = 0; + publish_dial_end_event(in, outgoing, NULL, "CANCEL"); ast_frfree(f); if (ast_channel_cdr(in) && ast_channel_state(in) != AST_STATE_UP) { ast_cdr_noanswer(ast_channel_cdr(in)); @@ -4540,6 +4572,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) { ast_verb(3, "User pressed digit: %c\n", f->subclass.integer); *to = 0; + publish_dial_end_event(in, outgoing, NULL, "CANCEL"); *digit = f->subclass.integer; ast_frfree(f); if (ast_channel_cdr(in) && ast_channel_state(in) != AST_STATE_UP) { @@ -4600,6 +4633,7 @@ skip_frame:; rna(orig, qe, o->interface, o->member->membername, 1); } + publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER"); if (ast_channel_cdr(in) && ast_channel_state(in) != AST_STATE_UP && (!*to || ast_check_hangup(in))) { @@ -5509,7 +5543,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a member = lpeer->member; /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ ao2_ref(member, 1); - hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere); + hangupcalls(qe, outgoing, peer, qe->cancel_answered_elsewhere); outgoing = NULL; if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { int res2; @@ -5552,7 +5586,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a /* Agent must have hung up */ ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer)); ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", ""); - if (qe->parent->eventwhencalled) + if (qe->parent->eventwhencalled) { /*** DOCUMENTATION Raised when an agent hangs up on a member in the queue. @@ -5577,6 +5611,8 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a "%s", queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername, qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); + } + ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer))); ast_autoservice_chan_hangup_peer(qe->chan, peer); ao2_ref(member, -1); goto out; @@ -5585,6 +5621,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer)); ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); record_abandoned(qe); + ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer))); ast_autoservice_chan_hangup_peer(qe->chan, peer); ao2_ref(member, -1); return -1; @@ -5877,7 +5914,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a } } - if (qe->parent->eventwhencalled) + if (qe->parent->eventwhencalled) { /*** DOCUMENTATION Raised when an agent answers and is bridged to a member in the queue. @@ -5909,6 +5946,8 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername, (long) time(NULL) - qe->start, ast_channel_uniqueid(peer), (long)(orig - to > 0 ? (orig - to) / 1000 : 0), qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); + } + ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext)); ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten)); @@ -5977,7 +6016,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a ao2_ref(member, -1); } out: - hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere); + hangupcalls(qe, outgoing, NULL, qe->cancel_answered_elsewhere); return res; } diff --git a/include/asterisk/dial.h b/include/asterisk/dial.h index 0991c8ff6..7aa892f60 100644 --- a/include/asterisk/dial.h +++ b/include/asterisk/dial.h @@ -206,6 +206,11 @@ void ast_dial_set_global_timeout(struct ast_dial *dial, int timeout); */ void ast_dial_set_timeout(struct ast_dial *dial, int num, int timeout); +/*! \since 12 + * \brief Convert a hangup cause to a publishable dial status + */ +const char *ast_hangup_cause_to_dial_status(int hangup_cause); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/dial.c b/main/dial.c index 7008cd574..840f681d6 100644 --- a/main/dial.c +++ b/main/dial.c @@ -616,10 +616,7 @@ static int handle_timeout_trip(struct ast_dial *dial, struct timeval start) return new_timeout; } -/*! \since 12 - * \internal \brief Convert a hangup cause to a publishable dial status - */ -static const char *hangup_cause_to_dial_status(int hangup_cause) +const char *ast_hangup_cause_to_dial_status(int hangup_cause) { switch(hangup_cause) { case AST_CAUSE_BUSY: @@ -728,7 +725,7 @@ static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_chann } if (chan) ast_poll_channel_del(chan, channel->owner); - ast_channel_publish_dial(chan, who, channel->device, hangup_cause_to_dial_status(ast_channel_hangupcause(who))); + ast_channel_publish_dial(chan, who, channel->device, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(who))); ast_hangup(who); channel->owner = NULL; continue; -- cgit v1.2.3