]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
more sofia stuff
authorAnthony Minessale <anthony.minessale@gmail.com>
Thu, 5 Oct 2006 14:24:25 +0000 (14:24 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Thu, 5 Oct 2006 14:24:25 +0000 (14:24 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2978 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_ivr.h
src/mod/endpoints/mod_sofia/mod_sofia.c
src/switch_ivr.c

index cde5758315c3ed34fa323e3771e46ba336e1118b..eb472da44b9983fda0a943e8f87df0d94aa09e6e 100644 (file)
@@ -242,6 +242,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
 */
 SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(char *originator_uuid, char *originatee_uuid);
 
+/*!
+  \brief Transfer variables from one session to another 
+  \param sessa the original session
+  \param sessb the new session
+  \param var the name of the variable to transfer (NULL for all)
+  \return SWITCH_STATUS_SUCCESS if all is well 
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_transfer_variable(switch_core_session_t *sessa, switch_core_session_t *sessb, char *var);
+
 /** @} */
 
 SWITCH_END_EXTERN_C
index 3a15009492f931246c268a3f9ea2f9469bc2eb22..f8e65adad071659d8fd69a2e5a2c743f16bf3617 100644 (file)
@@ -60,7 +60,7 @@ typedef struct private_object private_object_t;
 #define MY_EVENT_REGISTER "sofia::register"
 #define MY_EVENT_EXPIRE "sofia::expire"
 #define MULTICAST_EVENT "multicast::event"
-
+#define SOFIA_REPLACES_HEADER "_sofia_replaces_"
 
 #include <sofia-sip/nua.h>
 #include <sofia-sip/sip_status.h>
@@ -110,6 +110,7 @@ typedef enum {
        PFLAG_AUTH_CALLS = (1 << 0),
        PFLAG_BLIND_REG = (1 << 1),
        PFLAG_AUTH_ALL = (1 << 2),
+       PFLAG_FULL_ID = (1 << 3)
 } PFLAGS;
 
 typedef enum {
@@ -792,6 +793,7 @@ static void do_invite(switch_core_session_t *session)
                                                                                                         tech_pvt->profile->sipip
                                                                                                         ))) {
 
+               char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
 
                tech_choose_port(tech_pvt);
                set_local_sdp(tech_pvt);
@@ -810,6 +812,7 @@ static void do_invite(switch_core_session_t *session)
                                   SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
                                   SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
                                   SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
+                                  TAG_IF(rep, SIPTAG_REPLACES_STR(rep)),
                                   TAG_END());
        } else {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
@@ -1594,6 +1597,10 @@ static switch_status_t sofia_outgoing_channel(switch_core_session_t *session, sw
        switch_channel_set_variable(channel, "endpoint_disposition", "OUTBOUND");
        *new_session = nsession;
        status = SWITCH_STATUS_SUCCESS;
+       if (session) {
+               switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER);
+       }
+
  done:
        return status;
 }
