]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
wait for reply of refer
authorAnthony Minessale <anthony.minessale@gmail.com>
Thu, 20 Nov 2008 02:07:59 +0000 (02:07 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Thu, 20 Nov 2008 02:07:59 +0000 (02:07 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@10471 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_core.h
src/include/switch_types.h
src/mod/applications/mod_commands/mod_commands.c
src/mod/endpoints/mod_sofia/mod_sofia.c
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c

index b1a15600a177fe3d8446f2b229ddc4274994e020..7f9efc6d9b4c9db94e5bcb1b693adb94ab844eec 100644 (file)
@@ -92,6 +92,7 @@ struct switch_core_session_message {
        const char *_file;
        const char *_func;
        int _line;
+
 };
 
 /*! \brief A generic object to pass as a thread's session object to allow mutiple arguements and a pool */
index 2f41b02636578db4c58979ccb471a95258dafbbd..f3eaedd6bc28407618dd2214125ed958a00d3e2b 100644 (file)
@@ -676,7 +676,9 @@ typedef enum {
 } switch_text_channel_t;
 
 typedef enum {
-       SCSMF_DYNAMIC = (1 << 0)
+       SCSMF_DYNAMIC = (1 << 0),
+       SCSMF_FREE_STRING_REPLY = (1 << 1),
+       SCSMF_FREE_POINTER_REPLY = (1 << 2),
 } switch_core_session_message_flag_enum_t;
 typedef uint32_t switch_core_session_message_flag_t;
 
index 23893e126ee5ad966101f25c3b7d59c55cc859ab..568f76025f3a511004350a45e62b673fc2f4c970 100644 (file)
@@ -1259,6 +1259,45 @@ SWITCH_STANDARD_API(uuid_chat)
        return SWITCH_STATUS_SUCCESS;
 }
 
+
+
+#define UUID_DEFLECT_SYNTAX "<uuid> <uri>"
+SWITCH_STANDARD_API(uuid_deflect)
+{
+       switch_core_session_t *tsession = NULL;
+       char *uuid = NULL, *text = NULL;
+
+       if (!switch_strlen_zero(cmd) && (uuid = strdup(cmd))) {
+               if ((text = strchr(uuid, ' '))) {
+                       *text++ = '\0';
+               }
+       }
+
+       if (switch_strlen_zero(uuid) || switch_strlen_zero(text)) {
+               stream->write_function(stream, "-USAGE: %s\n", UUID_DEFLECT_SYNTAX);
+       } else {
+               if ((tsession = switch_core_session_locate(uuid))) {
+                       switch_core_session_message_t msg = { 0 };
+
+                       /* Tell the channel to deflect the call */
+                       msg.from = __FILE__;
+                       msg.string_arg = text;
+                       msg.message_id = SWITCH_MESSAGE_INDICATE_DEFLECT;
+                       switch_core_session_receive_message(tsession, &msg);
+                       stream->write_function(stream, "+OK:%s\n", msg.string_reply);
+                       if (switch_set_flag((&msg), SCSMF_FREE_STRING_REPLY)) {
+                               free(msg.string_reply);
+                       }
+                       switch_core_session_rwunlock(tsession);
+               } else {
+                       stream->write_function(stream, "-ERR No Such Channel %s!\n", uuid);
+               }
+       }
+
+       switch_safe_free(uuid);
+       return SWITCH_STATUS_SUCCESS;
+}
+
 #define SCHED_TRANSFER_SYNTAX "[+]<time> <uuid> <extension> [<dialplan>] [<context>]"
 SWITCH_STANDARD_API(sched_transfer_function)
 {
@@ -3091,6 +3130,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
        SWITCH_ADD_API(commands_api_interface, "regex", "Eval a regex", regex_function, "<data>|<pattern>[|<subst string>]");
        SWITCH_ADD_API(commands_api_interface, "acl", "compare an ip to an acl list", acl_function, "<ip> <list_name>");
        SWITCH_ADD_API(commands_api_interface, "uuid_chat", "Send a chat message", uuid_chat, UUID_CHAT_SYNTAX);
+       SWITCH_ADD_API(commands_api_interface, "uuid_deflect", "Send a deflect", uuid_deflect, UUID_DEFLECT_SYNTAX);
        SWITCH_ADD_API(commands_api_interface, "find_user_xml", "find a user", find_user_function, "<key> <user> <domain>");
        SWITCH_ADD_API(commands_api_interface, "user_exists", "find a user", user_exists_function, "<key> <user> <domain>");
        SWITCH_ADD_API(commands_api_interface, "xml_locate", "find some xml", xml_locate_function, "[root | <section> <tag> <tag_attr_name> <tag_attr_val>]");
index dc50c95ebae0e02cd29b117a37e4f2d28b14527b..e84645c7a095f8ed3623a3484b150464e9ab5e57 100644 (file)
@@ -1120,6 +1120,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
        case SWITCH_MESSAGE_INDICATE_DEFLECT:
                {
                        char ref_to[128] = "";
+                       const char *var;
 
                        if (!strstr(msg->string_arg, "sip:")) {
                                const char *format = strchr(tech_pvt->profile->sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s";
@@ -1128,6 +1129,16 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
                                switch_set_string(ref_to, msg->string_arg);
                        }
                        nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(tech_pvt->contact_url), TAG_END());
+                       switch_mutex_unlock(tech_pvt->sofia_mutex);
+                       sofia_wait_for_reply(tech_pvt, 9999, 300);
+                       switch_mutex_lock(tech_pvt->sofia_mutex);
+                       
+                       if ((var = switch_channel_get_variable(tech_pvt->channel, "sip_refer_reply"))) {
+                               msg->string_reply = strdup(var); 
+                               switch_set_flag(msg, SCSMF_FREE_STRING_REPLY);
+                       } else {
+                               msg->string_reply = "no reply";
+                       }
                }
                break;
 
index c45fd613e22221b3e01e7e4a751a395f9a8cb1f9..4a58c7788eff69ee15b8dd02a05b0229bf415b84 100644 (file)
@@ -513,6 +513,7 @@ struct private_object {
        switch_size_t last_ts;
        uint32_t check_frames;
        uint32_t mismatch_count;
+       nua_event_t want_event;
 };
 
 struct callback_t {
@@ -717,3 +718,4 @@ void sofia_glue_restart_all_profiles(void);
 void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly);
 const char * sofia_state_string(int state);
 switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force);
+void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout);
index 85c6d076898b6f5134d5e7d1b62e26ed304bdf66..ec13e8a6c5ad454ef5b121bf042c4b146127699c 100644 (file)
@@ -83,6 +83,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
                                                           nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
 {
        switch_channel_t *channel = NULL;
+       private_object_t *tech_pvt = NULL;
 
        /* make sure we have a proper event */
        if (!sip || !sip->sip_event) {
@@ -94,14 +95,35 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
                nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
                return;
        }
+       
+       if (session) {
+               channel = switch_core_session_get_channel(session);
+               switch_assert(channel != NULL);
+               tech_pvt = switch_core_session_get_private(session);
+               switch_assert(tech_pvt != NULL);
+       }
+
+       if (!strcasecmp(sip->sip_event->o_type, "refer")) {
+               if (session && channel && tech_pvt) {
+                       if (sip->sip_payload && sip->sip_payload->pl_data) {
+                               if (!switch_stristr("100", sip->sip_payload->pl_data)) {
+                                       switch_channel_set_variable(channel, "sip_refer_reply", sip->sip_payload->pl_data);
+                                       if (tech_pvt->want_event == 9999) {
+                                               tech_pvt->want_event = 0;
+                                       }
+                               }
+                       }
+               }
+               nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+       }
+
 
        /* make sure we have a proper "talk" event */
        if (!session || strcasecmp(sip->sip_event->o_type, "talk")) {
                goto error;
        }
 
-       channel = switch_core_session_get_channel(session);
-       switch_assert(channel != NULL);
+       
        if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
                switch_channel_answer(channel);
                switch_channel_set_variable(channel, "auto_answer_destination", switch_channel_get_variable(channel, "destination_number"));
@@ -109,6 +131,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
                nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
                return;
        }
