Add dial events to app_queue and app_followme.
authorJason Parker <jparker@digium.com>
Wed, 22 May 2013 18:11:57 +0000 (18:11 +0000)
committerJason Parker <jparker@digium.com>
Wed, 22 May 2013 18:11:57 +0000 (18:11 +0000)
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
apps/app_followme.c
apps/app_queue.c
include/asterisk/dial.h
main/dial.c

index 35c9ad8..b6f1ce8 100644 (file)
@@ -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
        <application name="Dial" language="en_US">
@@ -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);
index 43f1967..6698000 100644 (file)
@@ -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
        <application name="FollowMe" language="en_US">
@@ -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;
 
index 8a5bedb..bc93216 100644 (file)
@@ -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
                <managerEventInstance>
                        <synopsis>Raised when an Agent is notified of a member in the queue.</synopsis>
@@ -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
                                        <managerEventInstance>
                                                <synopsis>Raised when an agent hangs up on a member in the queue.</synopsis>
@@ -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
                        <managerEventInstance>
                                <synopsis>Raised when an agent answers and is bridged to a member in the queue.</synopsis>
@@ -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;
 }
index 0991c8f..7aa892f 100644 (file)
@@ -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
index 7008cd5..840f681 100644 (file)
@@ -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;