@@ -1801,9 +1808,7 @@ static void sip_i_state(int status,
                                sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
                                sdp_session_t *sdp;
                                uint8_t match = 0;
-
-
-
+                               
                                if (tech_pvt->num_codecs) {
                                        if ((sdp = sdp_session(parser))) {
                                                match = negotiate_sdp(session, sdp);
@@ -1814,14 +1819,41 @@ static void sip_i_state(int status,
                                        sdp_parser_free(parser);
                                }
 
-
                                if (match) {
+                                       nua_handle_t *bnh;
+
                                        switch_channel_set_variable(channel, "endpoint_disposition", "RECEIVED");
                                        switch_channel_set_state(channel, CS_INIT);
                                        switch_set_flag_locked(tech_pvt, TFLAG_READY);
                                        switch_core_session_thread_launch(session);
+                                       if (sip->sip_replaces && (bnh = nua_handle_by_replaces(nua, sip->sip_replaces))) {
+                                               sofia_private_t *b_private;
+
+                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Attended Transfer\n");
+                                               while (switch_channel_get_state(channel) < CS_EXECUTE) {
+                                                       switch_yield(10000);
+                                               }
+
+                                               if ((b_private = nua_handle_fetch(bnh))) {
+                                                       char *br_b = switch_channel_get_variable(channel, "BRIDGETO");
+                                                       char *br_a = switch_core_session_get_uuid(b_private->session);
+
+                                                       if (br_b) {
+                                                               switch_ivr_uuid_bridge(br_a, br_b);
+                                                               switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER");
+                                                               switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
+                                                       } else {
+                                                               switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR");
+                                                               switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                                       }
+                                               } else {
+                                                       switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR");
+                                                       switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                               }
+                                       }
                                        return;
                                }
+
                                switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS");
                                nua_respond(nh, SIP_488_NOT_ACCEPTABLE, 
                                                        TAG_END());
@@ -2200,27 +2232,19 @@ static void sip_i_refer(nua_t *nua,
        if (session) {
                private_object_t *tech_pvt = NULL;
                char *exten;
-               const char *tmp = NULL;
-#ifdef this_was_done
-               char *dest;
-               private_object_t *ntech_pvt;
-               switch_core_session_t *nsession;
-               switch_channel_t *channel, *nchannel;
-               switch_caller_profile_t *caller_profile = NULL, *outbound_profile = NULL;
-#endif
 
                tech_pvt = switch_core_session_get_private(session);
                from = sip->sip_from;
                to = sip->sip_to;
 
-               tl_gets(tags, 
-                               SIPTAG_REFER_TO_STR_REF(tmp),
-                               TAG_END()); 
-
                if ((refer_to = sip->sip_refer_to)) {
-                       exten = (char *) refer_to->r_url->url_user;
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", 
-                                                         exten, (char *) refer_to->r_url->url_host);
+                       if (profile->pflags & PFLAG_FULL_ID) {
+                               exten = switch_core_db_mprintf("%s@%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host);
+                       } else {
+                               exten = (char *) refer_to->r_url->url_user;
+                       }
+
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", exten, (char *) refer_to->r_url->url_host);
 
                        if (refer_to->r_url->url_headers) {
                                sip_replaces_t *replaces;
@@ -2228,29 +2252,27 @@ static void sip_i_refer(nua_t *nua,
                                char *rep;
 
                                if ((rep = strchr(refer_to->r_url->url_headers, '='))) {
+                                       switch_channel_t *channel_a = NULL, *channel_b = NULL;
+                                       char *br_a, *br_b;
                                        char *buf;
                                        rep++;
 
+                                       channel_a = switch_core_session_get_channel(session);
+
                                        if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) {
                                                rep = url_unescape(buf, (const char *) rep); 
                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Replaces: [%s]\n", rep);
                                        } else {
                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
-                                               return;
+                                               goto done;
                                        }
                                        if ((replaces = sip_replaces_make(tech_pvt->home, rep)) && (bnh = nua_handle_by_replaces(nua, replaces))) {
                                                sofia_private_t *b_private;
-                                               switch_channel_t *channel_a = NULL, *channel_b = NULL;
-
-                                               channel_a = switch_core_session_get_channel(session);
-                                                       
+                                               
                                                if ((b_private = nua_handle_fetch(bnh))) {
-                                                       char *br_a, *br_b;
-
                                                        channel_b = switch_core_session_get_channel(b_private->session);
                                
                                                        br_a = switch_channel_get_variable(channel_a, "BRIDGETO");
-                                                       //br_a = switch_core_session_get_uuid(session);
                                                        br_b = switch_channel_get_variable(channel_b, "BRIDGETO");
 
                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", br_a, br_b);
@@ -2271,18 +2293,65 @@ static void sip_i_refer(nua_t *nua,
                                                }
                                        
                                                nua_handle_unref(bnh);
-                                       } else {
-                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find handle from Replaces!\n");
+                                       } else { /* the other channel is on a different box, we have to go find them */
+                                               if (exten && (br_a = switch_channel_get_variable(channel_a, "BRIDGETO"))) {
+                                                       switch_core_session_t *bsession;
+                                                       switch_channel_t *channel = switch_core_session_get_channel(session);
+                                                       
+                                                       if ((bsession = switch_core_session_locate(br_a))) {
+                                                               switch_core_session_t *tsession;
+                                                               switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
+                                                               uint32_t timeout = 60;
+                                                               char *tuuid_str;
+
+                                                               channel = switch_core_session_get_channel(bsession);
+
+                                                               exten = switch_core_db_mprintf("sofia/%s/%s@%s:%d", 
+                                                                                                                          profile->name,
+                                                                                                                          (char *) refer_to->r_url->url_user,
+                                                                                                                          (char *) refer_to->r_url->url_host,
+                                                                                                                          refer_to->r_url->url_port
+                                                                                                                          );
+
+                                                               switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep);
+                                                               
+                                                               if (switch_ivr_originate(bsession,
+                                                                                                                &tsession,
+                                                                                                                &cause,
+                                                                                                                exten,
+                                                                                                                timeout,
+                                                                                                                &noop_state_handler,
+                                                                                                                NULL,
+                                                                                                                NULL,
+                                                                                                                NULL) != SWITCH_STATUS_SUCCESS) {
+                                                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel! [%s]\n", exten);
+                                                                       goto done;
+                                                               } 
+
+                                                               switch_core_session_rwunlock(bsession);
+                                                               tuuid_str = switch_core_session_get_uuid(tsession);
+                                                               switch_ivr_uuid_bridge(br_a, tuuid_str);
+                                                               switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER");
+                                                               switch_channel_hangup(channel_a, SWITCH_CAUSE_ATTENDED_TRANSFER);
+                                                       } else {
+                                                               goto error;
+                                                       }
+
+                                               } else { error:
+                                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Transfer! [%s]\n", br_a);
+                                                       switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR");
+                                                       switch_channel_hangup(channel_a, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                               }
                                        }
                                } else {
                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot parse Replaces!\n");
                                }
-                               return;
+                               goto done;
                        }
 
                } else {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Refer-To\n");
-                       return;
+                       goto done;
                }
 
                if (exten) {
@@ -2304,38 +2373,11 @@ static void sip_i_refer(nua_t *nua,
                        }
                                
                }
-               
 
-#ifdef this_was_done
-               if (!(nsession = switch_core_session_request(&sofia_endpoint_interface, NULL))) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
-                       goto done;
+       done:
+               if (strchr(exten, '@')) {
+                       switch_core_db_free(exten);
                }
-
-               if (!(ntech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*ntech_pvt)))) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
-                       terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-                       goto done;
-               }
-               ntech_pvt->dest = switch_core_session_strdup(nsession, exten);
-               dest = ntech_pvt->dest + 4;
-               channel = switch_core_session_get_channel(session);
-               outbound_profile = switch_channel_get_caller_profile(channel);
-               nchannel = switch_core_session_get_channel(nsession);
-               attach_private(nsession, profile, ntech_pvt, dest);     
-               caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
-               caller_profile->destination_number = switch_core_session_strdup(nsession, dest);
-               switch_channel_set_caller_profile(nchannel, caller_profile);
-               switch_channel_set_flag(nchannel, CF_OUTBOUND);
-               switch_set_flag_locked(ntech_pvt, TFLAG_OUTBOUND);
-               switch_set_flag_locked(ntech_pvt, TFLAG_REFER);
-               switch_channel_set_state(nchannel, CS_INIT);
-               switch_channel_set_variable(channel, "endpoint_disposition", "OUTBOUND_REFER");
-               switch_core_session_thread_launch(nsession);
-#endif
-
-               //done:
-               return;
        }
 
 }
@@ -2365,7 +2407,7 @@ static void sip_i_invite(nua_t *nua,
                        sip_from_t const *from = sip->sip_from;
                        sip_to_t const *to = sip->sip_to;
                        char *displayname;
-                       char username[256];
+                       char *username, *to_username;
                        char *url_user = (char *) from->a_url->url_user;
 
                        if (!(tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)))) {
@@ -2396,7 +2438,16 @@ static void sip_i_invite(nua_t *nua,
                                displayname = url_user;
                        }
                        
-                       snprintf(username, sizeof(username), "%s@%s", url_user, (char *) from->a_url->url_host);
+                       if (!(username = switch_core_db_mprintf("%s@%s", url_user, (char *) from->a_url->url_host))) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
+                               return;
+                       }
+                       if (!(to_username = switch_core_db_mprintf("%s@%s", (char *) to->a_url->url_user, (char *) to->a_url->url_host))) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
+                               switch_core_db_free(username);
+                               return;
+                       }
+
                        attach_private(session, profile, tech_pvt, username);
 
                        channel = switch_core_session_get_channel(session);
