chan_pjsip: Add support for picking up calls in the configured pickup group.
authorJoshua Colp <jcolp@digium.com>
Wed, 30 Apr 2014 12:32:12 +0000 (12:32 +0000)
committerJoshua Colp <jcolp@digium.com>
Wed, 30 Apr 2014 12:32:12 +0000 (12:32 +0000)
AST-1363

Review: https://reviewboard.asterisk.org/r/3478/
........

Merged revisions 413117 from http://svn.asterisk.org/svn/asterisk/branches/12

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

channels/chan_pjsip.c
res/res_pjsip_session.c

index b28c2d6..5781504 100644 (file)
@@ -58,6 +58,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/stasis_channels.h"
 #include "asterisk/indications.h"
 #include "asterisk/threadstorage.h"
+#include "asterisk/features_config.h"
+#include "asterisk/pickup.h"
 
 #include "asterisk/res_pjsip.h"
 #include "asterisk/res_pjsip_session.h"
@@ -1967,6 +1969,49 @@ static int chan_pjsip_incoming_request(struct ast_sip_session *session, struct p
        return 0;
 }
 
+static int call_pickup_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+       struct ast_features_pickup_config *pickup_cfg = ast_get_chan_features_pickup_config(session->channel);
+       struct ast_channel *chan;
+
+       if (!pickup_cfg) {
+               ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension.\n");
+               return 0;
+       }
+
+       if (strcmp(session->exten, pickup_cfg->pickupexten)) {
+               ao2_ref(pickup_cfg, -1);
+               return 0;
+       }
+       ao2_ref(pickup_cfg, -1);
+
+       /* We can't directly use session->channel because the pickup operation will cause a masquerade to occur,
+        * changing the channel pointer in session to a different channel. To ensure we work on the right channel
+        * we store a pointer locally before we begin and keep a reference so it remains valid no matter what.
+        */
+       chan = ast_channel_ref(session->channel);
+       if (ast_pickup_call(chan)) {
+               ast_channel_hangupcause_set(chan, AST_CAUSE_CALL_REJECTED);
+       } else {
+               ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL_CLEARING);
+       }
+       /* A hangup always occurs because the pickup operation will have either failed resulting in the call
+        * needing to be hung up OR the pickup operation was a success and the channel we now have is actually
+        * the channel that was replaced, which should be hung up since it is literally in limbo not connected
+        * to anything at all.
+        */
+       ast_hangup(chan);
+       ast_channel_unref(chan);
+
+       return 1;
+}
+
+static struct ast_sip_session_supplement call_pickup_supplement = {
+       .method = "INVITE",
+       .priority = AST_SIP_SUPPLEMENT_PRIORITY_LAST - 1,
+       .incoming_request = call_pickup_incoming_request,
+};
+
 static int pbx_start_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
 {
        int res;
@@ -2106,9 +2151,16 @@ static int load_module(void)
                goto end;
        }
 
+       if (ast_sip_session_register_supplement(&call_pickup_supplement)) {
+               ast_log(LOG_ERROR, "Unable to register PJSIP call pickup supplement\n");
+               ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
+               goto end;
+       }
+
        if (ast_sip_session_register_supplement(&pbx_start_supplement)) {
                ast_log(LOG_ERROR, "Unable to register PJSIP pbx start supplement\n");
                ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
+               ast_sip_session_unregister_supplement(&call_pickup_supplement);
                goto end;
        }
 
@@ -2116,6 +2168,7 @@ static int load_module(void)
                ast_log(LOG_ERROR, "Unable to register PJSIP ACK supplement\n");
                ast_sip_session_unregister_supplement(&pbx_start_supplement);
                ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
+               ast_sip_session_unregister_supplement(&call_pickup_supplement);
                goto end;
        }
 
@@ -2154,6 +2207,7 @@ static int unload_module(void)
        ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
        ast_sip_session_unregister_supplement(&pbx_start_supplement);
        ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
+       ast_sip_session_unregister_supplement(&call_pickup_supplement);
 
        ast_custom_function_unregister(&media_offer_function);
        ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
index 82c7a3f..6acbc0c 100644 (file)
@@ -43,6 +43,8 @@
 #include "asterisk/sdp_srtp.h"
 #include "asterisk/dsp.h"
 #include "asterisk/acl.h"
+#include "asterisk/features_config.h"
+#include "asterisk/pickup.h"
 
 #define SDP_HANDLER_BUCKETS 11
 
@@ -1349,12 +1351,27 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s
 {
        pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
        pjsip_sip_uri *sip_ruri;
+       struct ast_features_pickup_config *pickup_cfg;
+       const char *pickupexten;
+
        if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
                return SIP_GET_DEST_UNSUPPORTED_URI;
        }
+
        sip_ruri = pjsip_uri_get_uri(ruri);
        ast_copy_pj_str(session->exten, &sip_ruri->user, sizeof(session->exten));
-       if (ast_exists_extension(NULL, session->endpoint->context, session->exten, 1, NULL)) {
+
+       pickup_cfg = ast_get_chan_features_pickup_config(session->channel);
+       if (!pickup_cfg) {
+               ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
+               pickupexten = "";
+       } else {
+               pickupexten = ast_strdupa(pickup_cfg->pickupexten);
+               ao2_ref(pickup_cfg, -1);
+       }
+
+       if (!strcmp(session->exten, pickupexten) ||
+               ast_exists_extension(NULL, session->endpoint->context, session->exten, 1, NULL)) {
                return SIP_GET_DEST_EXTEN_FOUND;
        }
        /* XXX In reality, we'll likely have further options so that partial matches