FS-3758 --resolve ok so I wrote my own patch but i did borrow the 2 lines of code to create a seq from the original patch! sofia changes probably need to be converted to a tag if they are to go upstream. This completely manages sub/pub from inside mod_sofia inside the db and subs can now persist and/or fail over mid dialog tested on several things like polycom/snom/yealink on SLA and presence

This commit is contained in:
Anthony Minessale 2011-12-15 16:30:33 -06:00
parent e164b76caf
commit e9bde2eb0e
9 changed files with 314 additions and 723 deletions

View File

@ -827,10 +827,10 @@ static int nua_notify_usage_shutdown(nua_handle_t *nh,
nua_dialog_usage_t *du) nua_dialog_usage_t *du)
{ {
struct notifier_usage *nu = nua_dialog_usage_private(du); struct notifier_usage *nu = nua_dialog_usage_private(du);
nua_client_request_t *cr = du->du_cr; //nua_client_request_t *cr = du->du_cr;
nu->nu_substate = nua_substate_terminated; nu->nu_substate = nua_substate_terminated;
#if 0
if (cr) { if (cr) {
SU_DEBUG_5(("%s(%p, %p, %p): using existing cr=%p\n", SU_DEBUG_5(("%s(%p, %p, %p): using existing cr=%p\n",
"nua_notify_usage_shutdown", "nua_notify_usage_shutdown",
@ -852,7 +852,7 @@ static int nua_notify_usage_shutdown(nua_handle_t *nh,
TAG_END()) >= 0) TAG_END()) >= 0)
return 0; return 0;
} }
#endif
nua_dialog_usage_remove(nh, ds, du, NULL, NULL); nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
return 200; return 200;
} }

View File

@ -158,14 +158,15 @@ int nua_stack_process_request(nua_handle_t *nh,
/* These must be in-dialog */ /* These must be in-dialog */
sm = NULL; sm = NULL;
} }
else if (initial && sip->sip_to->a_tag) { else if (initial && sip->sip_to->a_tag && method != sip_method_subscribe) {
/* RFC 3261 section 12.2.2: /* RFC 3261 section 12.2.2:
If the UAS wishes to reject the request because it does not wish to If the UAS wishes to reject the request because it does not wish to
recreate the dialog, it MUST respond to the request with a 481 recreate the dialog, it MUST respond to the request with a 481
(Call/Transaction Does Not Exist) status code and pass that to the (Call/Transaction Does Not Exist) status code and pass that to the
server transaction. server transaction.
*/ */ /* we allow this on subscribes because we have disabled the built-in notify server and we need those messages in the application layer */
if (method == sip_method_info) if (method == sip_method_info)
/* accept out-of-dialog info */; else /* accept out-of-dialog info */; else
if (method != sip_method_message || !NH_PGET(nh, win_messenger_enable)) if (method != sip_method_message || !NH_PGET(nh, win_messenger_enable))

View File

@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua
SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la
mod_LTLIBRARIES = mod_sofia.la mod_LTLIBRARIES = mod_sofia.la
mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_sla.c sip-dig.c mod_sofia.h mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c mod_sofia.h
mod_sofia_la_CFLAGS = $(AM_CFLAGS) -I. $(SOFIA_CMD_LINE_CFLAGS) mod_sofia_la_CFLAGS = $(AM_CFLAGS) -I. $(SOFIA_CMD_LINE_CFLAGS)
mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf
mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http

View File

@ -217,7 +217,7 @@ typedef enum {
PFLAG_UUID_AS_CALLID, PFLAG_UUID_AS_CALLID,
PFLAG_SCROOGE, PFLAG_SCROOGE,
PFLAG_MANAGE_SHARED_APPEARANCE, PFLAG_MANAGE_SHARED_APPEARANCE,
PFLAG_MANAGE_SHARED_APPEARANCE_SYLANTRO, PFLAG_MANAGE_SHARED_APPEARANCE_SYLANTRO_DELETED_USE_ME,
PFLAG_DISABLE_SRV, PFLAG_DISABLE_SRV,
PFLAG_DISABLE_SRV503, PFLAG_DISABLE_SRV503,
PFLAG_DISABLE_NAPTR, PFLAG_DISABLE_NAPTR,
@ -634,6 +634,7 @@ struct sofia_profile {
int watchdog_enabled; int watchdog_enabled;
switch_mutex_t *gw_mutex; switch_mutex_t *gw_mutex;
uint32_t queued_events; uint32_t queued_events;
uint32_t cseq_base;
}; };
struct private_object { struct private_object {
@ -1064,24 +1065,6 @@ 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); void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout);
void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *t38_options, int insist); void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *t38_options, int insist);
/*
* SLA (shared line appearance) entrypoints
*/
void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip,
sofia_dispatch_event_t *de, long exptime, const char *full_contact);
void sofia_sla_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip,
sofia_dispatch_event_t *de, tagi_t tags[]);
void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip,
sofia_dispatch_event_t *de, tagi_t tags[]);
void sofia_sla_handle_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,
sofia_dispatch_event_t *de,
tagi_t tags[]);
void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip,
sofia_dispatch_event_t *de, tagi_t tags[]);
/* /*
* Logging control functions * Logging control functions
*/ */
@ -1145,3 +1128,4 @@ char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, sof
void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on); void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on);
void sofia_process_dispatch_event(sofia_dispatch_event_t **dep); void sofia_process_dispatch_event(sofia_dispatch_event_t **dep);
char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool); char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool);
void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now);

View File

