diff --git a/libs/libdingaling/src/libdingaling.c b/libs/libdingaling/src/libdingaling.c index bbec64e1a7..b91128ad1f 100644 --- a/libs/libdingaling/src/libdingaling.c +++ b/libs/libdingaling/src/libdingaling.c @@ -445,11 +445,29 @@ static int on_presence(void *user_data, ikspak *pak) { ldl_handle_t *handle = user_data; char *from = iks_find_attrib(pak->x, "from"); + char *type = iks_find_attrib(pak->x, "type"); + char *show = iks_find_cdata(pak->x, "show"); + char *status = iks_find_cdata(pak->x, "status"); char id[1024]; char *resource; struct ldl_buffer *buffer; size_t x; + ldl_signal_t signal; + + if (type && !strcasecmp(type, "unavailable")) { + signal = LDL_SIGNAL_PRESENCE_OUT; + } else { + signal = LDL_SIGNAL_PRESENCE_IN; + } + + if (!status) { + status = type; + } + if (handle->session_callback) { + handle->session_callback(handle, NULL, signal, from, status ? status : "n/a", show ? show : "n/a"); + } + if (!apr_hash_get(handle->sub_hash, from, APR_HASH_KEY_STRING)) { iks *msg; apr_hash_set(handle->sub_hash, apr_pstrdup(handle->pool, from), APR_HASH_KEY_STRING, &marker); diff --git a/libs/libdingaling/src/libdingaling.h b/libs/libdingaling/src/libdingaling.h index 68ce4e2b18..d18151648d 100644 --- a/libs/libdingaling/src/libdingaling.h +++ b/libs/libdingaling/src/libdingaling.h @@ -119,6 +119,8 @@ typedef enum { LDL_SIGNAL_INITIATE, LDL_SIGNAL_CANDIDATES, LDL_SIGNAL_MSG, + LDL_SIGNAL_PRESENCE_IN, + LDL_SIGNAL_PRESENCE_OUT, LDL_SIGNAL_TERMINATE, LDL_SIGNAL_ERROR, LDL_SIGNAL_LOGIN_SUCCESS, diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 4b8e9bafad..d37fa2a29f 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -83,6 +83,8 @@ struct switch_core_session_message { void *pointer_reply; /*! optional arbitrary pointer reply's size */ switch_size_t pointer_reply_size; + /*! message flags */ + switch_core_session_message_flag_t flags; }; /*! \brief A generic object to pass as a thread's session object to allow mutiple arguements and a pool */ @@ -421,6 +423,22 @@ SWITCH_DECLARE(void) switch_core_session_hupall(switch_call_cause_t cause); */ SWITCH_DECLARE (switch_status_t) switch_core_session_message_send(char *uuid_str, switch_core_session_message_t *message); +/*! + \brief Queue a message on a session + \param session the session to queue the message to + \param message the message to queue + \return SWITCH_STATUS_SUCCESS if the message was queued +*/ +SWITCH_DECLARE(switch_status_t) switch_core_session_queue_message(switch_core_session_t *session, switch_core_session_message_t *message); + +/*! + \brief DE-Queue an message on a given session + \param session the session to de-queue the message on + \param message the de-queued message + \return the SWITCH_STATUS_SUCCESS if the message was de-queued +*/ +SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_message(switch_core_session_t *session, switch_core_session_message_t **message); + /*! \brief Queue an event on another session using its uuid \param uuid_str the unique id of the session you want to send a message to diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 81ff52de7c..692f008b8f 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -247,7 +247,8 @@ typedef enum { SWITCH_MESSAGE_INDICATE_PROGRESS, SWITCH_MESSAGE_INDICATE_BRIDGE, SWITCH_MESSAGE_INDICATE_UNBRIDGE, - SWITCH_MESSAGE_INDICATE_TRANSFER + SWITCH_MESSAGE_INDICATE_TRANSFER, + SWITCH_MESSAGE_INDICATE_RINGING } switch_core_session_message_types_t; @@ -348,6 +349,10 @@ typedef enum { SWITCH_CHANNEL_ID_EVENT } switch_text_channel_t; +typedef enum { + SCSMF_DYNAMIC = (1 << 0) +} switch_core_session_message_flag_t; + #define SWITCH_UUID_FORMATTED_LENGTH APR_UUID_FORMATTED_LENGTH #define SWITCH_CHANNEL_LOG SWITCH_CHANNEL_ID_LOG, __FILE__, __FUNCTION__, __LINE__ #define SWITCH_CHANNEL_LOG_CLEAN SWITCH_CHANNEL_ID_LOG_CLEAN, __FILE__, __FUNCTION__, __LINE__ @@ -610,6 +615,7 @@ typedef enum { SWITCH_EVENT_MODULE_LOAD - Module was loaded SWITCH_EVENT_DTMF - DTMF was sent SWITCH_EVENT_MESSAGE - A Basic Message + SWITCH_EVENT_PRESENCE - Presence Info SWITCH_EVENT_CODEC - Codec Change SWITCH_EVENT_BACKGROUND_JOB - Background Job SWITCH_EVENT_ALL - All events at once @@ -644,6 +650,8 @@ typedef enum { SWITCH_EVENT_MODULE_LOAD, SWITCH_EVENT_DTMF, SWITCH_EVENT_MESSAGE, + SWITCH_EVENT_PRESENCE_IN, + SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_CODEC, SWITCH_EVENT_BACKGROUND_JOB, SWITCH_EVENT_ALL diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c index 85e887f174..3fc026b982 100644 --- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c +++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c @@ -38,7 +38,6 @@ #define DL_EVENT_LOGIN_SUCCESS "dingaling::login_success" #define DL_EVENT_LOGIN_FAILURE "dingaling::login_failure" -#define DL_EVENT_MESSAGE "dingaling::message" #define DL_EVENT_CONNECTED "dingaling::connected" static const char modname[] = "mod_dingaling"; @@ -1191,11 +1190,6 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_mod return SWITCH_STATUS_GENERR; } - if (switch_event_reserve_subclass(DL_EVENT_MESSAGE) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!", DL_EVENT_MESSAGE); - return SWITCH_STATUS_GENERR; - } - if (switch_event_reserve_subclass(DL_EVENT_CONNECTED) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!", DL_EVENT_CONNECTED); return SWITCH_STATUS_GENERR; @@ -1533,12 +1527,30 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi if (!dlsession) { switch(signal) { + case LDL_SIGNAL_PRESENCE_IN: + if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", profile->login); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", from); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", subject); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "show", msg); + switch_event_fire(&event); + } + break; + case LDL_SIGNAL_PRESENCE_OUT: + if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", profile->login); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", from); + switch_event_fire(&event); + } + break; case LDL_SIGNAL_MSG: - if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, DL_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) { + if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", profile->login); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", from); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "subject", subject); - switch_event_add_body(event, msg); + if (msg) { + switch_event_add_body(event, msg); + } switch_event_fire(&event); } break; @@ -1639,12 +1651,13 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SESSION MSG [%s]\n", msg); } - if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, DL_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) { + if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", profile->login); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", from); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "subject", subject); - switch_event_add_body(event, msg); - + if (msg) { + switch_event_add_body(event, msg); + } if (switch_core_session_queue_event(tech_pvt->session, &event) != SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true"); switch_event_fire(&event); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 4242398955..7ed814e6dd 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -42,6 +42,9 @@ struct outbound_reg; typedef struct outbound_reg outbound_reg_t; +struct sip_presence; +typedef struct sip_presence sip_presence_t; + struct sofia_profile; typedef struct sofia_profile sofia_profile_t; #define NUA_MAGIC_T sofia_profile_t @@ -49,6 +52,7 @@ typedef struct sofia_profile sofia_profile_t; struct sofia_private { switch_core_session_t *session; outbound_reg_t *oreg; + sip_presence_t *presence; }; typedef struct sofia_private sofia_private_t; @@ -113,7 +117,8 @@ typedef enum { PFLAG_AUTH_CALLS = (1 << 0), PFLAG_BLIND_REG = (1 << 1), PFLAG_AUTH_ALL = (1 << 2), - PFLAG_FULL_ID = (1 << 3) + PFLAG_FULL_ID = (1 << 3), + PFLAG_PRESENCE = (1 << 4) } PFLAGS; typedef enum { @@ -183,6 +188,14 @@ struct outbound_reg { struct outbound_reg *next; }; + +struct sip_presence { + sofia_private_t sofia_private; + nua_handle_t *nh; + sofia_profile_t *profile; +}; + + struct sofia_profile { int debug; char *name; @@ -216,6 +229,8 @@ struct sofia_profile { switch_mutex_t *ireg_mutex; switch_mutex_t *oreg_mutex; outbound_reg_t *registrations; + sip_presence_t *presence; + su_home_t *home; }; @@ -1311,6 +1326,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END()); + } } @@ -1605,6 +1621,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-activate timed RTP!\n"); } break; + case SWITCH_MESSAGE_INDICATE_RINGING: + nua_respond(tech_pvt->nh, SIP_180_RINGING, TAG_END()); + break; case SWITCH_MESSAGE_INDICATE_PROGRESS: { struct private_object *tech_pvt; switch_channel_t *channel = NULL; @@ -1809,11 +1828,11 @@ static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp) for (map = m->m_rtpmaps; map; map = map->rm_next) { int32_t i; - + if (!strcasecmp(map->rm_encoding, "telephone-event")) { tech_pvt->te = (switch_payload_t)map->rm_pt; } - + for (i = 0; i < tech_pvt->num_codecs; i++) { const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Codec Compare [%s:%d]/[%s:%d]\n", @@ -1823,7 +1842,7 @@ static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp) } else { match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1; } - + if (match && (map->rm_rate == imp->samples_per_second)) { tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *)map->rm_encoding); tech_pvt->pt = (switch_payload_t)map->rm_pt; @@ -1902,6 +1921,76 @@ static switch_call_cause_t sip_cause_to_freeswitch(int status) { } } +static void sip_i_message(int status, + char const *phrase, + nua_t *nua, + sofia_profile_t *profile, + nua_handle_t *nh, + sofia_private_t *sofia_private, + sip_t const *sip, + tagi_t tags[]) +{ + if (sip) { + sip_from_t const *from = sip->sip_from; + char *from_user = NULL; + char *from_host = NULL; + sip_to_t const *to = sip->sip_to; + char *to_user = NULL; + char *to_host = NULL; + sip_subject_t const *sip_subject = sip->sip_subject; + sip_payload_t *payload = sip->sip_payload; + const char *subject = "n/a"; + char *msg = ""; + + + if (from) { + from_user = (char *) from->a_url->url_user; + from_host = (char *) from->a_url->url_host; + } + + if (to) { + to_user = (char *) to->a_url->url_user; + to_host = (char *) to->a_url->url_host; + } + + if (payload) { + msg = payload->pl_data; + } + + if (sip_subject) { + subject = sip_subject->g_value; + } + + if (nh) { + char *message = "hello world"; + char buf[256] = ""; + + if (find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) { + nua_handle_t *msg_nh; + + + msg_nh = nua_handle(profile->nua, NULL, + SIPTAG_FROM(sip->sip_to), + SIPTAG_TO_STR(buf), + SIPTAG_CONTACT_STR(profile->url), + TAG_END()); + + + nua_message(msg_nh, + SIPTAG_CONTENT_TYPE_STR("text/plain"), + TAG_IF(message, + SIPTAG_PAYLOAD_STR(message)), + TAG_END()); + + nua_handle_destroy(msg_nh); + } + + } + //printf("==================================\nFrom: %s@%s\nSubject: %s\n\n%s\n\n",from_user,from_host,subject,msg); + } + +} + static void sip_i_state(int status, char const *phrase, nua_t *nua, @@ -1964,6 +2053,27 @@ static void sip_i_state(int status, break; case nua_callstate_proceeding: if (channel) { + if (status == 180) { + if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) { + switch_core_session_message_t msg; + msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING; + msg.from = __FILE__; + switch_core_session_receive_message(other_session, &msg); + switch_core_session_rwunlock(other_session); + } + + } else { + switch_core_session_message_t *msg; + if ((msg = malloc(sizeof(*msg)))) { + memset(msg, 0, sizeof(*msg)); + msg->message_id = SWITCH_MESSAGE_INDICATE_RINGING; + msg->from = __FILE__; + switch_core_session_queue_message(session, msg); + switch_set_flag(msg, SCSMF_DYNAMIC); + } + } + } if (r_sdp) { if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); @@ -2462,6 +2572,31 @@ static uint8_t handle_register(nua_t *nua, } +static void sip_i_subscribe(int status, + char const *phrase, + nua_t *nua, + sofia_profile_t *profile, + nua_handle_t *nh, + sofia_private_t *sofia_private, + sip_t const *sip, + tagi_t tags[]) +{ + nua_respond(nh, SIP_200_OK, + TAG_END()); +} + +static void sip_r_subscribe(int status, + char const *phrase, + nua_t *nua, + sofia_profile_t *profile, + nua_handle_t *nh, + sofia_private_t *sofia_private, + sip_t const *sip, + tagi_t tags[]) +{ + +} + /*---------------------------------------*/ static void sip_i_refer(nua_t *nua, @@ -2850,6 +2985,22 @@ static void sip_i_register(nua_t *nua, } +static void sip_i_options(int status, + char const *phrase, + nua_t *nua, + sofia_profile_t *profile, + nua_handle_t *nh, + sofia_private_t *sofia_private, + sip_t const *sip, + tagi_t tags[]) +{ + nua_respond(nh, SIP_200_OK, + //SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), + //SOATAG_AUDIO_AUX("cn telephone-event"), + //NUTAG_INCLUDE_EXTRA_SDP(1), + TAG_END()); +} + static void sip_r_register(int status, char const *phrase, @@ -3000,6 +3151,10 @@ static void event_callback(nua_event_t event, //sip_r_options(status, phrase, nua, profile, nh, sofia_private, sip, tags); break; + case nua_i_options: + sip_i_options(status, phrase, nua, profile, nh, sofia_private, sip, tags); + break; + case nua_i_fork: //sip_i_fork(status, phrase, nua, profile, nh, sofia_private, sip, tags); break; @@ -3033,7 +3188,7 @@ static void event_callback(nua_event_t event, break; case nua_i_message: - //sip_i_message(nua, profile, nh, sofia_private, sip, tags); + sip_i_message(status, phrase, nua, profile, nh, sofia_private, sip, tags); break; case nua_r_info: @@ -3053,7 +3208,11 @@ static void event_callback(nua_event_t event, break; case nua_r_subscribe: - //sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags); + sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags); + break; + + case nua_i_subscribe: + sip_i_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags); break; case nua_r_unsubscribe: @@ -3063,7 +3222,9 @@ static void event_callback(nua_event_t event, case nua_r_publish: //sip_r_publish(status, phrase, nua, profile, nh, sofia_private, sip, tags); break; - + case nua_r_notifier: + nua_respond(nh, SIP_200_OK, TAG_END()); + break; case nua_r_notify: //sip_r_notify(status, phrase, nua, profile, nh, sofia_private, sip, tags); break; @@ -3180,6 +3341,8 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void NUTAG_AUTOALERT(0), NUTAG_ALLOW("REGISTER"), NUTAG_ALLOW("REFER"), + TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")), + TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)), SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT), TAG_END()); @@ -3198,6 +3361,8 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void NUTAG_AUTOALERT(0), NUTAG_ALLOW("REGISTER"), NUTAG_ALLOW("REFER"), + TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")), + TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)), SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT), TAG_END()); @@ -3217,10 +3382,6 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void switch_mutex_init(&profile->ireg_mutex, SWITCH_MUTEX_NESTED, profile->pool); switch_mutex_init(&profile->oreg_mutex, SWITCH_MUTEX_NESTED, profile->pool); - switch_mutex_lock(globals.mutex); - globals.running = 1; - switch_mutex_unlock(globals.mutex); - ireg_loops = IREG_SECONDS; oreg_loops = OREG_SECONDS; @@ -3230,6 +3391,45 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void switch_event_fire(&s_event); } + if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._tcp"); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port); + switch_event_fire(&s_event); + } + + if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._sctp"); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port); + switch_event_fire(&s_event); + } + + if (profile->pflags & PFLAG_PRESENCE) { + if (!(profile->presence = switch_core_alloc(profile->pool, sizeof(*profile->presence)))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); + return NULL; + } + + profile->presence->nh = nua_handle(profile->nua, NULL, + TAG_END()); + profile->presence->sofia_private.presence = profile->presence; + nua_handle_bind(profile->presence->nh, &profile->presence->sofia_private); + + nua_notifier(profile->presence->nh, + NUTAG_URL(profile->url), + SIPTAG_EXPIRES_STR("3600"), + SIPTAG_FROM_STR(profile->url), + //SIPTAG_EVENT_STR("presence"), + SIPTAG_EVENT_STR("message-summary"), + //SIPTAG_ALLOW_EVENTS_STR("message-summary"), + SIPTAG_CONTENT_TYPE_STR("text/urllist"), + //SIPTAG_CONTENT_TYPE_STR("application/pidf-partial+xml"), + //SIPTAG_CONTENT_TYPE_STR("text/plain"), + NUTAG_SUBSTATE(nua_substate_pending), + TAG_END()); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Creating notifier for %s\n", profile->url); + } + while(globals.running == 1) { if (++ireg_loops >= IREG_SECONDS) { check_expire(profile, time(NULL)); @@ -3243,6 +3443,13 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void su_root_step(profile->s_root, 1000); } + + /* + if (profile->presence && profile->presence->nh) { + nua_handle_destroy(profile->presence->nh); + profile->presence->nh = NULL; + } + */ if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp"); @@ -3251,7 +3458,6 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void } su_root_destroy(profile->s_root); - pool = profile->pool; switch_core_destroy_memory_pool(&pool); switch_mutex_lock(globals.mutex); @@ -3285,6 +3491,10 @@ static switch_status_t config_sofia(int reload) sofia_profile_t *profile = NULL; char url[512] = ""; + switch_mutex_lock(globals.mutex); + globals.running = 1; + switch_mutex_unlock(globals.mutex); + if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf); status = SWITCH_STATUS_FALSE; @@ -3367,6 +3577,10 @@ static switch_status_t config_sofia(int reload) profile->sipdomain = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "rtp-timer-name")) { profile->timer_name = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "manage-presence")) { + if (switch_true(val)) { + profile->pflags |= PFLAG_PRESENCE; + } } else if (!strcasecmp(var, "auth-calls")) { if (switch_true(val)) { profile->pflags |= PFLAG_AUTH_CALLS; @@ -3588,6 +3802,58 @@ static void event_handler(switch_event_t *event) } } +static void msg_event_handler(switch_event_t *event) +{ + switch_hash_index_t *hi; + void *val; + sofia_profile_t *profile; + int open = 0; + char *from = switch_event_get_header(event, "from"); + //char *status = switch_event_get_header(event, "status"); + + switch(event->event_id) { + case SWITCH_EVENT_PRESENCE_IN: + open = 1; + break; + case SWITCH_EVENT_PRESENCE_OUT: + open = 0; + break; + default: + break; + } + + for (hi = switch_hash_first(apr_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, NULL, NULL, &val); + profile = (sofia_profile_t *) val; + if (profile && profile->presence) { + char *url; + char *myfrom = strdup(from); + char *p; + for(p = myfrom; *p ; p++) { + if (*p == '@') { + *p = '!'; + } + } + + url = switch_core_db_mprintf("sip:%s", myfrom); + + nua_publish(profile->presence->nh, + SIPTAG_EVENT_STR("presence"), + SIPTAG_CONTENT_TYPE_STR("text/urllist"), + SIPTAG_PAYLOAD_STR(url), + TAG_NULL()); + + switch_safe_free(url); + switch_safe_free(myfrom); + + } + + } + + + +} + SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename) { @@ -3614,7 +3880,20 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_mod config_sofia(0); + if (switch_event_bind((char *) modname, SWITCH_EVENT_MESSAGE, SWITCH_EVENT_SUBCLASS_ANY, msg_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + return SWITCH_STATUS_GENERR; + } + if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, msg_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + return SWITCH_STATUS_GENERR; + } + + if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, msg_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + return SWITCH_STATUS_GENERR; + } /* connect my internal structure to the blank pointer passed to me */ *module_interface = &sofia_module_interface; diff --git a/src/switch_core.c b/src/switch_core.c index a0d3e290a7..482c810c4a 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -50,6 +50,7 @@ #endif #define SWITCH_EVENT_QUEUE_LEN 256 +#define SWITCH_MESSAGE_QUEUE_LEN 256 #define SWITCH_SQL_QUEUE_LEN 2000 #define SWITCH_BUFFER_BLOCK_FRAMES 25 @@ -105,6 +106,7 @@ struct switch_core_session { char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; void *private_info; switch_queue_t *event_queue; + switch_queue_t *message_queue; switch_queue_t *private_event_queue; switch_thread_rwlock_t *bug_rwlock; switch_media_bug_t *bugs; @@ -1413,8 +1415,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_answer_channel(switch_core_s return status; } -SWITCH_DECLARE(switch_status_t) switch_core_session_receive_message(switch_core_session_t *session, - switch_core_session_message_t *message) +SWITCH_DECLARE(switch_status_t) switch_core_session_receive_message(switch_core_session_t *session, switch_core_session_message_t *message) { switch_io_event_hook_receive_message_t *ptr; switch_status_t status = SWITCH_STATUS_FALSE; @@ -1429,11 +1430,44 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_receive_message(switch_core_ } } } - } + } + return status; +} + +SWITCH_DECLARE(switch_status_t) switch_core_session_queue_message(switch_core_session_t *session, switch_core_session_message_t *message) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + assert(session != NULL); + + if (!session->message_queue) { + switch_queue_create(&session->message_queue, SWITCH_MESSAGE_QUEUE_LEN, session->pool); + } + + if (session->message_queue) { + if (switch_queue_trypush(session->message_queue, message) == SWITCH_STATUS_SUCCESS) { + status = SWITCH_STATUS_SUCCESS; + } + } return status; } +SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_message(switch_core_session_t *session, switch_core_session_message_t **message) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + void *pop; + + assert(session != NULL); + + if (session->message_queue) { + if ((status = (switch_status_t) switch_queue_trypop(session->message_queue, &pop)) == SWITCH_STATUS_SUCCESS) { + *message = (switch_core_session_message_t *) pop; + } + } + + return status; +} SWITCH_DECLARE(switch_status_t) switch_core_session_receive_event(switch_core_session_t *session, switch_event_t **event) diff --git a/src/switch_event.c b/src/switch_event.c index bffe06e410..dee2c387a7 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -123,6 +123,8 @@ static char *EVENT_NAMES[] = { "MODULE_LOAD", "DTMF", "MESSAGE", + "PRESENCE_IN", + "PRESENCE_OUT", "CODEC", "BACKGROUND_JOB", "ALL" diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 0ea5a05374..318bfa7977 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -1244,7 +1244,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) int *stream_id_p; int stream_id = 0, pre_b = 0, ans_a = 0, ans_b = 0, originator = 0; switch_input_callback_function_t input_callback; - switch_core_session_message_t msg = {0}; + switch_core_session_message_t *message, msg = {0}; void *user_data; switch_channel_t *chan_a, *chan_b; @@ -1297,62 +1297,65 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) break; } - if (!switch_channel_test_flag(chan_a, CF_HOLD)) { - - if (!ans_a && originator) { - if (!ans_b && switch_channel_test_flag(chan_b, CF_ANSWERED)) { - switch_channel_answer(chan_a); - ans_a++; - } else if (!pre_b && switch_channel_test_flag(chan_b, CF_EARLY_MEDIA)) { - switch_channel_pre_answer(chan_a); - pre_b++; + if (switch_core_session_dequeue_private_event(session_a, &event) == SWITCH_STATUS_SUCCESS) { + switch_channel_set_flag(chan_b, CF_HOLD); + switch_ivr_parse_event(session_a, event); + switch_channel_clear_flag(chan_b, CF_HOLD); + switch_event_destroy(&event); + } + + /* if 1 channel has DTMF pass it to the other */ + if (switch_channel_has_dtmf(chan_a)) { + char dtmf[128]; + switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf)); + switch_core_session_send_dtmf(session_b, dtmf); + + if (input_callback) { + if (input_callback(session_a, dtmf, SWITCH_INPUT_TYPE_DTMF, user_data, 0) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s ended call via DTMF\n", switch_channel_get_name(chan_a)); + switch_mutex_lock(data->mutex); + data->running = -1; + switch_mutex_unlock(data->mutex); + break; } - switch_yield(10000); - continue; + } + } + + if (switch_core_session_dequeue_event(session_a, &event) == SWITCH_STATUS_SUCCESS) { + if (input_callback) { + status = input_callback(session_a, event, SWITCH_INPUT_TYPE_EVENT, user_data, 0); } - if (switch_core_session_dequeue_private_event(session_a, &event) == SWITCH_STATUS_SUCCESS) { - switch_channel_set_flag(chan_b, CF_HOLD); - switch_ivr_parse_event(session_a, event); - switch_channel_clear_flag(chan_b, CF_HOLD); + if (switch_core_session_receive_event(session_b, &event) != SWITCH_STATUS_SUCCESS) { switch_event_destroy(&event); } - /* if 1 channel has DTMF pass it to the other */ - if (switch_channel_has_dtmf(chan_a)) { - char dtmf[128]; - switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf)); - switch_core_session_send_dtmf(session_b, dtmf); - - if (input_callback) { - if (input_callback(session_a, dtmf, SWITCH_INPUT_TYPE_DTMF, user_data, 0) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s ended call via DTMF\n", switch_channel_get_name(chan_a)); - switch_mutex_lock(data->mutex); - data->running = -1; - switch_mutex_unlock(data->mutex); - break; - } - } - } - - if (switch_core_session_dequeue_event(session_a, &event) == SWITCH_STATUS_SUCCESS) { - if (input_callback) { - status = input_callback(session_a, event, SWITCH_INPUT_TYPE_EVENT, user_data, 0); - } - - if (switch_core_session_receive_event(session_b, &event) != SWITCH_STATUS_SUCCESS) { - switch_event_destroy(&event); - } + } + if (switch_core_session_dequeue_message(session_b, &message) == SWITCH_STATUS_SUCCESS) { + switch_core_session_receive_message(session_a, message); + if (switch_test_flag(message, SCSMF_DYNAMIC)) { + switch_safe_free(message); } + } + if (!ans_a && originator) { + if (!ans_b && switch_channel_test_flag(chan_b, CF_ANSWERED)) { + switch_channel_answer(chan_a); + ans_a++; + } else if (!pre_b && switch_channel_test_flag(chan_b, CF_EARLY_MEDIA)) { + switch_channel_pre_answer(chan_a); + pre_b++; + } + switch_yield(10000); + continue; } /* read audio from 1 channel and write it to the other */ status = switch_core_session_read_frame(session_a, &read_frame, -1, stream_id); if (SWITCH_READ_ACCEPTABLE(status)) { - if (status != SWITCH_STATUS_BREAK) { + if (status != SWITCH_STATUS_BREAK && !switch_channel_test_flag(chan_a, CF_HOLD)) { if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "write: %s Bad Frame....[%u] Bubye!\n", switch_channel_get_name(chan_b), read_frame->datalen); @@ -1367,10 +1370,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) data->running = -1; switch_mutex_unlock(data->mutex); } - - //switch_yield(1000); } - msg.message_id = SWITCH_MESSAGE_INDICATE_UNBRIDGE; msg.from = __FILE__; @@ -1968,6 +1968,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess while ((!caller_channel || switch_channel_ready(caller_channel)) && check_channel_status(peer_channels, peer_sessions, and_argc, &idx, file, key) && ((time(NULL) - start) < (time_t)timelimit_sec)) { + if (or_argc == 1 && and_argc == 1) { /* when there is only 1 channel to call and bridge */ + switch_core_session_message_t *message = NULL; + if (switch_core_session_dequeue_message(peer_sessions[0], &message) == SWITCH_STATUS_SUCCESS) { + switch_core_session_receive_message(session, message); + if (switch_test_flag(message, SCSMF_DYNAMIC)) { + switch_safe_free(message); + } + } + } /* read from the channel while we wait if the audio is up on it */ if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA) &&