提交 97a68c50 authored 作者: Anthony Minessale's avatar Anthony Minessale

support allowing pidf-ful presence clients to share the same account and 'appear…

support allowing pidf-ful presence clients to share the same account and 'appear offline' without influencing each other =/ also refactor the contact generation string based on nat into a helper function
上级 c4e350ab
...@@ -745,6 +745,14 @@ typedef struct { ...@@ -745,6 +745,14 @@ typedef struct {
char *route_uri; char *route_uri;
} sofia_destination_t; } sofia_destination_t;
typedef struct {
char network_ip[80];
int network_port;
const char *is_nat;
int is_auto_nat;
} sofia_nat_parse_t;
#define sofia_test_pflag(obj, flag) ((obj)->pflags[flag] ? 1 : 0) #define sofia_test_pflag(obj, flag) ((obj)->pflags[flag] ? 1 : 0)
#define sofia_set_pflag(obj, flag) (obj)->pflags[flag] = 1 #define sofia_set_pflag(obj, flag) (obj)->pflags[flag] = 1
#define sofia_set_pflag_locked(obj, flag) assert(obj->flag_mutex != NULL);\ #define sofia_set_pflag_locked(obj, flag) assert(obj->flag_mutex != NULL);\
...@@ -1040,3 +1048,4 @@ switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, swi ...@@ -1040,3 +1048,4 @@ switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, swi
void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl); void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl);
void sofia_glue_check_dtmf_type(private_object_t *tech_pvt); void sofia_glue_check_dtmf_type(private_object_t *tech_pvt);
void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str); void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str);
char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, sofia_nat_parse_t *np);
...@@ -6136,6 +6136,129 @@ void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str) ...@@ -6136,6 +6136,129 @@ void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str)
} }
} }
char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, sofia_nat_parse_t *np)
{
char *contact_str = NULL;
const char *contact_host, *contact_user;
sip_contact_t const *contact;
char *port;
const char *display = "\"user\"";
char new_port[25] = "";
sofia_nat_parse_t lnp = { { 0 } };
const char *ipv6;
sip_from_t const *from;
if (!sip || !sip->sip_contact || !sip->sip_contact->m_url) {
return NULL;
}
from = sip->sip_from;
contact = sip->sip_contact;
if (!np) {
np = &lnp;
}
sofia_glue_get_addr(nua_current_request(profile->nua), np->network_ip, sizeof(np->network_ip), &np->network_port);
if (sofia_glue_check_nat(profile, np->network_ip)) {
np->is_auto_nat = 1;
}
port = (char *) contact->m_url->url_port;
contact_host = sip->sip_contact->m_url->url_host;
contact_user = sip->sip_contact->m_url->url_user;
display = contact->m_display;
if (zstr(display)) {
if (from) {
display = from->a_display;
if (zstr(display)) {
display = "\"user\"";
}
}
} else {
display = "\"user\"";
}
if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) {
if (sip->sip_via) {
const char *v_port = sip->sip_via->v_port;
const char *v_host = sip->sip_via->v_host;
if (v_host && sip->sip_via->v_received) {
np->is_nat = "via received";
} else if (v_host && strcmp(np->network_ip, v_host)) {
np->is_nat = "via host";
} else if (v_port && atoi(v_port) != np->network_port) {
np->is_nat = "via port";
}
}
}
if (!np->is_nat && sip && sip->sip_via && sip->sip_via->v_port &&
atoi(sip->sip_via->v_port) == 5060 && np->network_port != 5060 ) {
np->is_nat = "via port";
}
if (!np->is_nat && profile->nat_acl_count) {
uint32_t x = 0;
int ok = 1;
char *last_acl = NULL;
if (!zstr(contact_host)) {
for (x = 0; x < profile->nat_acl_count; x++) {
last_acl = profile->nat_acl[x];
if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
break;
}
}
if (ok) {
np->is_nat = last_acl;
}
}
}
if (np->is_nat && profile->local_network && switch_check_network_list_ip(np->network_ip, profile->local_network)) {
if (profile->debug) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s is on local network, not seting NAT mode.\n", np->network_ip);
}
np->is_nat = NULL;
}
if (zstr(contact_host)) {
np->is_nat = "No contact host";
}
if (np->is_nat) {
contact_host = np->network_ip;
switch_snprintf(new_port, sizeof(new_port), ":%d", np->network_port);
port = NULL;
}
if (port) {
switch_snprintf(new_port, sizeof(new_port), ":%s", port);
}
ipv6 = strchr(contact_host, ':');
if (contact->m_url->url_params) {
contact_str = switch_mprintf("%s <sip:%s@%s%s%s%s;%s>%s",
display, contact->m_url->url_user,
ipv6 ? "[" : "",
contact_host, ipv6 ? "]" : "", new_port, contact->m_url->url_params, np->is_nat ? ";fs_nat=yes" : "");
} else {
contact_str = switch_mprintf("%s <sip:%s@%s%s%s%s>%s",
display,
contact->m_url->url_user, ipv6 ? "[" : "", contact_host, ipv6 ? "]" : "", new_port, np->is_nat ? ";fs_nat=yes" : "");
}
return contact_str;
}
......
...@@ -289,7 +289,8 @@ void sofia_presence_cancel(void) ...@@ -289,7 +289,8 @@ void sofia_presence_cancel(void)
if ((sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from," if ((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"
",-1,'unavailable','unavailable' from sip_subscriptions where expires > -1 and event='presence' and hostname='%q'", ",-1,'unavailable','unavailable' from sip_subscriptions where version > -1 and "
"expires > -1 and event='presence' and hostname='%q'",
mod_sofia_globals.hostname))) { mod_sofia_globals.hostname))) {
switch_mutex_lock(mod_sofia_globals.hash_mutex); switch_mutex_lock(mod_sofia_globals.hash_mutex);
for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) { for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
...@@ -322,7 +323,7 @@ void sofia_presence_establish_presence(sofia_profile_t *profile) ...@@ -322,7 +323,7 @@ void sofia_presence_establish_presence(sofia_profile_t *profile)
if (sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, if (sofia_glue_execute_sql_callback(profile, profile->ireg_mutex,
"select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions " "select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions "
"where expires > -1 and proto='ext' or proto='user' or proto='conf'", "where expires > -1 and version > -1 and proto='ext' or proto='user' or proto='conf'",
sofia_presence_resub_callback, &h) != SWITCH_TRUE) { sofia_presence_resub_callback, &h) != SWITCH_TRUE) {
return; return;
} }
...@@ -435,12 +436,12 @@ static void actual_sofia_presence_mwi_event_handler(switch_event_t *event) ...@@ -435,12 +436,12 @@ 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 expires > -1 and event='message-summary' " ",'%q','%q' 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, host, 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 expires > -1 and event='message-summary' " ",'%q','%q' 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, host, user, host, host, sub_call_id);
} }
...@@ -545,7 +546,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) ...@@ -545,7 +546,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
"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) "
"where sip_subscriptions.expires > -1 and sip_subscriptions.event='presence' and sip_subscriptions.full_from like '%%%q%%'", "where sip_subscriptions.version > -1 and "
"sip_subscriptions.expires > -1 and sip_subscriptions.event='presence' and sip_subscriptions.full_from like '%%%q%%'",
switch_str_nil(status), switch_str_nil(rpid), from); switch_str_nil(status), switch_str_nil(rpid), from);
} else { } else {
sql = switch_mprintf("select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host," sql = switch_mprintf("select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,"
...@@ -557,7 +559,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) ...@@ -557,7 +559,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
"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) "
"where sip_subscriptions.expires > -1 and sip_subscriptions.event='presence'", switch_str_nil(status), "where sip_subscriptions.version > -1 and "
"sip_subscriptions.expires > -1 and sip_subscriptions.event='presence'", switch_str_nil(status),
switch_str_nil(rpid)); switch_str_nil(rpid));
} }
...@@ -833,7 +836,7 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) ...@@ -833,7 +836,7 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
"(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) "
"where sip_subscriptions.expires > -1 and " "where sip_subscriptions.version > -1 and sip_subscriptions.expires > -1 and "
"(event='%q' or event='%q') and sub_to_user='%q' " "(event='%q' or event='%q') and sub_to_user='%q' "
"and (sub_to_host='%q' or presence_hosts like '%%%q%%') " "and (sub_to_host='%q' or presence_hosts like '%%%q%%') "
"and (sip_subscriptions.profile_name = '%q' or sip_subscriptions.presence_hosts != sip_subscriptions.sub_to_host) ", "and (sip_subscriptions.profile_name = '%q' or sip_subscriptions.presence_hosts != sip_subscriptions.sub_to_host) ",
...@@ -2009,13 +2012,13 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char * ...@@ -2009,13 +2012,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 "
"from sip_subscriptions " "from sip_subscriptions "
"where 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 "
"from sip_subscriptions " "from sip_subscriptions "
"where 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);
} }
...@@ -2044,350 +2047,287 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char * ...@@ -2044,350 +2047,287 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char *
} }
void sofia_presence_handle_sip_i_subscribe(int status, void sofia_presence_handle_sip_i_subscribe(int status,
char const *phrase, char const *phrase,
nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
tagi_t tags[]) tagi_t tags[])
{ {
if (sip) {
long exp_abs, exp_delta;
char exp_delta_str[30] = "";
sip_to_t const *to = sip->sip_to;
sip_from_t const *from = sip->sip_from;
sip_contact_t const *contact = sip->sip_contact;
const char *from_user = NULL, *from_host = NULL;
const char *to_user = NULL, *to_host = NULL;
char *my_to_user = NULL;
char *sql, *event = NULL;
char *proto = "sip";
char *d_user = NULL;
char *contact_str = "";
const char *call_id = NULL;
char *to_str = NULL;
char *full_from = NULL;
char *full_via = NULL;
char *full_agent = NULL;
char *sstr;
const char *display = "\"user\"";
switch_event_t *sevent;
int sub_state;
int sent_reply = 0;
int network_port = 0;
char network_ip[80];
const char *contact_host, *contact_user;
char *port;
char new_port[25] = "";
char *is_nat = NULL;
int is_auto_nat = 0;
const char *ipv6;
if (!(contact && sip->sip_contact->m_url)) {
nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END());
return;
}
sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); long exp_abs, exp_delta;
char exp_delta_str[30] = "";
sip_to_t const *to;
const char *from_user = NULL, *from_host = NULL;
const char *to_user = NULL, *to_host = NULL;
char *my_to_user = NULL;
char *sql, *event = NULL;
char *proto = "sip";
char *d_user = NULL;
char *contact_str = "";
const char *call_id = NULL;
char *to_str = NULL;
char *full_from = NULL;
char *full_via = NULL;
char *full_agent = NULL;
char *sstr;
switch_event_t *sevent;
int sub_state;
int sent_reply = 0;
sip_contact_t const *contact;
const char *ipv6;
const char *contact_host, *contact_user;
sofia_nat_parse_t np = { { 0 } };
if (sofia_glue_check_nat(profile, network_ip)) { if (!sip) {
is_auto_nat = 1; return;
} }
tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END()); to = sip->sip_to;
contact = sip->sip_contact;
event = sip_header_as_string(profile->home, (void *) sip->sip_event); if (!(contact_str = sofia_glue_gen_contact_str(profile, sip, &np))) {
nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END());
return;
}
port = (char *) contact->m_url->url_port; 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;
display = contact->m_display; tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END());
if (zstr(display)) { event = sip_header_as_string(profile->home, (void *) sip->sip_event);
if (from) {
display = from->a_display;
if (zstr(display)) {
display = "\"user\"";
}
}
} else {
display = "\"user\"";
}
if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) {
if (sip && sip->sip_via) {
const char *v_port = sip->sip_via->v_port;
const char *v_host = sip->sip_via->v_host;
if (v_host && sip->sip_via->v_received) { /* the following could be refactored back to the calling event handler in sofia.c XXX MTK */
is_nat = "via received"; if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
} else if (v_host && strcmp(network_ip, v_host)) { if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) {
is_nat = "via host"; /* only fire this on <200 to try to avoid resubscribes. probably better ways to do this? */
} else if (v_port && atoi(v_port) != network_port) { if (status < 200) {
is_nat = "via port"; sofia_sla_handle_sip_i_subscribe(nua, contact_str, profile, nh, sip, tags);
}
} }
switch_safe_free(contact_str);
return;
} }
}
if (!is_nat && sip && sip->sip_via && sip->sip_via->v_port && if (to) {
atoi(sip->sip_via->v_port) == 5060 && network_port != 5060 ) { to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host);
is_nat = "via port"; }
}
if (!is_nat && profile->nat_acl_count) { if (to) {
uint32_t x = 0; to_user = to->a_url->url_user;
int ok = 1; to_host = to->a_url->url_host;
char *last_acl = NULL; }
if (!zstr(contact_host)) { if (profile->sub_domain) {
for (x = 0; x < profile->nat_acl_count; x++) { to_host = profile->sub_domain;
last_acl = profile->nat_acl[x]; }
if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
break;
}
}
if (ok) { if (sip->sip_from) {
is_nat = last_acl; from_user = sip->sip_from->a_url->url_user;
} from_host = sip->sip_from->a_url->url_host;
} } else {
} from_user = "n/a";
from_host = "n/a";
}
if (is_nat && profile->local_network && switch_check_network_list_ip(network_ip, profile->local_network)) { if ((exp_delta = sip->sip_expires ? sip->sip_expires->ex_delta : 3600)) {
if (profile->debug) { if (profile->force_subscription_expires) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s is on local network, not seting NAT mode.\n", network_ip); exp_delta = profile->force_subscription_expires;
}
is_nat = NULL;
} }
}
if (zstr(contact_host)) { if (exp_delta) {
is_nat = "No contact host"; exp_abs = (long) switch_epoch_time_now(NULL) + exp_delta;
} } else {
exp_abs = 0;
sub_state = nua_substate_terminated;
}
if (is_nat) { switch_snprintf(exp_delta_str, sizeof(exp_delta_str), "%ld", exp_delta);
contact_host = network_ip;
switch_snprintf(new_port, sizeof(new_port), ":%d", network_port);
port = NULL;
}
if (zstr(contact_host)) { if (to_user && strchr(to_user, '+')) {
nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END()); char *h;
return; if ((proto = (d_user = strdup(to_user)))) {
if ((my_to_user = strchr(d_user, '+'))) {
*my_to_user++ = '\0';
to_user = my_to_user;
if ((h = strchr(to_user, '+')) || (h = strchr(to_user, '@'))) {
*h++ = '\0';
to_host = h;
}
}
} }
if (port) { if (!(proto && to_user && to_host)) {
switch_snprintf(new_port, sizeof(new_port), ":%s", port); nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END());
goto end;
} }
}
ipv6 = strchr(contact_host, ':'); call_id = sip->sip_call_id->i_id;
if (contact->m_url->url_params) { full_from = sip_header_as_string(profile->home, (void *) sip->sip_from);
contact_str = switch_mprintf("%s <sip:%s@%s%s%s%s;%s>%s", full_via = sip_header_as_string(profile->home, (void *) sip->sip_via);
display, contact->m_url->url_user,
ipv6 ? "[" : "",
contact_host, ipv6 ? "]" : "", new_port, contact->m_url->url_params, is_nat ? ";fs_nat=yes" : "");
} else {
contact_str = switch_mprintf("%s <sip:%s@%s%s%s%s>%s",
display,
contact->m_url->url_user, ipv6 ? "[" : "", contact_host, ipv6 ? "]" : "", new_port, is_nat ? ";fs_nat=yes" : "");
}
if (sip->sip_expires && sip->sip_expires->ex_delta > 31536000) {
sip->sip_expires->ex_delta = 31536000;
}
if (sofia_test_pflag(profile, PFLAG_MULTIREG)) {
sql = switch_mprintf("delete from sip_subscriptions where call_id='%q' "
"or (proto='%q' and sip_user='%q' and sip_host='%q' "
"and sub_to_user='%q' and sub_to_host='%q' and event='%q' and hostname='%q' "
"and contact='%q')",
call_id, proto, from_user, from_host, to_user, to_host, event, mod_sofia_globals.hostname, contact_str);
/* the following could be refactored back to the calling event handler in sofia.c XXX MTK */ } else {
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { sql = switch_mprintf("delete from sip_subscriptions where "
if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) { "proto='%q' and sip_user='%q' and sip_host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q' and hostname='%q'",
/* only fire this on <200 to try to avoid resubscribes. probably better ways to do this? */ proto, from_user, from_host, to_user, to_host, event, mod_sofia_globals.hostname);
if (status < 200) { }
sofia_sla_handle_sip_i_subscribe(nua, contact_str, profile, nh, sip, tags);
}
switch_safe_free(contact_str);
return;
}
}
switch_mutex_lock(profile->ireg_mutex);
switch_assert(sql != NULL);
sofia_glue_actually_execute_sql(profile, sql, NULL);
switch_safe_free(sql);
if (sub_state == nua_substate_terminated) {
sstr = switch_mprintf("terminated");
} else {
sip_accept_t *ap = sip->sip_accept;
char accept[256] = "";
full_agent = sip_header_as_string(profile->home, (void *) sip->sip_user_agent);
while (ap) {
switch_snprintf(accept + strlen(accept), sizeof(accept) - strlen(accept), "%s%s ", ap->ac_type, ap->ac_next ? "," : "");
ap = ap->ac_next;
}
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,"
"full_via,expires,user_agent,accept,profile_name,hostname,network_port,network_ip) "
"values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%d','%q')",
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,
//sofia_test_pflag(profile, PFLAG_MULTIREG) ? switch_epoch_time_now(NULL) + exp_delta : exp_delta * -1,
(long) switch_epoch_time_now(NULL) + (exp_delta * 2),
full_agent, accept, profile->name, mod_sofia_globals.hostname, np.network_port, np.network_ip);
if (to) { switch_assert(sql != NULL);
to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host);
}
if (to) { if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) {
to_user = to->a_url->url_user; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s SUBSCRIBE %s@%s %s@%s\n%s\n",
to_host = to->a_url->url_host; profile->name, from_user, from_host, to_user, to_host, sql);
} }
if (profile->sub_domain) {
to_host = profile->sub_domain;
}
if (sip && sip->sip_from) { sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
from_user = sip->sip_from->a_url->url_user; sstr = switch_mprintf("active;expires=%ld", exp_delta);
from_host = sip->sip_from->a_url->url_host; }
} else {
from_user = "n/a"; switch_mutex_unlock(profile->ireg_mutex);
from_host = "n/a";
} if (status < 200) {
char *sticky = NULL;
char *contactstr = profile->url, *cs = NULL;
char *p = NULL, *new_contactstr = NULL;
if ((exp_delta = sip->sip_expires ? sip->sip_expires->ex_delta : 3600)) { if (np.is_nat) {
if (profile->force_subscription_expires) { char params[128] = "";
exp_delta = profile->force_subscription_expires; if (contact->m_url->url_params) {
switch_snprintf(params, sizeof(params), ";%s", contact->m_url->url_params);
} }
ipv6 = strchr(np.network_ip, ':');
sticky = switch_mprintf("sip:%s@%s%s%s:%d%s", contact_user, ipv6 ? "[" : "", np.network_ip, ipv6 ? "]" : "", np.network_port, params);
} }
if (exp_delta) { if (np.is_auto_nat) {
exp_abs = (long) switch_epoch_time_now(NULL) + exp_delta; contactstr = profile->public_url;
} else { } else {
exp_abs = 0; contactstr = profile->url;
sub_state = nua_substate_terminated;
} }
switch_snprintf(exp_delta_str, sizeof(exp_delta_str), "%ld", exp_delta);
if (to_user && strchr(to_user, '+')) { if (switch_stristr("port=tcp", contact->m_url->url_params)) {
char *h; if (np.is_auto_nat) {
if ((proto = (d_user = strdup(to_user)))) { cs = profile->tcp_public_contact;
if ((my_to_user = strchr(d_user, '+'))) { } else {
*my_to_user++ = '\0'; cs = profile->tcp_contact;
to_user = my_to_user;
if ((h = strchr(to_user, '+')) || (h = strchr(to_user, '@'))) {
*h++ = '\0';
to_host = h;
}
}
} }
} else if (switch_stristr("port=tls", contact->m_url->url_params)) {
if (!(proto && to_user && to_host)) { if (np.is_auto_nat) {
nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END()); cs = profile->tls_public_contact;
goto end; } else {
cs = profile->tls_contact;
} }
} }
call_id = sip->sip_call_id->i_id; if (cs) {
full_from = sip_header_as_string(profile->home, (void *) sip->sip_from); contactstr = cs;
full_via = sip_header_as_string(profile->home, (void *) sip->sip_via);
if (sip && sip->sip_expires && sip->sip_expires->ex_delta > 31536000) {
sip->sip_expires->ex_delta = 31536000;
} }
if (sofia_test_pflag(profile, PFLAG_MULTIREG)) {
sql = switch_mprintf("delete from sip_subscriptions where call_id='%q' " if (nh && nh->nh_ds && nh->nh_ds->ds_usage) {
"or (proto='%q' and sip_user='%q' and sip_host='%q' " /* nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta + SUB_OVERLAP, exp_delta + SUB_OVERLAP); */
"and sub_to_user='%q' and sub_to_host='%q' and event='%q' and hostname='%q' " nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta * 2, exp_delta * 2);
"and contact='%q')",
call_id, proto, from_user, from_host, to_user, to_host, event, mod_sofia_globals.hostname, contact_str);
} else {
sql = switch_mprintf("delete from sip_subscriptions where "
"proto='%q' and sip_user='%q' and sip_host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q' and hostname='%q'",
proto, from_user, from_host, to_user, to_host, event, mod_sofia_globals.hostname);
} }
switch_mutex_lock(profile->ireg_mutex); if (contactstr && (p = strchr(contactstr, '@'))) {
switch_assert(sql != NULL); if (strrchr(p, '>')) {
sofia_glue_actually_execute_sql(profile, sql, NULL); new_contactstr = switch_mprintf("<sip:%s%s", to_user, p);
switch_safe_free(sql); } else {
new_contactstr = switch_mprintf("<sip:%s%s>", to_user, p);
if (sub_state == nua_substate_terminated) {
sstr = switch_mprintf("terminated");
} else {
sip_accept_t *ap = sip->sip_accept;
char accept[256] = "";
full_agent = sip_header_as_string(profile->home, (void *) sip->sip_user_agent);
while (ap) {
switch_snprintf(accept + strlen(accept), sizeof(accept) - strlen(accept), "%s%s ", ap->ac_type, ap->ac_next ? "," : "");
ap = ap->ac_next;
}
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,"
"full_via,expires,user_agent,accept,profile_name,hostname,network_port,network_ip) "
"values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%d','%q')",
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,
//sofia_test_pflag(profile, PFLAG_MULTIREG) ? switch_epoch_time_now(NULL) + exp_delta : exp_delta * -1,
(long) switch_epoch_time_now(NULL) + (exp_delta * 2),
full_agent, accept, profile->name, mod_sofia_globals.hostname, network_port, network_ip);
switch_assert(sql != NULL);
if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s SUBSCRIBE %s@%s %s@%s\n%s\n",
profile->name, from_user, from_host, to_user, to_host, sql);
} }
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
sstr = switch_mprintf("active;expires=%ld", exp_delta);
} }
switch_mutex_unlock(profile->ireg_mutex); nua_respond(nh, SIP_202_ACCEPTED,
TAG_IF(new_contactstr, SIPTAG_CONTACT_STR(new_contactstr)),
NUTAG_WITH_THIS(nua),
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EXPIRES_STR(exp_delta_str), TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END());
if (status < 200) { switch_safe_free(new_contactstr);
char *sticky = NULL; switch_safe_free(sticky);
char *contactstr = profile->url, *cs = NULL; }
char *p = NULL, *new_contactstr = NULL;
if (is_nat) { if (sub_state == nua_substate_terminated) {
char params[128] = ""; char *full_call_info = NULL;
if (contact->m_url->url_params) { char *p = NULL;
switch_snprintf(params, sizeof(params), ";%s", contact->m_url->url_params);
}
ipv6 = strchr(network_ip, ':');
sticky = switch_mprintf("sip:%s@%s%s%s:%d%s", contact_user, ipv6 ? "[" : "", network_ip, ipv6 ? "]" : "", network_port, params);
}
if (is_auto_nat) { if (sip->sip_call_info) {
contactstr = profile->public_url; full_call_info = sip_header_as_string(profile->home, (void *) sip->sip_call_info);
} else { if ((p = strchr(full_call_info, ';'))) {
contactstr = profile->url; p++;
} }
nua_notify(nh,
SIPTAG_EXPIRES_STR("0"),
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), TAG_IF(full_call_info, SIPTAG_CALL_INFO_STR(full_call_info)), TAG_END());
if (switch_stristr("port=tcp", contact->m_url->url_params)) {
if (is_auto_nat) { if (!strcasecmp(event, "line-seize")) {
cs = profile->tcp_public_contact; if (mod_sofia_globals.debug_sla > 1) {
} else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CANCEL LINE SEIZE\n");
cs = profile->tcp_contact;
}
} else if (switch_stristr("port=tls", contact->m_url->url_params)) {
if (is_auto_nat) {
cs = profile->tls_public_contact;
} else {
cs = profile->tls_contact;
} }
}
if (cs) { sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
contactstr = cs; "and call_info_state='seized'",
} to_user, to_host, to_user, to_host);
if (nh && nh->nh_ds && nh->nh_ds->ds_usage) {
/* nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta + SUB_OVERLAP, exp_delta + SUB_OVERLAP); */
nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta * 2, exp_delta * 2);
}
if (contactstr && (p = strchr(contactstr, '@'))) { if (mod_sofia_globals.debug_sla > 1) {
if (strrchr(p, '>')) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql);
new_contactstr = switch_mprintf("<sip:%s%s", to_user, p);
} else {
new_contactstr = switch_mprintf("<sip:%s%s>", to_user, p);
} }
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE);
} }
nua_respond(nh, SIP_202_ACCEPTED, su_free(profile->home, full_call_info);
TAG_IF(new_contactstr, SIPTAG_CONTACT_STR(new_contactstr)),
NUTAG_WITH_THIS(nua),
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EXPIRES_STR(exp_delta_str), TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END());
switch_safe_free(new_contactstr);
switch_safe_free(sticky);
} }
if (sub_state == nua_substate_terminated) { } else {
if (!strcasecmp(event, "line-seize")) {
char *full_call_info = NULL; char *full_call_info = NULL;
char *p = NULL; char *p;
if (sip->sip_call_info) { if (sip->sip_call_info) {
full_call_info = sip_header_as_string(profile->home, (void *) sip->sip_call_info); full_call_info = sip_header_as_string(profile->home, (void *) sip->sip_call_info);
...@@ -2396,153 +2336,117 @@ void sofia_presence_handle_sip_i_subscribe(int status, ...@@ -2396,153 +2336,117 @@ void sofia_presence_handle_sip_i_subscribe(int status,
} }
nua_notify(nh, nua_notify(nh,
SIPTAG_EXPIRES_STR("0"), SIPTAG_EXPIRES_STR(exp_delta_str),
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), TAG_IF(full_call_info, SIPTAG_CALL_INFO_STR(full_call_info)), TAG_END()); SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
SIPTAG_EVENT_STR("line-seize"), TAG_IF(full_call_info, SIPTAG_CALL_INFO_STR(full_call_info)), TAG_END());
if (!strcasecmp(event, "line-seize")) {
if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CANCEL LINE SEIZE\n");
}
sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') " sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
"and call_info_state='seized'", "and call_info_state='seized'",
to_user, to_host, to_user, to_host); to_user, to_host, to_user, to_host);
if (mod_sofia_globals.debug_sla > 1) { if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql);
}
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE);
} }
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
su_free(profile->home, full_call_info); sql = switch_mprintf("insert into sip_dialogs (sip_from_user,sip_from_host,call_info,call_info_state,hostname,expires) "
"values ('%q','%q','%q','seized','%q',%ld)",
} to_user, to_host, switch_str_nil(p), mod_sofia_globals.hostname, switch_epoch_time_now(NULL) + exp_delta);
} else {
if (!strcasecmp(event, "line-seize")) {
char *full_call_info = NULL;
char *p;
if (sip->sip_call_info) {
full_call_info = sip_header_as_string(profile->home, (void *) sip->sip_call_info);
if ((p = strchr(full_call_info, ';'))) {
p++;
}
nua_notify(nh,
SIPTAG_EXPIRES_STR(exp_delta_str),
SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
SIPTAG_EVENT_STR("line-seize"), TAG_IF(full_call_info, SIPTAG_CALL_INFO_STR(full_call_info)), TAG_END());
sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
"and call_info_state='seized'",
to_user, to_host, to_user, to_host);
if (mod_sofia_globals.debug_sla > 1) { if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SEIZE SQL %s\n", sql);
}
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
sql = switch_mprintf("insert into sip_dialogs (sip_from_user,sip_from_host,call_info,call_info_state,hostname,expires) "
"values ('%q','%q','%q','seized','%q',%ld)",
to_user, to_host, switch_str_nil(p), mod_sofia_globals.hostname, switch_epoch_time_now(NULL) + exp_delta);
if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SEIZE SQL %s\n", sql);
}
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE);
su_free(profile->home, full_call_info);
} }
} else if (!strcasecmp(event, "call-info")) { sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE); sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE);
su_free(profile->home, full_call_info);
} }
} else if (!strcasecmp(event, "call-info")) {
sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE);
} }
}
sent_reply++; sent_reply++;
switch_safe_free(sstr); switch_safe_free(sstr);
if (!strcasecmp(event, "message-summary")) { if (!strcasecmp(event, "message-summary")) {
if ((sql = switch_mprintf("select proto,sip_user,'%q',sub_to_user,sub_to_host,event,contact,call_id,full_from," if ((sql = switch_mprintf("select proto,sip_user,'%q',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"
" from sip_subscriptions where expires > -1 and event='message-summary' and sip_user='%q' " " from sip_subscriptions where version > -1 and "
"and (sip_host='%q' or presence_hosts like '%%%q%%')", to_host, to_user, to_host, to_host))) { "expires > -1 and event='message-summary' and sip_user='%q' "
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_sub_reg_callback, profile); "and (sip_host='%q' or presence_hosts like '%%%q%%')", to_host, to_user, to_host, to_host))) {
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_sub_reg_callback, profile);
switch_safe_free(sql); switch_safe_free(sql);
}
} }
}
end: end:
if (to_user && (strstr(to_user, "ext+") || strstr(to_user, "user+"))) { if (to_user && (strstr(to_user, "ext+") || strstr(to_user, "user+"))) {
char protocol[80]; char protocol[80];
char *p; char *p;
switch_copy_string(protocol, to_user, sizeof(protocol)); switch_copy_string(protocol, to_user, sizeof(protocol));
if ((p = strchr(protocol, '+'))) { if ((p = strchr(protocol, '+'))) {
*p = '\0'; *p = '\0';
} }
if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", protocol); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", protocol);
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name);
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, to_host); switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, to_host);
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "rpid", "active"); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "rpid", "active");
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "status", "Click To Call"); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "status", "Click To Call");
switch_event_fire(&sevent); switch_event_fire(&sevent);
} }
} else { } else {
if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) { if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name);
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host); switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, to_host); switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, to_host);
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto-specific-event-name", event); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto-specific-event-name", event);
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "event_type", "presence"); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "event_type", "presence");
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog"); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str); switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
switch_event_fire(&sevent); switch_event_fire(&sevent);
}
} }
}
if (event) { if (event) {
su_free(profile->home, event); su_free(profile->home, event);
} }
if (full_from) { if (full_from) {
su_free(profile->home, full_from); su_free(profile->home, full_from);
} }
if (full_via) { if (full_via) {
su_free(profile->home, full_via); su_free(profile->home, full_via);
} }
if (full_agent) { if (full_agent) {
su_free(profile->home, full_agent); su_free(profile->home, full_agent);
} }
switch_safe_free(d_user); switch_safe_free(d_user);
switch_safe_free(to_str); switch_safe_free(to_str);
switch_safe_free(contact_str); switch_safe_free(contact_str);
if (!sent_reply) { if (!sent_reply) {
nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END()); nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END());
}
} }
} }
sofia_gateway_subscription_t *sofia_find_gateway_subscription(sofia_gateway_t *gateway_ptr, const char *event) sofia_gateway_subscription_t *sofia_find_gateway_subscription(sofia_gateway_t *gateway_ptr, const char *event)
{ {
sofia_gateway_subscription_t *gw_sub_ptr; sofia_gateway_subscription_t *gw_sub_ptr;
...@@ -2624,145 +2528,197 @@ void sofia_presence_handle_sip_r_subscribe(int status, ...@@ -2624,145 +2528,197 @@ void sofia_presence_handle_sip_r_subscribe(int status,
} }
} }
static int sofia_counterpath_crutch(void *pArg, int argc, char **argv, char **columnNames)
{
nua_handle_t *nh;
sofia_profile_t *profile = (sofia_profile_t *) 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(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(profile->nua),
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());
}
return 0;
}
void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
tagi_t tags[]) tagi_t tags[])
{ {
if (sip) {
sip_from_t const *from = sip->sip_from; sip_from_t const *from;
char *from_user = NULL; char *from_user = NULL;
char *from_host = NULL; char *from_host = NULL;
char *rpid = ""; char *rpid = "";
sip_payload_t *payload = sip->sip_payload; sip_payload_t *payload;
char *event_type = NULL; char *event_type = NULL;
char etag[9] = ""; char etag[9] = "";
char expstr[30] = ""; char expstr[30] = "";
long exp = 0, exp_delta = 3600; long exp = 0, exp_delta = 3600;
char *pd_dup = NULL; char *pd_dup = NULL;
int count = 1;
/* the following could instead be refactored back to the calling event handler in sofia.c XXX MTK */ char *contact_str;
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { int open = 1;
/* 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, tags);
return;
}
}
if (from) { if (!sip) {
from_user = (char *) from->a_url->url_user; return;
from_host = (char *) from->a_url->url_host; }
from = sip->sip_from;
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, tags);
return;
} }
}
contact_str = sofia_glue_gen_contact_str(profile, sip, NULL);
if (from) {
from_user = (char *) from->a_url->url_user;
from_host = (char *) from->a_url->url_host;
}
exp_delta = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600);
exp_delta = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600); if (profile->force_publish_expires) {
if (profile->force_publish_expires) { exp_delta = profile->force_publish_expires;
exp_delta = profile->force_publish_expires; }
}
if (exp_delta < 0) { if (exp_delta < 0) {
exp = exp_delta; exp = exp_delta;
} else { } else {
exp = (long) switch_epoch_time_now(NULL) + exp_delta; exp = (long) switch_epoch_time_now(NULL) + exp_delta;
} }
if (payload) { if (payload) {
switch_xml_t xml, note, person, tuple, status, basic, act; switch_xml_t xml, note, person, tuple, status, basic, act;
switch_event_t *event; switch_event_t *event;
char *sql; char *sql;
char *full_agent = NULL; char *full_agent = NULL;
int count = 1;
pd_dup = strdup(payload->pl_data);
pd_dup = strdup(payload->pl_data); if ((xml = switch_xml_parse_str(pd_dup, strlen(pd_dup)))) {
char *open_closed = "", *note_txt = "";
if ((xml = switch_xml_parse_str(pd_dup, strlen(pd_dup)))) { if (sip->sip_user_agent) {
char *open_closed = "", *note_txt = ""; full_agent = sip_header_as_string(profile->home, (void *) sip->sip_user_agent);
}
if (sip->sip_user_agent) { if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status"))
full_agent = sip_header_as_string(profile->home, (void *) sip->sip_user_agent); && (basic = switch_xml_child(status, "basic"))) {
} open_closed = basic->txt;
}
if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status")) if ((person = switch_xml_child(xml, "dm:person")) && (note = switch_xml_child(person, "dm:note"))) {
&& (basic = switch_xml_child(status, "basic"))) { note_txt = note->txt;
open_closed = basic->txt; }
}
if ((person = switch_xml_child(xml, "dm:person")) && (note = switch_xml_child(person, "dm:note"))) { if (person && (act = switch_xml_child(person, "rpid:activities")) && act->child && act->child->name) {
note_txt = note->txt; if ((rpid = strchr(act->child->name, ':'))) {
rpid++;
} else {
rpid = act->child->name;
} }
}
if (!(open = !strcasecmp(open_closed, "open"))) {
sql = switch_mprintf("update sip_subscriptions set version = -1 where contact='%q'", contact_str);
} else {
sql = switch_mprintf("update sip_subscriptions set version = 0 where contact='%q'", contact_str);
}
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
if (person && (act = switch_xml_child(person, "rpid:activities")) && act->child && act->child->name) {
if ((rpid = strchr(act->child->name, ':'))) {
rpid++;
} else {
rpid = act->child->name;
}
}
if (sofia_test_pflag(profile, PFLAG_MULTIREG) && !strcasecmp(open_closed, "closed")) { if (sofia_test_pflag(profile, PFLAG_MULTIREG) && !open) {
char buf[32] = ""; char buf[32] = "";
sql = switch_mprintf("select count(*) from sip_registrations where sip_user='%q' and orig_server_host='%q'", from_user, from_host); sql = switch_mprintf("select count(*) from sip_registrations where "
sofia_glue_execute_sql2str(profile, profile->ireg_mutex, sql, buf, sizeof(buf)); "sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')", from_user, from_host, from_host);
switch_safe_free(sql);
count = atoi(buf); sofia_glue_execute_sql2str(profile, profile->ireg_mutex, sql, buf, sizeof(buf));
} switch_safe_free(sql);
count = atoi(buf);
}
/* if (count > 1) let's not and say we did or all the clients who subscribe to their own presence will think they selves is offline */ /* if (count > 1) let's not and say we did or all the clients who subscribe to their own presence will think they selves is offline */
if (count < 2) { event_type = sip_header_as_string(profile->home, (void *) sip->sip_event);
if ((sql =
switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' " if (count < 2) {
" and profile_name='%q' and hostname='%q'", from_user, from_host, profile->name, mod_sofia_globals.hostname))) { if ((sql =
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' "
} " and profile_name='%q' and hostname='%q'", from_user, from_host, profile->name, mod_sofia_globals.hostname))) {
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
}
if ((sql = if ((sql =
switch_mprintf("insert into sip_presence (sip_user, sip_host, status, rpid, expires, user_agent," switch_mprintf("insert into sip_presence (sip_user, sip_host, status, rpid, expires, user_agent,"
" profile_name, hostname, open_closed) " " profile_name, hostname, open_closed) "
"values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q')", "values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q')",
from_user, from_host, note_txt, rpid, exp, full_agent, profile->name, mod_sofia_globals.hostname, open_closed))) { from_user, from_host, note_txt, rpid, exp, full_agent, profile->name, mod_sofia_globals.hostname, open_closed))) {
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
} }
} else if (contact_str) {
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,
from_user, from_host, contact_str);
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_counterpath_crutch, profile);
switch_safe_free(sql);
}
event_type = sip_header_as_string(profile->home, (void *) sip->sip_event);
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent", full_agent);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", note_txt);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", event_type);
switch_event_fire(&event);
}
}
if (event_type) { if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
su_free(profile->home, event_type); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
} switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent", full_agent);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", note_txt);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", event_type);
switch_event_fire(&event);
}
if (full_agent) { if (event_type) {
su_free(profile->home, full_agent); su_free(profile->home, event_type);
} }
switch_xml_free(xml); if (full_agent) {
su_free(profile->home, full_agent);
} }
} else {
char *sql = switch_mprintf("update sip_presence set expires=%ld where sip_user='%q' and sip_host='%q' and profile_name='%q' and hostname='%q'", switch_xml_free(xml);
exp, from_user, from_host, profile->name, mod_sofia_globals.hostname);
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
} }
} else {
char *sql = switch_mprintf("update sip_presence set expires=%ld where sip_user='%q' and sip_host='%q' and profile_name='%q' and hostname='%q'",
exp, from_user, from_host, profile->name, mod_sofia_globals.hostname);
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
}
switch_safe_free(pd_dup); switch_safe_free(pd_dup);
switch_snprintf(expstr, sizeof(expstr), "%d", exp_delta); switch_snprintf(expstr, sizeof(expstr), "%d", exp_delta);
switch_stun_random_string(etag, 8, NULL); switch_stun_random_string(etag, 8, NULL);
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), SIPTAG_ETAG_STR(etag), SIPTAG_EXPIRES_STR(expstr), TAG_END()); nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), SIPTAG_ETAG_STR(etag), SIPTAG_EXPIRES_STR(expstr), TAG_END());
}
switch_safe_free(contact_str);
} }
void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip) void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论