@@ -2412,9 +2463,14 @@ static void sip_i_invite(nua_t *nua,
                                                                                                                                          NULL,
                                                                                                                                          NULL,
                                                                                                                                          (char *)modname,
-                                                                                                                                         profile->context,
-                                                                                                                                         (char *) to->a_url->url_user)) != 0) {
+                                                                                                                                         (profile->context && !strcasecmp(profile->context, "_domain_")) ? 
+                                                                                                                                         (char *) from->a_url->url_host : profile->context,
+                                                                                                                                         (profile->pflags & PFLAG_FULL_ID) ? 
+                                                                                                                                         to_username : (char *) to->a_url->url_user
+                                                                                                                                         )) != 0) {
                                switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+                               switch_core_db_free(username);
+                               switch_core_db_free(to_username);
                        }
                        switch_set_flag_locked(tech_pvt, TFLAG_INBOUND);
                        tech_pvt->sofia_private.session = session;
@@ -2752,7 +2808,7 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void
        uint32_t ireg_loops = 0;
        uint32_t oreg_loops = 0;
        switch_core_db_t *db;
-
+       switch_event_t *s_event;
 
        profile->s_root = su_root_create(NULL);
        profile->nua = nua_create(profile->s_root, /* Event loop */
@@ -2765,7 +2821,6 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void
                                   NUTAG_EARLY_MEDIA(1),                                   
                                   NUTAG_AUTOANSWER(0),
                                   NUTAG_AUTOALERT(0),
-                                  //NUTAG_AUTOTRYING(0),
                                   NUTAG_ALLOW("REGISTER"),
                                   NUTAG_ALLOW("REFER"),
                                   SIPTAG_SUPPORTED_STR("100rel, precondition"),
@@ -2783,7 +2838,6 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void
                                           NUTAG_EARLY_MEDIA(1),
                                           NUTAG_AUTOANSWER(0),
                                           NUTAG_AUTOALERT(0),
-                                          //NUTAG_AUTOTRYING(0),
                                           NUTAG_ALLOW("REGISTER"),
                                           SIPTAG_SUPPORTED_STR("100rel, precondition"),
                                           TAG_END());