@ -90,7 +90,8 @@ void sofia_handle_sip_r_notify(switch_core_session_t *session, int status,
if (status >= 300 && sip && sip->sip_call_id && (!sofia_private || !sofia_private->is_call)) { if (status >= 300 && sip && sip->sip_call_id && (!sofia_private || !sofia_private->is_call)) {
char *sql; char *sql;
sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", sip->sip_call_id->i_id);
sql = switch_mprintf("update sip_subscriptions set expires=%ld where call_id='%q'", (long) switch_epoch_time_now(NULL), sip->sip_call_id->i_id);
switch_assert(sql != NULL); switch_assert(sql != NULL);
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
nua_handle_destroy(nh); nua_handle_destroy(nh);
@ -238,19 +239,21 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip,
switch_stream_handle_t stream = { 0 }; switch_stream_handle_t stream = { 0 };
int x = 0; int x = 0;
SWITCH_STANDARD_STREAM(stream); if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
SWITCH_STANDARD_STREAM(stream);
for(vp = sip->sip_via; vp; vp = vp->v_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
stream.write_function(&stream, x == 0 ? "%s" : ",%s", v);
su_free(nh->nh_home, v);
x++; for(vp = sip->sip_via; vp; vp = vp->v_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
stream.write_function(&stream, x == 0 ? "%s" : ",%s", v);
su_free(nh->nh_home, v);
x++;
}
switch_channel_set_variable(channel, "sip_recover_via", (char *)stream.data);
free(stream.data);
} }
switch_channel_set_variable(channel, "sip_recover_via", (char *)stream.data);
free(stream.data);
} }
if (sip->sip_from) { if (sip->sip_from) {
@ -337,21 +340,6 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
goto error; goto error;
} }
/* the following could be refactored back to the calling event handler here in sofia.c XXX MTK */
/* potentially interesting note: for Linksys shared appearance, we'll probably have to set up to get bare notifies
* and pass them inward to the sla handler. we'll have to set NUTAG_APPL_METHOD("NOTIFY") when creating
* nua, and also pick them off special elsewhere here in sofia.c - MTK
* *and* for Linksys, I believe they use "sa" as their magic appearance agent name for those blind notifies, so
* we'll probably have to change to match
*/
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) {
sofia_sla_handle_sip_i_notify(nua, profile, nh, sip, de, tags);
goto end;
}
}
/* Automatically return a 200 OK for Event: keep-alive */ /* Automatically return a 200 OK for Event: keep-alive */
if (!strcasecmp(sip->sip_event->o_type, "keep-alive")) { if (!strcasecmp(sip->sip_event->o_type, "keep-alive")) {
/* XXX MTK - is this right? in this case isn't sofia is already sending a 200 itself also? */ /* XXX MTK - is this right? in this case isn't sofia is already sending a 200 itself also? */
@ -4077,8 +4065,9 @@ switch_status_t config_sofia(int reload, char *profile_name)
sofia_set_pflag(profile, PFLAG_MULTIREG); sofia_set_pflag(profile, PFLAG_MULTIREG);
} else if (!strcasecmp(val, "sylantro")) { } else if (!strcasecmp(val, "sylantro")) {
profile->sla_contact = switch_core_sprintf(profile->pool, "sla-agent"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
sofia_set_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE_SYLANTRO); "Sylantro support has been removed.\n"
"It was incomplete anyway, and we fully support the broadsoft SCA shared line spec.");
} }
} else if (!strcasecmp(var, "disable-srv")) { } else if (!strcasecmp(var, "disable-srv")) {
if (switch_true(val)) { if (switch_true(val)) {

View File

@ -5904,7 +5904,8 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
" network_port VARCHAR(6),\n" " network_port VARCHAR(6),\n"
" network_ip VARCHAR(255),\n" " network_ip VARCHAR(255),\n"
" version INTEGER DEFAULT 0 NOT NULL,\n" " version INTEGER DEFAULT 0 NOT NULL,\n"
" orig_proto VARCHAR(255)\n" " orig_proto VARCHAR(255),\n"
" full_to VARCHAR(255)\n"
");\n"; ");\n";
char auth_sql[] = char auth_sql[] =
@ -6047,10 +6048,8 @@ int sofia_glue_init_sql(sofia_profile_t *profile)
free(test_sql); free(test_sql);
test_sql = switch_mprintf("delete from sip_subscriptions where hostname='%q' and full_to='XXX'", mod_sofia_globals.hostname);
test_sql = switch_mprintf("delete from sip_subscriptions where hostname='%q' "
"and (version < 0 or orig_proto like '%%' or network_ip like '%%' or network_port like '%%')",
mod_sofia_globals.hostname);
switch_cache_db_test_reactive(dbh, test_sql, "DROP TABLE sip_subscriptions", sub_sql); switch_cache_db_test_reactive(dbh, test_sql, "DROP TABLE sip_subscriptions", sub_sql);
free(test_sql); free(test_sql);

View File

@ -537,14 +537,14 @@ static void actual_sofia_presence_mwi_event_handler(switch_event_t *event)
if (for_everyone) { if (for_everyone) {
sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from," sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,"
"full_via,expires,user_agent,accept,profile_name,network_ip" "full_via,expires,user_agent,accept,profile_name,network_ip"
",'%q','%q' from sip_subscriptions where version > -1 and expires > -1 and event='message-summary' " ",'%q',full_to,network_ip,network_port from sip_subscriptions where version > -1 and expires > -1 and event='message-summary' "
"and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%')", stream.data, host, user, host, host); "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%')", stream.data, user, host, host);
} else if (sub_call_id) { } else if (sub_call_id) {
sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from," sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,"
"full_via,expires,user_agent,accept,profile_name,network_ip" "full_via,expires,user_agent,accept,profile_name,network_ip"
",'%q','%q' from sip_subscriptions where version > -1 and expires > -1 and event='message-summary' " ",'%q',full_to,network_ip,network_port from sip_subscriptions where version > -1 and expires > -1 and event='message-summary' "
"and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%' and call_id='%q')", "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%' and call_id='%q')",
stream.data, host, user, host, host, sub_call_id); stream.data, user, host, host, sub_call_id);
} }
@ -798,7 +798,7 @@ static void do_dialog_probe(sofia_profile_t *profile, switch_event_t *event)
// The dialog_probe_callback has built up the dialogs to be included in the NOTIFY. // The dialog_probe_callback has built up the dialogs to be included in the NOTIFY.
// Now send the "full" dialog event to the triggering subscription. // Now send the "full" dialog event to the triggering subscription.
sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,version, " sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,version, "
"'full' " "'full',full_to,full_from,contact,expires,event,network_ip,network_port "
"from sip_subscriptions " "from sip_subscriptions "
"where expires > -1 and hostname='%q' " "where expires > -1 and hostname='%q' "
"and sub_to_user='%q' and sub_to_host='%q' " "and (event='dialog') and " "and sub_to_user='%q' and sub_to_host='%q' " "and (event='dialog') and "
@ -887,7 +887,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
"sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from," "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,"
"sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent," "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
"sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip" "sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip"
",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed " ",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'','','','','sip',"
" sip_subscriptions.full_to,sip_subscriptions.network_ip,sip_subscriptions.network_port "
"from sip_subscriptions left join sip_presence on " "from sip_subscriptions left join sip_presence on "
"(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and " "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and "
"sip_subscriptions.profile_name=sip_presence.profile_name) " "sip_subscriptions.profile_name=sip_presence.profile_name) "
@ -900,7 +901,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
"sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from," "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,"
"sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent," "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
"sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip" "sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip"
",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed " ",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'','','','','sip',"
"sip_subscriptions.full_to,sip_subscriptions.network_ip,sip_subscriptions.network_port "
"from sip_subscriptions left join sip_presence on " "from sip_subscriptions left join sip_presence on "
"(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and " "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and "
"sip_subscriptions.profile_name=sip_presence.profile_name) " "sip_subscriptions.profile_name=sip_presence.profile_name) "
@ -1028,7 +1030,6 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
call_info, call_info_state, mod_sofia_globals.hostname, euser, host, euser, host, call_info); call_info, call_info_state, mod_sofia_globals.hostname, euser, host, euser, host, call_info);
} }
//printf("WTF %s\n", sql);
if (mod_sofia_globals.debug_sla > 1) { if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STATE SQL %s\n", sql); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STATE SQL %s\n", sql);
@ -1068,7 +1069,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
"sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent," "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
"sip_subscriptions.accept,sip_subscriptions.profile_name" "sip_subscriptions.accept,sip_subscriptions.profile_name"
",'%q','%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'%q','%q'," ",'%q','%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'%q','%q',"
"sip_subscriptions.version, '%q',sip_subscriptions.orig_proto " "sip_subscriptions.version, '%q',sip_subscriptions.orig_proto,sip_subscriptions.full_to,"
"sip_subscriptions.network_ip, sip_subscriptions.network_port "
"from sip_subscriptions " "from sip_subscriptions "
"left join sip_presence on " "left join sip_presence on "
"(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and " "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and "
@ -1638,6 +1640,111 @@ static int sofia_dialog_probe_callback(void *pArg, int argc, char **argv, char *
return 0; return 0;
} }
static void send_presence_notify(sofia_profile_t *profile,
const char *full_to,
const char *full_from,
const char *contact,
const char *expires,
const char *call_id,
const char *event,
const char *remote_ip,
const char *remote_port,
const char *ct,
const char *pl,
const char *call_info
)
{
char sstr[128] = "";
nua_handle_t *nh;
int exptime = 0;
char expires_str[10] = "";
char *tmp, *route = NULL;
sip_cseq_t *cseq = NULL;
uint32_t callsequence;
uint32_t now = (uint32_t) switch_epoch_time_now(NULL);
if (expires) {
long ltmp = atol(expires);
if (ltmp > 0) {
exptime = (ltmp - now);
} else {
exptime = 0;
}
}
switch_mutex_lock(profile->ireg_mutex);
if (!profile->cseq_base) {
profile->cseq_base = (now - 1312693200) * 10;
}
callsequence = ++profile->cseq_base;
switch_mutex_unlock(profile->ireg_mutex);
nh = nua_handle(profile->nua, NULL, TAG_END());
cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY);
nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
if (exptime > 0) {
switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned) exptime);
} else {
switch_snprintf(sstr, sizeof(sstr), "terminated;reason=noresource");
}
tmp = (char *)contact;
contact = sofia_glue_get_url_from_contact(tmp, 0);
if (remote_ip && remote_port) {
route = switch_mprintf("sip:%s:%s", remote_ip, remote_port);
}
if (mod_sofia_globals.debug_presence > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SEND PRES NOTIFY:\n"
"route[%s]\ncontact[%s]\nto[%s]\nfrom[%s]\nurl[%s]\ncall_id[%s]\nexpires_str[%s]\n"
"event[%s]\nct[%s]\npl[%s]\ncall_info[%s]\nexptime[%ld]\n",
route,
contact,
full_to,
full_from,
profile->url,
call_id,
expires_str,
event,
switch_str_nil(ct),
switch_str_nil(pl),
switch_str_nil(call_info),
(long)exptime
);
}
nua_notify(nh,
NUTAG_NEWSUB(1),
TAG_IF(route, NUTAG_PROXY(route)),
NUTAG_URL(contact),
SIPTAG_FROM_STR(full_to),
SIPTAG_TO_STR(full_from),
SIPTAG_CONTACT_STR(profile->url),
SIPTAG_CALL_ID_STR(call_id),
TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)),
SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
SIPTAG_EVENT_STR(event),
TAG_IF(!zstr(ct), SIPTAG_CONTENT_TYPE_STR(ct)),
TAG_IF(!zstr(pl), SIPTAG_PAYLOAD_STR(pl)),
TAG_IF(!zstr(call_info), SIPTAG_CALL_INFO_STR(call_info)),
TAG_IF(!exptime, SIPTAG_EXPIRES_STR("0")),
SIPTAG_CSEQ(cseq),
TAG_END());
switch_safe_free(route);
}
static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv, char **columnNames) static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv, char **columnNames)
{ {
struct rfc4235_helper *sh = (struct rfc4235_helper *) pArg; struct rfc4235_helper *sh = (struct rfc4235_helper *) pArg;
@ -1650,21 +1757,18 @@ static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv,
char *event = argv[4]; char *event = argv[4];
char *version = argv[5]; char *version = argv[5];
char *notify_state = argv[6]; char *notify_state = argv[6];
char *full_to = argv[7];
char *full_from = argv[8];
char *contact = argv[9];
char *remote_ip = argv[10];
char *remote_port = argv[11];
switch_stream_handle_t stream = { 0 }; switch_stream_handle_t stream = { 0 };
nua_handle_t *nh;
time_t exptime = switch_epoch_time_now(NULL) + 3600;
char sstr[128] = "";
char expires_str[10] = "";
char *to; char *to;
const char *pl = NULL; const char *pl = NULL;
const char *ct = "application/dialog-info+xml"; const char *ct = "application/dialog-info+xml";
if (!(nh = nua_handle_by_call_id(sh->profile->nua, call_id))) {
switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_DEBUG, "sofia_dialog_probe_notify_callback: could not find nua handle (old subscription)\n");
return 0;
}
if (mod_sofia_globals.debug_presence > 0) { if (mod_sofia_globals.debug_presence > 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
"SEND DIALOG\nTo: \t%s@%s\nFrom: \t%s@%s\nCall-ID: \t%s\n", "SEND DIALOG\nTo: \t%s@%s\nFrom: \t%s@%s\nCall-ID: \t%s\n",
@ -1698,25 +1802,25 @@ static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv,
pl = stream.data; pl = stream.data;
ct = "application/dialog-info+xml"; ct = "application/dialog-info+xml";
nua_handle_bind(nh, &mod_sofia_globals.keep_private);
if (expires) {
long tmp = atol(expires);
exptime = tmp - switch_epoch_time_now(NULL);
}
if (exptime > 0) {
switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned) exptime);
} else {
switch_snprintf(sstr, sizeof(sstr), "terminated;reason=timeout");
}
if (mod_sofia_globals.debug_presence > 0 && pl) { if (mod_sofia_globals.debug_presence > 0 && pl) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send payload:\n%s\n", pl); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send payload:\n%s\n", pl);
} }
nua_notify(nh,
TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)), send_presence_notify(sh->profile,
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR(ct), SIPTAG_PAYLOAD_STR(pl), TAG_END()); full_to,
full_from,
contact,
expires,
call_id,
event,
remote_ip,
remote_port,
ct,
pl,
NULL
);
switch_safe_free(to); switch_safe_free(to);
switch_safe_free(stream.data); switch_safe_free(stream.data);
@ -1862,12 +1966,17 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
struct presence_helper *helper = (struct presence_helper *) pArg; struct presence_helper *helper = (struct presence_helper *) pArg;
char *pl = NULL; char *pl = NULL;
char *clean_id = NULL, *id = NULL; char *clean_id = NULL, *id = NULL;
char *proto = argv[0]; char *proto = argv[0];
char *user = argv[1]; char *user = argv[1];
char *host = argv[2]; char *host = argv[2];
char *sub_to_user = argv[3]; char *sub_to_user = argv[3];
char *event = argv[5]; char *event = argv[5];
char *contact = argv[6];
char *call_id = argv[7]; char *call_id = argv[7];
char *full_from = argv[8];
//char *full_via = argv[9];
char *expires = argv[10]; char *expires = argv[10];
char *user_agent = argv[11]; char *user_agent = argv[11];
char *profile_name = argv[13]; char *profile_name = argv[13];
@ -1880,16 +1989,14 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
char *dialog_rpid = NULL; char *dialog_rpid = NULL;
const char *ct = "no/idea"; const char *ct = "no/idea";
nua_handle_t *nh;
char *to = NULL; char *to = NULL;
char *open; char *open;
char *prpid; char *prpid;
time_t exptime = switch_epoch_time_now(NULL) + 3600;
int is_dialog = 0; int is_dialog = 0;
sofia_profile_t *ext_profile = NULL, *profile = helper->profile; sofia_profile_t *ext_profile = NULL, *profile = helper->profile;
char sstr[128] = "";
int kill_handle = 0;
char expires_str[10] = "";
char status_line[256] = ""; char status_line[256] = "";
char *version = "0"; char *version = "0";
char *presence_id = NULL; char *presence_id = NULL;
@ -1897,14 +2004,17 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
int holding = 0; int holding = 0;
char *orig_proto = NULL; char *orig_proto = NULL;
int skip_proto = 0; int skip_proto = 0;
char *full_to = NULL;
char *ip = NULL;
char *port = 0;
if (mod_sofia_globals.debug_presence > 0) {
//int i; int i;
for(i = 0; i < argc; i++) {
//for(i = 0; i < argc; i++) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]);
//printf("arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]); }
//} DUMP_EVENT(helper->event);
//DUMP_EVENT(helper->event); }
if (argc > 18) { if (argc > 18) {
if (!zstr(argv[17])) { if (!zstr(argv[17])) {
@ -1922,6 +2032,9 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
version = argv[22]; version = argv[22];
presence_id = argv[23]; presence_id = argv[23];
orig_proto = argv[24]; orig_proto = argv[24];
full_to = argv[25];
ip = argv[26];
port = argv[27];
} }
if (!zstr(presence_id) && strchr(presence_id, '@')) { if (!zstr(presence_id) && strchr(presence_id, '@')) {
@ -1969,34 +2082,25 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
} }
} }
if (!(nh = nua_handle_by_call_id(profile->nua, call_id))) {
if (mod_sofia_globals.debug_presence > 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find handle for call id %s\n", call_id);
}
goto end;
}
if (expires) {
long tmp = atol(expires);
if (tmp > 0) {
exptime = tmp - switch_epoch_time_now(NULL); // - SUB_OVERLAP;
} else {
exptime = tmp;
}
}
if (!rpid) {
rpid = "unknown";
}
if (!strcasecmp(proto, SOFIA_CHAT_PROTO) || skip_proto) { if (!strcasecmp(proto, SOFIA_CHAT_PROTO) || skip_proto) {
clean_id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host); clean_id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
} else { } else {
clean_id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host); clean_id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
} }
if (!rpid) {
rpid = "unknown";
}
// if (!strcasecmp(proto, SOFIA_CHAT_PROTO) || skip_proto) {
// clean_id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
//} else {
// clean_id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
//}
if (mod_sofia_globals.debug_presence > 0) { if (mod_sofia_globals.debug_presence > 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
"SEND PRESENCE\nTo: \t%s@%s\nFrom: \t%s@%s\nCall-ID: \t%s\nProfile:\t%s [%s]\n\n", "SEND PRESENCE\nTo: \t%s@%s\nFrom: \t%s@%s\nCall-ID: \t%s\nProfile:\t%s [%s]\n\n",
@ -2220,7 +2324,6 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
if (!zstr(astate) && !zstr(uuid) && if (!zstr(astate) && !zstr(uuid) &&
helper && helper->stream.data && strcmp(helper->last_uuid, uuid) && strcasecmp(astate, "terminated") && strchr(uuid, '-')) { helper && helper->stream.data && strcmp(helper->last_uuid, uuid) && strcasecmp(astate, "terminated") && strchr(uuid, '-')) {
helper->stream.write_function(&helper->stream, "update sip_dialogs set state='%s' where uuid='%s';", astate, uuid); helper->stream.write_function(&helper->stream, "update sip_dialogs set state='%s' where uuid='%s';", astate, uuid);
//printf("WTF update sip_dialogs set state='%s' where uuid='%s';\n", astate, uuid);
switch_copy_string(helper->last_uuid, uuid, sizeof(helper->last_uuid)); switch_copy_string(helper->last_uuid, uuid, sizeof(helper->last_uuid));
} }
@ -2347,40 +2450,11 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
if (!zstr(uuid) && strchr(uuid, '-') && !zstr(status_line) && !zstr(rpid) && (zstr(register_source) || strcasecmp(register_source, "register"))) { if (!zstr(uuid) && strchr(uuid, '-') && !zstr(status_line) && !zstr(rpid) && (zstr(register_source) || strcasecmp(register_source, "register"))) {
char *sql = switch_mprintf("update sip_dialogs set rpid='%q',status='%q' where uuid='%q'", rpid, status_line, uuid); char *sql = switch_mprintf("update sip_dialogs set rpid='%q',status='%q' where uuid='%q'", rpid, status_line, uuid);
//printf("WTF %s\n", sql);
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
} }
} }
send_presence_notify(profile, full_to, full_from, contact, expires, call_id, event, ip, port, ct, pl, NULL);
nua_handle_bind(nh, &mod_sofia_globals.keep_private);
if (helper->event && helper->event->event_id == SWITCH_EVENT_PRESENCE_OUT) {
switch_set_string(sstr, "terminated;reason=noresource");
switch_set_string(expires_str, "0");
kill_handle = 1;
} else if (exptime > 0) {
switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned) exptime);
} else {
unsigned delta = (unsigned) (exptime * -1);
switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", delta);
switch_snprintf(expires_str, sizeof(expires_str), "%u", delta);
if (nh && nh->nh_ds && nh->nh_ds->ds_usage) {
nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, delta, delta);
}
}
if (mod_sofia_globals.debug_presence > 0 && pl) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "send payload:\n%s\n", pl);
}
nua_notify(nh,
TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)),
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR(ct), SIPTAG_PAYLOAD_STR(pl), TAG_END());
nua_handle_unref(nh);
end:
switch_safe_free(free_me); switch_safe_free(free_me);
@ -2393,25 +2467,24 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
switch_safe_free(pl); switch_safe_free(pl);
switch_safe_free(to); switch_safe_free(to);
if (nh && kill_handle) {
nua_handle_destroy(nh);
}
return 0; return 0;
} }
static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char **columnNames) static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char **columnNames)
{ {
char *sub_to_user = argv[3]; //char *sub_to_user = argv[3];
char *sub_to_host = argv[15]; //char *sub_to_host = argv[4];
char *event = argv[5]; char *event = argv[5];
char *contact = argv[6];
char *call_id = argv[7]; char *call_id = argv[7];
char *full_from = argv[8];
char *expires = argv[10]; char *expires = argv[10];
char *profile_name = argv[13]; char *profile_name = argv[13];
char *body = argv[15]; char *body = argv[15];
char *id = NULL; char *full_to = argv[16];
nua_handle_t *nh; char *remote_ip = argv[17];
int expire_sec = atoi(expires); char *remote_port = argv[18];
struct mwi_helper *h = (struct mwi_helper *) pArg; struct mwi_helper *h = (struct mwi_helper *) pArg;
sofia_profile_t *ext_profile = NULL, *profile = h->profile; sofia_profile_t *ext_profile = NULL, *profile = h->profile;
@ -2421,31 +2494,23 @@ static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char *
} }
} }
if (!(nh = nua_handle_by_call_id(h->profile->nua, call_id))) { send_presence_notify(profile,
if (profile->debug) { full_to,
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot find handle for %s\n", call_id); full_from,
} contact,
goto end; expires,
} call_id,
event,
remote_ip,
remote_port,
"application/simple-message-summary",
body,
NULL
);
id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
expire_sec = (int) (expire_sec - switch_epoch_time_now(NULL));
if (expire_sec < 0) {
expire_sec = 3600;
}
nua_handle_bind(nh, &mod_sofia_globals.keep_private);
nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR("active"),
SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"), SIPTAG_PAYLOAD_STR(body), TAG_END());
nua_handle_unref(nh);
switch_safe_free(id);
h->total++; h->total++;
end:
if (ext_profile) { if (ext_profile) {
sofia_glue_release_profile(ext_profile); sofia_glue_release_profile(ext_profile);
} }
@ -2488,14 +2553,11 @@ static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char
char key[256] = ""; char key[256] = "";
char *data = NULL, *tmp; char *data = NULL, *tmp;
char *call_id = argv[0]; char *call_id = argv[0];
char *expires = argv[1]; //char *expires = argv[1];
char *user = argv[2]; char *user = argv[2];
char *host = argv[3]; char *host = argv[3];
char *event = argv[4]; char *event = argv[4];
int i; int i;
char sstr[128] = "", expires_str[128] = "";
time_t exptime = 3600;
nua_handle_t *nh;
if (mod_sofia_globals.debug_sla > 1) { if (mod_sofia_globals.debug_sla > 1) {
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
@ -2505,19 +2567,7 @@ static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char
switch_snprintf(key, sizeof(key), "%s%s", user, host); switch_snprintf(key, sizeof(key), "%s%s", user, host);
data = switch_core_hash_find(sh->hash, key); data = switch_core_hash_find(sh->hash, key);
if (expires) {
long tmp = atol(expires);
exptime = tmp - switch_epoch_time_now(NULL);
}
if (exptime > 0) {
switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned) exptime);
} else {
switch_snprintf(sstr, sizeof(sstr), "terminated;reason=noresource");
}
switch_snprintf(expires_str, sizeof(expires_str), "%u", (unsigned) exptime);
data = switch_core_hash_find(sh->hash, key); data = switch_core_hash_find(sh->hash, key);
@ -2527,26 +2577,23 @@ static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char
tmp = switch_core_sprintf(sh->pool, "<sip:%s>;appearance-index=*;appearance-state=idle", host); tmp = switch_core_sprintf(sh->pool, "<sip:%s>;appearance-index=*;appearance-state=idle", host);
} }
if (!strcasecmp(event, "line-seize") && (nh = nua_handle_by_call_id(sh->profile->nua, call_id))) {
if (!strcasecmp(event, "line-seize")) {
char *hack; char *hack;
if ((hack = (char *) switch_stristr("=seized", tmp))) { if ((hack = (char *) switch_stristr("=seized", tmp))) {
switch_snprintf(hack, 7, "=idle "); switch_snprintf(hack, 7, "=idle ");
} }
nua_notify(nh,
SIPTAG_EXPIRES_STR("0"),
SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_EVENT_STR("line-seize"), SIPTAG_CALL_INFO_STR(tmp), TAG_END());
nua_handle_unref(nh);
return 0;
} }
if (!strcasecmp(event, "call-info") && (nh = nua_handle_by_call_id(sh->profile->nua, call_id))) { if (mod_sofia_globals.debug_sla > 1) {
nua_notify(nh, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DB PRES NOTIFY: [%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n",
TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)), argv[5], argv[6], argv[7], argv[8], call_id, event, argv[9], argv[10], tmp);
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR("call-info"), SIPTAG_CALL_INFO_STR(tmp), TAG_END());
nua_handle_unref(nh);
} }
send_presence_notify(sh->profile, argv[5], argv[6], argv[7], argv[8], call_id, event, argv[9], argv[10], NULL, NULL, tmp);
return 0; return 0;
} }
@ -2667,13 +2714,13 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char *
if (unseize) { if (unseize) {
sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event " sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port "
"from sip_subscriptions " "from sip_subscriptions "
"where version > -1 and expires > -1 and hostname='%q' " "where version > -1 and expires > -1 and hostname='%q' "
"and sub_to_user='%q' and sub_to_host='%q' " "and sub_to_user='%q' and sub_to_host='%q' "
"and (event='call-info' or event='line-seize')", mod_sofia_globals.hostname, to_user, to_host); "and (event='call-info' or event='line-seize')", mod_sofia_globals.hostname, to_user, to_host);
} else { } else {
sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event " sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port "
"from sip_subscriptions " "from sip_subscriptions "
"where version > -1 and expires > -1 and hostname='%q' " "where version > -1 and expires > -1 and hostname='%q' "
"and sub_to_user='%q' and sub_to_host='%q' " "and (event='call-info')", mod_sofia_globals.hostname, to_user, to_host); "and sub_to_user='%q' and sub_to_host='%q' " "and (event='call-info')", mod_sofia_globals.hostname, to_user, to_host);
@ -2711,7 +2758,7 @@ void sofia_presence_handle_sip_i_subscribe(int status,
tagi_t tags[]) tagi_t tags[])
{ {
long exp_delta; long exp_delta = 0;
char exp_delta_str[30] = ""; char exp_delta_str[30] = "";
sip_to_t const *to; sip_to_t const *to;
const char *from_user = NULL, *from_host = NULL; const char *from_user = NULL, *from_host = NULL;
@ -2726,6 +2773,7 @@ void sofia_presence_handle_sip_i_subscribe(int status,
const char *call_id = NULL; const char *call_id = NULL;
char *to_str = NULL; char *to_str = NULL;
char *full_from = NULL; char *full_from = NULL;
char *full_to = NULL;
char *full_via = NULL; char *full_via = NULL;
char *full_agent = NULL; char *full_agent = NULL;
char *sstr; char *sstr;
@ -2737,6 +2785,7 @@ void sofia_presence_handle_sip_i_subscribe(int status,
const char *contact_user; const char *contact_user;
sofia_nat_parse_t np = { { 0 } }; sofia_nat_parse_t np = { { 0 } };
int found_proto = 0; int found_proto = 0;
char to_tag[13] = "";
if (!sip) { if (!sip) {
return; return;
@ -2750,6 +2799,8 @@ void sofia_presence_handle_sip_i_subscribe(int status,
return; return;
} }
switch_stun_random_string(to_tag, 12, NULL);
//contact_host = sip->sip_contact->m_url->url_host; //contact_host = sip->sip_contact->m_url->url_host;
contact_user = sip->sip_contact->m_url->url_user; contact_user = sip->sip_contact->m_url->url_user;
@ -2757,19 +2808,6 @@ void sofia_presence_handle_sip_i_subscribe(int status,
event = sip_header_as_string(nh->nh_home, (void *) sip->sip_event); event = sip_header_as_string(nh->nh_home, (void *) sip->sip_event);
/* the following could be refactored back to the calling event handler in sofia.c XXX MTK */
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) {
/* only fire this on <200 to try to avoid resubscribes. probably better ways to do this? */
if (status < 200) {
sofia_sla_handle_sip_i_subscribe(nua, contact_str, profile, nh, sip, de, tags);
}
switch_safe_free(contact_str);
return;
}
}
if (to) { if (to) {
to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host); to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host);
} }
@ -2826,8 +2864,10 @@ void sofia_presence_handle_sip_i_subscribe(int status,
call_id = sip->sip_call_id->i_id; call_id = sip->sip_call_id->i_id;
full_from = sip_header_as_string(nh->nh_home, (void *) sip->sip_from); full_from = sip_header_as_string(nh->nh_home, (void *) sip->sip_from);
full_to = sip_header_as_string(nh->nh_home, (void *) sip->sip_to);
full_via = sip_header_as_string(nh->nh_home, (void *) sip->sip_via); full_via = sip_header_as_string(nh->nh_home, (void *) sip->sip_via);
if (sip->sip_expires && sip->sip_expires->ex_delta > 31536000) { if (sip->sip_expires && sip->sip_expires->ex_delta > 31536000) {
sip->sip_expires->ex_delta = 31536000; sip->sip_expires->ex_delta = 31536000;
} }
@ -2879,6 +2919,7 @@ void sofia_presence_handle_sip_i_subscribe(int status,
} else { } else {
sip_accept_t *ap = sip->sip_accept; sip_accept_t *ap = sip->sip_accept;
char accept[256] = ""; char accept[256] = "";
full_agent = sip_header_as_string(nh->nh_home, (void *) sip->sip_user_agent); full_agent = sip_header_as_string(nh->nh_home, (void *) sip->sip_user_agent);
while (ap) { while (ap) {
switch_snprintf(accept + strlen(accept), sizeof(accept) - strlen(accept), "%s%s ", ap->ac_type, ap->ac_next ? "," : ""); switch_snprintf(accept + strlen(accept), sizeof(accept) - strlen(accept), "%s%s ", ap->ac_type, ap->ac_next ? "," : "");
@ -2887,13 +2928,13 @@ void sofia_presence_handle_sip_i_subscribe(int status,
sql = switch_mprintf("insert into sip_subscriptions " sql = switch_mprintf("insert into sip_subscriptions "
"(proto,sip_user,sip_host,sub_to_user,sub_to_host,presence_hosts,event,contact,call_id,full_from," "(proto,sip_user,sip_host,sub_to_user,sub_to_host,presence_hosts,event,contact,call_id,full_from,"
"full_via,expires,user_agent,accept,profile_name,hostname,network_port,network_ip, orig_proto) " "full_via,expires,user_agent,accept,profile_name,hostname,network_port,network_ip, orig_proto, full_to) "
"values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%d','%q','%q')", "values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%d','%q','%q','%q;tag=%q')",
proto, from_user, from_host, to_user, to_host, profile->presence_hosts ? profile->presence_hosts : to_host, proto, from_user, from_host, to_user, to_host, profile->presence_hosts ? profile->presence_hosts : to_host,
event, contact_str, call_id, full_from, full_via, event, contact_str, call_id, full_from, full_via,
//sofia_test_pflag(profile, PFLAG_MULTIREG) ? switch_epoch_time_now(NULL) + exp_delta : exp_delta * -1,
(long) switch_epoch_time_now(NULL) + exp_delta, (long) switch_epoch_time_now(NULL) + exp_delta,
full_agent, accept, profile->name, mod_sofia_globals.hostname, np.network_port, np.network_ip, orig_proto); full_agent, accept, profile->name, mod_sofia_globals.hostname,
np.network_port, np.network_ip, orig_proto, full_to, to_tag);
switch_assert(sql != NULL); switch_assert(sql != NULL);
@ -2905,15 +2946,16 @@ void sofia_presence_handle_sip_i_subscribe(int status,
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
sstr = switch_mprintf("active;expires=%ld", exp_delta); sstr = switch_mprintf("active;expires=%ld", exp_delta);
} }
switch_mutex_unlock(profile->ireg_mutex); switch_mutex_unlock(profile->ireg_mutex);
} }
if (status < 200) { if (status < 200) {
char *sticky = NULL; char *sticky = NULL;
char *contactstr = profile->url, *cs = NULL; char *contactstr = profile->url, *cs = NULL;
char *p = NULL, *new_contactstr = NULL; char *p = NULL, *new_contactstr = NULL;
if (np.is_nat) { if (np.is_nat) {
char params[128] = ""; char params[128] = "";
@ -2962,8 +3004,11 @@ void sofia_presence_handle_sip_i_subscribe(int status,
new_contactstr = switch_mprintf("<sip:%s%s>", to_user, p); new_contactstr = switch_mprintf("<sip:%s%s>", to_user, p);
} }
} }
sip_to_tag(nh->nh_home, sip->sip_to, to_tag);
nua_respond(nh, SIP_202_ACCEPTED, nua_respond(nh, SIP_202_ACCEPTED,
SIPTAG_TO(sip->sip_to),
TAG_IF(new_contactstr, SIPTAG_CONTACT_STR(new_contactstr)), TAG_IF(new_contactstr, SIPTAG_CONTACT_STR(new_contactstr)),
NUTAG_WITH_THIS_MSG(de->data->e_msg), NUTAG_WITH_THIS_MSG(de->data->e_msg),
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EXPIRES_STR(exp_delta_str), TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END()); SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EXPIRES_STR(exp_delta_str), TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END());
@ -3141,6 +3186,10 @@ void sofia_presence_handle_sip_i_subscribe(int status,
if (full_from) { if (full_from) {
su_free(nh->nh_home, full_from); su_free(nh->nh_home, full_from);
} }
if (full_to) {
su_free(nh->nh_home, full_to);
}
if (full_via) { if (full_via) {
su_free(nh->nh_home, full_via); su_free(nh->nh_home, full_via);
} }
@ -3156,7 +3205,9 @@ void sofia_presence_handle_sip_i_subscribe(int status,
if (!sent_reply) { if (!sent_reply) {
nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END()); nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END());
} }
nua_handle_destroy(nh);
} }
@ -3192,14 +3243,6 @@ void sofia_presence_handle_sip_r_subscribe(int status,
return; return;
} }
/* the following could possibly be refactored back towards the calling event handler in sofia.c XXX MTK */
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
if (!strcasecmp(o->o_type, "dialog") && msg_params_find(o->o_params, "sla")) {
sofia_sla_handle_sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
return;
}
}
if (!sofia_private || !sofia_private->gateway) { if (!sofia_private || !sofia_private->gateway) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
return; return;
@ -3244,32 +3287,13 @@ void sofia_presence_handle_sip_r_subscribe(int status,
} }
} }
struct cpc {
sofia_profile_t *profile;
sofia_dispatch_event_t *de;
};
static int sofia_counterpath_crutch(void *pArg, int argc, char **argv, char **columnNames) static int sofia_presence_send_sql(void *pArg, int argc, char **argv, char **columnNames)
{ {
nua_handle_t *nh; sofia_profile_t *profile = (sofia_profile_t *) pArg;
struct cpc *crutch = (struct cpc *) pArg;
char *call_id = argv[0];
char *pl = argv[1];
char *event_type = argv[2];
long exp_delta = atol(argv[3]);
if ((nh = nua_handle_by_call_id(crutch->profile->nua, call_id))) {
char sstr[128] = "", expstr[128] = "";
switch_snprintf(expstr, sizeof(expstr), "%d", exp_delta);
switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", exp_delta);
nua_notify(nh,
NUTAG_WITH_THIS_MSG(crutch->de->data->e_msg),
SIPTAG_EXPIRES_STR(expstr),
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event_type),
SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END());
nua_handle_unref(nh);
}
send_presence_notify(profile, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], NULL);
return 0; return 0;
} }
@ -3312,15 +3336,6 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n
from = sip->sip_from; from = sip->sip_from;
payload = sip->sip_payload; payload = sip->sip_payload;
/* the following could instead be refactored back to the calling event handler in sofia.c XXX MTK */
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
/* also it probably is unsafe to dereference so many things in a row without testing XXX MTK */
if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) {
sofia_sla_handle_sip_i_publish(nua, profile, nh, sip, de, tags);
return;
}
}
contact_str = sofia_glue_gen_contact_str(profile, sip, de, NULL); contact_str = sofia_glue_gen_contact_str(profile, sip, de, NULL);
if (from) { if (from) {
@ -3407,14 +3422,12 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n
} }
} else if (contact_str) { } else if (contact_str) {
struct cpc crutch; sql = switch_mprintf("select full_to, full_from, contact, expires, call_id, event, network_ip, network_port, "
"'application/pidf+xml' as ct,'%q' as pt "
crutch.profile = profile; " from sip_subscriptions where sub_to_user='%q' and sub_to_host='%q' and event='%q'"
crutch.de = de; "and contact = '%q' ", switch_str_nil(payload->pl_data), from_user, from_host, event_type);
sql = switch_mprintf("select call_id,'%q','%q','%ld' from sip_subscriptions where sub_to_user='%q' and sub_to_host='%q' "
"and contact = '%q' ", payload->pl_data ? payload->pl_data : "", event_type, exp_delta, sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_send_sql, profile);
from_user, from_host, contact_str);
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_counterpath_crutch, &crutch);
switch_safe_free(sql); switch_safe_free(sql);
} }
@ -3636,6 +3649,30 @@ void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip)
switch_mutex_unlock(tech_pvt->profile->flag_mutex); switch_mutex_unlock(tech_pvt->profile->flag_mutex);
} }
void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now)
{
char *sql;
if (now) {
sql = switch_mprintf("select full_to, full_from, contact, expires, call_id, event, network_ip, network_port, "
"NULL as ct, NULL as pt "
" from sip_subscriptions where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%q'",
(long) now, mod_sofia_globals.hostname);
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_send_sql, profile);
switch_safe_free(sql);
sql = switch_mprintf("delete from sip_subscriptions where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%q'",
(long) now, mod_sofia_globals.hostname);
sofia_glue_actually_execute_sql(profile, sql, NULL);
}
}
/* For Emacs: /* For Emacs:
* Local Variables: * Local Variables:
* mode:c * mode:c

View File

@ -763,15 +763,8 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot)
sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_sub_del_callback, profile); sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_sub_del_callback, profile);
if (now) {
switch_snprintfv(sql, sizeof(sql), "delete from sip_subscriptions where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%q'",
(long) now, mod_sofia_globals.hostname);
} else {
switch_snprintfv(sql, sizeof(sql), "delete from sip_subscriptions where expires >= -1 and hostname='%q'", mod_sofia_globals.hostname);
}
sofia_glue_actually_execute_sql(profile, sql, NULL);
sofia_presence_check_subscriptions(profile, now);
if (now) { if (now) {
switch_snprintfv(sql, sizeof(sql), "delete from sip_dialogs where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%q'", switch_snprintfv(sql, sizeof(sql), "delete from sip_dialogs where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%q'",
@ -1500,8 +1493,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
if (delete_subs) { if (delete_subs) {
if (reg_count == 1) { if (reg_count == 1) {
sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'", sql = switch_mprintf("update sip_subscriptions set expires=%ld where sip_user='%q' and sip_host='%q' and contact='%q'",
to_user, sub_host, contact_str); (long) switch_epoch_time_now(NULL), to_user, sub_host, contact_str);
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
} }
} }
@ -1509,16 +1502,19 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
if (multi_reg_contact) { if (multi_reg_contact) {
sql = sql =
switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q' and contact='%q'", to_user, reg_host, contact_str); switch_mprintf("update sip_registrations set expires=%ld where sip_user='%q' and sip_host='%q' and contact='%q'",
(long) switch_epoch_time_now(NULL), to_user, reg_host, contact_str);
} else { } else {
sql = switch_mprintf("delete from sip_registrations where call_id='%q'", call_id); sql = switch_mprintf("update sip_registrations set expires=%ld where call_id='%q'", (long) switch_epoch_time_now(NULL), call_id);
} }
} else { } else {
if (delete_subs) { if (delete_subs) {
sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q'", to_user, sub_host); sql = switch_mprintf("update sip_subscriptions set expires=%ld where sip_user='%q' and sip_host='%q'",
(long) switch_epoch_time_now(NULL), to_user, sub_host);
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
} }
sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", to_user, reg_host); sql = switch_mprintf("update sip_registrations set expires=%ld where sip_user='%q' and sip_host='%q'",
(long) switch_epoch_time_now(NULL), to_user, reg_host);
} }
switch_mutex_lock(profile->ireg_mutex); switch_mutex_lock(profile->ireg_mutex);
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
@ -1664,9 +1660,10 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
if (delete_subs) { if (delete_subs) {
if (multi_reg_contact) { if (multi_reg_contact) {
sql = sql =
switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'", to_user, sub_host, contact_str); switch_mprintf("update sip_subscriptions set expires=%ld where sip_user='%q' and sip_host='%q' and contact='%q'",
(long) switch_epoch_time_now(NULL), to_user, sub_host, contact_str);
} else { } else {
sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", call_id); sql = switch_mprintf("update sip_subscriptions set expires=%ld where call_id='%q'", (long) switch_epoch_time_now(NULL), call_id);
} }
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
@ -1684,7 +1681,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
switch_safe_free(icontact); switch_safe_free(icontact);
} else { } else {
if (delete_subs) { if (delete_subs) {
if ((sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q'", to_user, sub_host))) { if ((sql = switch_mprintf("update sip_subscriptions set expires=%ld where sip_user='%q' and sip_host='%q'",
(long) switch_epoch_time_now(NULL), to_user, sub_host))) {
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
} }
} }
@ -1812,10 +1810,6 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
switch_event_fire(&s_mwi_event); switch_event_fire(&s_mwi_event);
} }
if (contact && *contact_str && sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE_SYLANTRO)) {
sofia_sla_handle_register(nua, profile, sip, de, exptime, contact_str);
}
switch_goto_int(r, 1, end); switch_goto_int(r, 1, end);
} }

View File

@ -1,413 +0,0 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
* Ken Rice, Asteria Solutions Group, Inc <ken@asteriasgi.com>
* Paul D. Tinsley <pdt at jackhammer.org>
* Bret McDanel <trixter AT 0xdecafbad.com>
* Brian West <brian@freeswitch.org>
*
* sofia_sla.c -- SOFIA SIP Endpoint (support for shared line appearance)
* This file (and calls into it) developed by Matthew T Kaufman <matthew@matthew.at>
*
*/
#include "mod_sofia.h"
static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **columnNames);
struct sla_helper {
char call_id[1024];
};
static int get_call_id_callback(void *pArg, int argc, char **argv, char **columnNames)
{
struct sla_helper *sh = (struct sla_helper *) pArg;
switch_set_string(sh->call_id, argv[0]);
return 0;
}
int sofia_sla_supported(sip_t const *sip)
{
if (sip && sip->sip_user_agent && sip->sip_user_agent->g_string) {
const char *ua = sip->sip_user_agent->g_string;
if (switch_stristr("polycom", ua)) {
return 1;
}
if (switch_stristr("snom", ua)) {
return 1;
}
}
return 0;
}
void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip,
sofia_dispatch_event_t *de, long exptime, const char *full_contact)
{
nua_handle_t *nh = NULL;
char exp_str[256] = "";
char my_contact[256] = "";
char *sql;
struct sla_helper sh = { {0} };
char *contact_str = sofia_glue_strip_uri(full_contact);
sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url);
char network_ip[80];
int network_port = 0;
sofia_destination_t *dst;
char *route_uri = NULL;
char port_str[25] = "";
nua_handle_t *fnh = NULL;
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
sql = switch_mprintf("select call_id from sip_shared_appearance_dialogs where hostname='%q' and profile_name='%q' and contact_str='%q'",
mod_sofia_globals.hostname, profile->name, contact_str);
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, get_call_id_callback, &sh);
free(sql);
if (*sh.call_id) {
if ((nh = nua_handle_by_call_id(profile->nua, sh.call_id))) {
fnh = nh;
} else {
if ((sql = switch_mprintf("delete from sip_shared_appearance_dialogs where hostname='%q' and profile_name='%q' and contact_str='%q'",
mod_sofia_globals.hostname, profile->name, contact_str))) {
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
}
}
}
if (!nh) {
nh = nua_handle(nua, NULL, NUTAG_URL(sip->sip_contact->m_url), TAG_NULL());
}
nua_handle_bind(nh, &mod_sofia_globals.keep_private);
switch_snprintf(exp_str, sizeof(exp_str), "%ld", exptime + 30);
switch_snprintf(port_str, sizeof(port_str), ":%ld", sofia_glue_transport_has_tls(transport) ? profile->tls_sip_port : profile->sip_port);
if (sofia_glue_check_nat(profile, network_ip)) {
switch_snprintf(my_contact, sizeof(my_contact), "<sip:%s@%s%s;transport=%s>;expires=%s", profile->sla_contact,
profile->extsipip, port_str, sofia_glue_transport2str(transport), exp_str);
} else {
switch_snprintf(my_contact, sizeof(my_contact), "<sip:%s@%s%s;transport=%s>;expires=%s", profile->sla_contact,
profile->sipip, port_str, sofia_glue_transport2str(transport), exp_str);
}
dst = sofia_glue_get_destination((char *) full_contact);
if (dst->route_uri) {
route_uri = sofia_glue_strip_uri(dst->route_uri);
}
nua_subscribe(nh,
TAG_IF(dst->route_uri, NUTAG_PROXY(route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)),
SIPTAG_TO(sip->sip_to),
SIPTAG_FROM(sip->sip_to),
SIPTAG_CONTACT_STR(my_contact),
SIPTAG_EXPIRES_STR(exp_str),
SIPTAG_EVENT_STR("dialog;sla;include-session-description"), SIPTAG_ACCEPT_STR("application/dialog-info+xml"), TAG_NULL());
if (fnh) {
nua_handle_unref(fnh);
}
sofia_glue_free_destination(dst);
free(contact_str);
}
void sofia_sla_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip,
sofia_dispatch_event_t *de, tagi_t tags[])
{
/* at present there's no SLA versions that we deal with that do publish. to be safe, we say "OK" */
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
}
void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip,
sofia_dispatch_event_t *de, tagi_t tags[])
{
char *aor = NULL;
char *subscriber = NULL;
char *sql = NULL;
char *route_uri = NULL;
char *sla_contact = NULL;
char network_ip[80];
int network_port = 0;
char port_str[25] = "";
sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url);
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
/*
* XXX MTK FIXME - we don't look at the tag to see if NUTAG_SUBSTATE(nua_substate_terminated) or
* a Subscription-State header with state "terminated" and/or expiration of 0. So we never forget
* about them here.
* likewise, we also don't have a hook against nua_r_notify events, so we can't see nua_substate_terminated there.
*/
/*
* extracting AOR is weird...
* the From is the main extension, not the third-party one...
* and the contact has the phone's own network address, not the AOR address
* so we do what openser's pua_bla does and...
*/
/* We always store the AOR as the sipip and not the request so SLA works with NAT inside out */
aor = switch_mprintf("sip:%s@%s", sip->sip_contact->m_url->url_user, profile->sipip);
/*
* ok, and now that we HAVE the AOR, we REALLY should go check in the XML config and see if this particular
* extension is set up to have shared appearances managed. right now it is all-or-nothing on the profile,
* which won't be sufficient for real life. FIXME XXX MTK
*/
/* then the subscriber is the user at their network location... this is arguably the wrong way, but works so far... */
subscriber = switch_mprintf("sip:%s@%s;transport=%s", sip->sip_from->a_url->url_user,
sip->sip_contact->m_url->url_host, sofia_glue_transport2str(transport));
if ((sql =
switch_mprintf("delete from sip_shared_appearance_subscriptions where subscriber='%q' and profile_name='%q' and hostname='%q'",
subscriber, profile->name, mod_sofia_globals.hostname))) {
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
}
if ((sql =
switch_mprintf("insert into sip_shared_appearance_subscriptions (subscriber, call_id, aor, profile_name, hostname, contact_str, network_ip) "
"values ('%q','%q','%q','%q','%q','%q','%q')",
subscriber, sip->sip_call_id->i_id, aor, profile->name, mod_sofia_globals.hostname, contact_str, network_ip))) {
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
}
if (strstr(contact_str, ";fs_nat")) {
char *p;
route_uri = sofia_glue_get_url_from_contact((char *) contact_str, 1);
if ((p = strstr(contact_str, ";fs_"))) {
*p = '\0';
}
}
if (route_uri) {
char *p;
while (route_uri && *route_uri && (*route_uri == '<' || *route_uri == ' ')) {
route_uri++;
}
if ((p = strchr(route_uri, '>'))) {
*p++ = '\0';
}
}
switch_snprintf(port_str, sizeof(port_str), ":%ld", sofia_glue_transport_has_tls(transport) ? profile->tls_sip_port : profile->sip_port);
if (sofia_glue_check_nat(profile, network_ip)) {
sla_contact = switch_mprintf("<sip:%s@%s%s;transport=%s>", profile->sla_contact, profile->extsipip, port_str, sofia_glue_transport2str(transport));
} else {
sla_contact = switch_mprintf("<sip:%s@%s%s;transport=%s>", profile->sla_contact, profile->sipip, port_str, sofia_glue_transport2str(transport));
}
nua_respond(nh, SIP_202_ACCEPTED, SIPTAG_CONTACT_STR(sla_contact), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_IF(route_uri, NUTAG_PROXY(route_uri)), SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* you thought the OTHER time was fake... need delta here FIXME XXX MTK */
SIPTAG_EXPIRES_STR("300"), /* likewise, totally fake - FIXME XXX MTK */
/* sofia_presence says something about needing TAG_IF(sticky, NUTAG_PROXY(sticky)) for NAT stuff? */
TAG_END());
switch_safe_free(aor);
switch_safe_free(subscriber);
switch_safe_free(route_uri);
switch_safe_free(sla_contact);
switch_safe_free(sql);
}
struct sla_notify_helper {
sofia_profile_t *profile;
char *payload;
};
void sofia_sla_handle_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,
sofia_dispatch_event_t *de,
tagi_t tags[])
{
if (status >= 300) {
nua_handle_destroy(nh);
sofia_private_free(sofia_private);
} else {
char *full_contact = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_contact);
time_t expires = switch_epoch_time_now(NULL);
char *sql;
char *contact_str = sofia_glue_strip_uri(full_contact);
if (sip && sip->sip_expires) {
expires += sip->sip_expires->ex_delta + 30;
}
if ((sql = switch_mprintf("insert into sip_shared_appearance_dialogs (profile_name, hostname, contact_str, call_id, expires) "
"values ('%q','%q','%q','%q','%ld')",
profile->name, mod_sofia_globals.hostname, contact_str, sip->sip_call_id->i_id, (long) expires))) {
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
}
free(contact_str);
}
}
void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip,
sofia_dispatch_event_t *de, tagi_t tags[])
{
char *sql = NULL;
struct sla_notify_helper helper;
char *aor = NULL;
char *contact = NULL;
sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url);
/*
* things we know we don't do:
* draft-anil-sipping-bla says we should look and see if the specific appearance is in use and if it is
* return an error for the i_notify, to handle the initial line-seize for dialing out case.
* to do that we would need to really track all the appearances *and* override sofia's autoresponder for i_notify
* because at this point, it already sent the 200 for us.
* and we simply don't track all the appearance status by decoding the XML payload out and recording that in
* an SQL line appearance database yet. we'll need to do that in order to do the above, and in order to make
* interoperation possible between devices that disagree on the dialog xml payload OR don't even do it that
* way and instead use things like call-info/line-seize events like the old Broadsoft spec.
* instead we cheat and just reflect the entire payload back to the subscribers (who, because we don't
* yet check each AOR as it comes in to see if it is to be managed, is more subscribers than we probably
* should have). for the current prototype stage, this works ok anyway.
* and because we don't parse the XML, we even reflect it right back to the notifier/sender (which is called
* "target" in the payload XML, of course).
* also because we don't track on a per-appearance basis, there IS NOT a hook back from sofia_glue to add
* an appearance index to the outbound invite for the "next free appearance". this can lead to race
* conditions where a call shows up on slightly different line key numbers at different phones, making
* "pick up on line X" meaningless if such a race occurs. again, it is a prototype. we can fix it later.
*/
/* the dispatcher calls us just because it is aimed at us, so check to see if it is dialog;sla at the very least... */
if ((!sip->sip_event)
|| (strcasecmp(sip->sip_event->o_type, "dialog"))
|| !msg_params_find(sip->sip_event->o_params, "sla")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "sent to sla-agent but not dialog;sla\n");
return;
}
/* calculate the AOR we're trying to tell people about. should probably double-check before derferencing XXX MTK */
/* We always store the AOR as the sipip and not the request so SLA works with NAT inside out */
aor = switch_mprintf("sip:%s@%s", sip->sip_to->a_url->url_user, profile->sipip);
/* this isn't sufficient because on things like the polycom, the subscriber is the 'main' ext number, but the
* 'main' ext number isn't in ANY of the headers they send us in the notify. of course.
* as a side effect, the subscriber<>'%q' below isn't sufficient to prevent reflecting the event back
* at a phone that has the ext # != third-party#. see above, can only fix by parsing the XML for the 'target'
* so we don't reflect it back at anyone who is the "boss" config, but we do reflect it back at the "secretary"
* config. if that breaks the phone, just set them all up as the "boss" config where ext#==third-party#
*/
contact = switch_mprintf("sip:%s@%s;transport=%s", sip->sip_contact->m_url->url_user,
sip->sip_contact->m_url->url_host, sofia_glue_transport2str(transport));
if (sip->sip_payload && sip->sip_payload->pl_data) {
sql = switch_mprintf("select subscriber,call_id,aor,profile_name,hostname,contact_str,network_ip from sip_shared_appearance_subscriptions where "
"aor='%q' and profile_name='%q' and hostname='%q'", aor, profile->name, mod_sofia_globals.hostname);
helper.profile = profile;
helper.payload = sip->sip_payload->pl_data; /* could just send the WHOLE payload. you'd get the type that way. */
/* which mutex if any is correct to hold in this callback? XXX MTK FIXME */
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_sla_sub_callback, &helper);
switch_safe_free(sql);
switch_safe_free(aor);
switch_safe_free(contact);
}
}
static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **columnNames)
{
struct sla_notify_helper *helper = pArg;
/* char *subscriber = argv[0]; */
char *call_id = argv[1];
/* char *aor = argv[2]; */
/* char *profile_name = argv[3]; */
/* char *hostname = argv[4]; */
char *contact_str = argv[5];
char *network_ip = argv[6];
nua_handle_t *nh;
char *route_uri = NULL;
char *xml_fixup = NULL;
char *fixup = NULL;
nh = nua_handle_by_call_id(helper->profile->nua, call_id); /* that's all you need to find the subscription's nh */
if (nh) {
if (strstr(contact_str, ";fs_nat")) {
char *p;
route_uri = sofia_glue_get_url_from_contact(contact_str, 1);
if ((p = strstr(contact_str, ";fs_"))) {
*p = '\0';
}
}
if (route_uri) {
char *p;
while (route_uri && *route_uri && (*route_uri == '<' || *route_uri == ' ')) {
route_uri++;
}
if ((p = strchr(route_uri, '>'))) {
*p++ = '\0';
}
}
if (helper->profile->extsipip) {
if (sofia_glue_check_nat(helper->profile, network_ip)) {
fixup = switch_string_replace(helper->payload, helper->profile->sipip, helper->profile->extsipip);
} else {
fixup = switch_string_replace(helper->payload, helper->profile->extsipip, helper->profile->sipip);
}
xml_fixup = fixup;
} else {
xml_fixup = helper->payload;
}
nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* XXX MTK FIXME - this is totally fake calculation */
TAG_IF(route_uri, NUTAG_PROXY(route_uri)), SIPTAG_CONTENT_TYPE_STR("application/dialog-info+xml"), /* could've just kept the type from the payload */
SIPTAG_PAYLOAD_STR(xml_fixup), TAG_END());
switch_safe_free(route_uri);
if (fixup && fixup != helper->payload) {
free(fixup);
}
nua_handle_unref(nh);
}
return 0;
}