Implementation of a feature that will disable "missed calls" counters on SIP phones.
authorOlle Johansson <oej@edvina.net>
Mon, 9 Jul 2007 08:27:37 +0000 (08:27 +0000)
committerOlle Johansson <oej@edvina.net>
Mon, 9 Jul 2007 08:27:37 +0000 (08:27 +0000)
If the call is answered by another phone, other phones won't display the call as "missed".
You can also add an option to the dial command so that you can have a "followme"
scenario and not count the calls as "missed" when you cancel the call.

Thanks to Ramon and Frank for feedback on this feature.

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

apps/app_dial.c
channels/chan_local.c
channels/chan_sip.c
include/asterisk/channel.h

index e566f58..8751d65 100644 (file)
@@ -99,6 +99,8 @@ static char *descrip =
 "  Options:\n"
 "    A(x) - Play an announcement to the called party, using 'x' as the file.\n"
 "    C    - Reset the CDR for this call.\n"
+"    c    - If DIAL cancels this call, always set the flag to tell the channel\n"
+"           driver that the call is answered elsewhere.\n"
 "    d    - Allow the calling user to dial a 1 digit extension while waiting for\n"
 "           a call to be answered. Exit to that extension if it exists in the\n"
 "           current context, or the context defined in the EXITCONTEXT variable,\n"
@@ -253,6 +255,7 @@ enum {
        OPT_CALLER_PARK =       (1 << 26),
        OPT_IGNORE_FORWARDING = (1 << 27),
        OPT_CALLEE_GOSUB =      (1 << 28),
+       OPT_CANCEL_ELSEWHERE =  (1 << 29),
 };
 
 #define DIAL_STILLGOING                        (1 << 30)
@@ -276,6 +279,7 @@ enum {
 AST_APP_OPTIONS(dial_exec_options, {
        AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
        AST_APP_OPTION('C', OPT_RESETCDR),
+       AST_APP_OPTION('c', OPT_CANCEL_ELSEWHERE),
        AST_APP_OPTION('d', OPT_DTMF_EXIT),
        AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF),
        AST_APP_OPTION('f', OPT_FORCECLID),
@@ -315,14 +319,17 @@ struct chanlist {
 };
 
 
-static void hanguptree(struct chanlist *outgoing, struct ast_channel *exception)
+static void hanguptree(struct chanlist *outgoing, struct ast_channel *exception, int answered_elsewhere)
 {
        /* Hang up a tree of stuff */
        struct chanlist *oo;
        while (outgoing) {
                /* Hangup any existing lines we have open */
-               if (outgoing->chan && (outgoing->chan != exception))
+               if (outgoing->chan && (outgoing->chan != exception)) {
+                       if (answered_elsewhere)
+                               ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
                        ast_hangup(outgoing->chan);
+               }
                oo = outgoing;
                outgoing=outgoing->next;
                ast_free(oo);
@@ -1314,6 +1321,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                        goto out;
                if (opts.flags) {
                        ast_copy_flags(tmp, &opts,
+                                      OPT_CANCEL_ELSEWHERE |
                                       OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
                                       OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
                                       OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
@@ -1513,7 +1521,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
                   we will always return with -1 so that it is hung up properly after the 
                   conversation.  */
-               hanguptree(outgoing, peer);
+               hanguptree(outgoing, peer, 1);
                outgoing = NULL;
                /* If appropriate, log that we have a destination channel */
                if (chan->cdr)
@@ -1562,7 +1570,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                        ast_parseable_goto(peer, opt_args[OPT_ARG_GOTO]);
                        peer->priority++;
                        ast_pbx_start(peer);
-                       hanguptree(outgoing, NULL);
+                       hanguptree(outgoing, NULL, ast_test_flag(&opts, OPT_CANCEL_ELSEWHERE ? 1 : 0));
                        if (continue_exec)
                                *continue_exec = 1;
                        res = 0;
@@ -1800,7 +1808,7 @@ out:
                ast_indicate(chan, -1);
        }
        ast_channel_early_bridge(chan, NULL);
-       hanguptree(outgoing, NULL);
+       hanguptree(outgoing, NULL, 0);  /* In this case, there's no answer anywhere */
        pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
        senddialendevent(chan, pa.status);
        ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);
index beac406..b4072ce 100644 (file)
@@ -495,6 +495,8 @@ static int local_hangup(struct ast_channel *ast)
                return -1;
 
        ast_mutex_lock(&p->lock);
+       if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) 
+               ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
        isoutbound = IS_OUTBOUND(ast, p);
        if (isoutbound) {
                const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
index 6c9ea33..9cebd9d 100644 (file)
@@ -752,7 +752,7 @@ struct sip_auth {
 #define SIP_REALTIME           (1 << 11)       /*!< P: Flag for realtime users */
 #define SIP_USECLIENTCODE      (1 << 12)       /*!< DP: Trust X-ClientCode info message */
 #define SIP_OUTGOING           (1 << 13)       /*!< D: Direction of the last transaction in this dialog */
-#define SIP_FREE_BIT           (1 << 14)       /*!< ---- */
+#define SIP_DIALOG_ANSWEREDELSEWHERE   (1 << 14)       /*!< D: This call is cancelled due to answer on another channel */
 #define SIP_DEFER_BYE_ON_TRANSFER      (1 << 15)       /*!< D: Do not hangup at first ast_hangup */
 #define SIP_DTMF               (3 << 16)       /*!< DP: DTMF Support: four settings, uses two bits */
 #define SIP_DTMF_RFC2833       (0 << 16)       /*!< DP: DTMF Support: RTP DTMF - "rfc2833" */
@@ -3674,6 +3674,12 @@ static int sip_hangup(struct ast_channel *ast)
                ast_debug(1, "Asked to hangup channel that was not connected\n");
                return 0;
        }
+       if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "This call was answered elsewhere");
+               append_history(p, "Cancel", "Call answered elsewhere");
+               ast_set_flag(&p->flags[0], SIP_DIALOG_ANSWEREDELSEWHERE);
+       }
 
        if (ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
                if (ast_test_flag(&p->flags[0], SIP_INC_COUNT)) {
@@ -8140,6 +8146,9 @@ static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, enum xm
                p->invitestate = INV_CONFIRMED;
 
        reqprep(&resp, p, sipmethod, seqno, newbranch);
+       if (sipmethod == SIP_CANCEL && ast_test_flag(&p->flags[0], SIP_DIALOG_ANSWEREDELSEWHERE)) 
+               add_header(&resp, "Reason:", "SIP;cause=200;text=\"Call completed elsewhere\"");
+
        add_header_contentLength(&resp, 0);
        return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
 }
index 8c0b6a5..139a8b1 100644 (file)
@@ -539,6 +539,9 @@ enum {
        /*! This is set to tell the channel not to generate DTMF begin frames, and
         *  to instead only generate END frames. */
        AST_FLAG_END_DTMF_ONLY = (1 << 14),
+       /*! Flag to show channels that this call is hangup due to the fact that the call
+           was indeed anwered, but in another channel */
+       AST_FLAG_ANSWERED_ELSEWHERE = (1 << 15),
 };
 
 /*! \brief ast_bridge_config flags */