@@ -2810,6 +2864,12 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void
        ireg_loops = IREG_SECONDS;
        oreg_loops = OREG_SECONDS;
 
+       if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
+               switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp");
+               switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
+               switch_event_fire(&s_event);
+       }
+
        while(globals.running == 1) {
                if (++ireg_loops >= IREG_SECONDS) {
                        check_expire(profile, time(NULL));
@@ -2825,6 +2885,13 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void
                //su_root_run(profile->s_root);
        }
 
+       
+       if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) {
+               switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp");
+               switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
+               switch_event_fire(&s_event);
+       }
+
        su_root_destroy(profile->s_root);
 
        pool = profile->pool;
@@ -2944,6 +3011,10 @@ static switch_status_t config_sofia(int reload)
                                                if (switch_true(val)) {
                                                        profile->pflags |= PFLAG_AUTH_ALL;
                                                }
+                                       } else if (!strcasecmp(var, "full-id-in-dialplan")) {
+                                               if (switch_true(val)) {
+                                                       profile->pflags |= PFLAG_FULL_ID;
+                                               }
                                        } else if (!strcasecmp(var, "ext-sip-ip")) {
                                                profile->extsipip = switch_core_strdup(profile->pool, val);
                                        } else if (!strcasecmp(var, "bitpacking")) {
index 3eb9f993b6fc9e4df98474635b58ae6cd74c7216..6600d4a4d21259a3ab15d3bdf5e3e30a05c6db69 100644 (file)
@@ -2253,4 +2253,28 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
        return SWITCH_STATUS_FALSE;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_ivr_transfer_variable(switch_core_session_t *sessa, switch_core_session_t *sessb, char *var)
+{
+       switch_channel_t *chana = switch_core_session_get_channel(sessa);
+       switch_channel_t *chanb = switch_core_session_get_channel(sessb);
+       char *val = NULL;
+
+       if (var) {
+               if ((val = switch_channel_get_variable(chana, var))) {
+                       switch_channel_set_variable(chanb, var, val);
+               }
+       } else {
+               switch_hash_index_t *hi;
+               void *vval;
+               const void *vvar;
+
+               for (hi = switch_channel_variable_first(chana, switch_core_session_get_pool(sessa)); hi; hi = switch_hash_next(hi)) {
+                       switch_hash_this(hi, &vvar, NULL, &vval);
+                       if (vvar && vval) {
+                               switch_channel_set_variable(chanb, (char *) vvar, (char *) vval);
+                       }
+               }
+       }
 
+       return SWITCH_STATUS_SUCCESS;
+}