+       
 
   error:
        nua_respond(nh, 481, "Subscription Does Not Exist", NUTAG_WITH_THIS(nua), TAG_END());
@@ -160,6 +183,18 @@ void sofia_handle_sip_r_message(int status, sofia_profile_t *profile, nua_handle
 {
 }
 
+void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout)
+{
+       time_t exp = switch_timestamp(NULL) + timeout;
+       
+       tech_pvt->want_event = event;
+
+       while(switch_channel_ready(tech_pvt->channel) && tech_pvt->want_event && switch_timestamp(NULL) < exp) {
+               switch_yield(100000);
+       }
+       
+}
+
 void sofia_event_callback(nua_event_t event,
                                                  int status,
                                                  char const *phrase,
@@ -336,6 +371,10 @@ void sofia_event_callback(nua_event_t event,
 
   done:
 
+       if (tech_pvt && tech_pvt->want_event && event == tech_pvt->want_event) {
+               tech_pvt->want_event = 0;
+       }
+
        switch (event) {
        case nua_i_subscribe:
                break;
@@ -586,6 +625,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
                                   TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("include-session-description")),
                                   TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("presence.winfo")),
                                   TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("message-summary")),
+                                  NUTAG_ALLOW_EVENTS("refer"),
                                   SIPTAG_SUPPORTED_STR(supported), SIPTAG_USER_AGENT_STR(profile->user_agent), TAG_END());
 
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set params for %s\n", profile->name);
@@ -2940,6 +2980,7 @@ static void launch_nightmare_xfer(nightmare_xfer_helper_t *nhelper)
 }
 
 /*---------------------------------------*/
+
 void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
 {
        /* Incoming refer */