From 478f165d253d3fbddc74389bdb6fd85c3f2f9d1b Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 7 Jan 2010 06:09:35 +0000 Subject: [PATCH] share and share alike, only nothing is alike in sip =/ git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16194 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/mod/endpoints/mod_sofia/mod_sofia.h | 1 + src/mod/endpoints/mod_sofia/sofia.c | 106 ++++- src/mod/endpoints/mod_sofia/sofia_glue.c | 9 +- src/mod/endpoints/mod_sofia/sofia_presence.c | 446 ++++++++++--------- src/switch_channel.c | 5 + 5 files changed, 335 insertions(+), 232 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 1197b37781..4cb350f85c 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -283,6 +283,7 @@ struct mod_sofia_globals { int guess_mask; char guess_mask_str[16]; int debug_presence; + int debug_sla; int auto_restart; int auto_nat; int tracelevel; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index ba3c0d9a2b..9dbd6476a6 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2413,6 +2413,8 @@ switch_status_t config_sofia(int reload, char *profile_name) su_log_set_level(NULL, atoi(val)); } else if (!strcasecmp(var, "debug-presence")) { mod_sofia_globals.debug_presence = atoi(val); + } else if (!strcasecmp(var, "debug-sla")) { + mod_sofia_globals.debug_sla = atoi(val); } else if (!strcasecmp(var, "auto-restart")) { mod_sofia_globals.auto_restart = switch_true(val); } else if (!strcasecmp(var, "rewrite-multicasted-fs-path")) { @@ -2771,6 +2773,7 @@ switch_status_t config_sofia(int reload, char *profile_name) if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE); profile->pres_type = PRES_TYPE_FULL; + sofia_set_pflag(profile, PFLAG_MULTIREG); profile->sla_contact = switch_core_sprintf(profile->pool, "sla-agent"); } } else if (!strcasecmp(var, "disable-srv")) { @@ -3384,6 +3387,8 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]) { + char *call_info = NULL; + if (sip && session) { switch_channel_t *channel = switch_core_session_get_channel(session); const char *uuid; @@ -3392,8 +3397,6 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status char network_ip[80]; int network_port = 0; switch_caller_profile_t *caller_profile = NULL; - char *call_info = NULL; - sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port); @@ -3406,6 +3409,51 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status switch_channel_clear_flag(channel, CF_REQ_MEDIA); + if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { + if (channel && sip->sip_call_info) { + char *p; + call_info = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_call_info); + if ((p = strchr(call_info, ';'))) { + switch_channel_set_variable(channel, "presence_call_info", p+1); + } + } else if ((status == 180 || status == 183 || status == 200)) { + char buf[128] = ""; + char *sql; + char *state = "active"; + + if (status != 200) { + state = "progressing"; + } + + if (sip && + sip->sip_from && sip->sip_from->a_url && sip->sip_from->a_url->url_user && sip->sip_from->a_url->url_host && + sip->sip_to && sip->sip_to->a_url && sip->sip_to->a_url->url_user && sip->sip_to->a_url->url_host) { + sql = switch_mprintf("select 'appearance-index=1' from sip_subscriptions where hostname='%q' and event='call-info' and " + "sub_to_user='%q' and sub_to_host='%q'", + mod_sofia_globals.hostname, sip->sip_to->a_url->url_user, sip->sip_from->a_url->url_host); + sofia_glue_execute_sql2str(profile, profile->ireg_mutex, sql, buf, sizeof(buf)); + + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "QUERY SQL %s [%s]\n", sql, buf); + } + free(sql); + + if (!zstr(buf)) { + sql = switch_mprintf("update sip_dialogs set call_info='%q',call_info_state='%q' " + "where uuid='%q'", buf, state, + switch_core_session_get_uuid(session)); + + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "QUERY SQL %s\n", sql); + } + + sofia_glue_actually_execute_sql(profile, sql, profile->ireg_mutex); + switch_safe_free(sql); + } + } + } + } + if ((status == 180 || status == 183 || status == 200)) { const char *x_freeswitch_support; @@ -3443,12 +3491,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status if (!p_contact) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing contact header in redirect request\n"); - return; - } - - if (sip->sip_call_info) { - call_info = sip_header_as_string(profile->home, (void *) sip->sip_call_info); - switch_channel_set_variable(channel, "presence_call_info", call_info); + goto end; } if ((br = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) { @@ -3579,7 +3622,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { if (!sofia_test_flag(tech_pvt, TFLAG_SENT_UPDATE)) { - return; + goto end; } sofia_clear_flag_locked(tech_pvt, TFLAG_SENT_UPDATE); @@ -3610,7 +3653,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status switch_core_session_queue_message(other_session, msg); switch_core_session_rwunlock(other_session); } - return; + goto end; } if ((status == 180 || status == 183 || status == 200)) { @@ -3664,11 +3707,15 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status const char *presence_data = switch_channel_get_variable(channel, "presence_data"); const char *presence_id = switch_channel_get_variable(channel, "presence_id"); char *full_contact = ""; - + char *p = NULL; + if (sip->sip_contact) { full_contact = sip_header_as_string(nua_handle_home(tech_pvt->nh), (void *) sip->sip_contact); } - + + if (call_info && (p = strchr(call_info, ';'))) { + p++; + } sql = switch_mprintf("insert into sip_dialogs " "(call_id,uuid,sip_to_user,sip_to_host,sip_from_user,sip_from_host,contact_user," "contact_host,state,direction,user_agent,profile_name,hostname,contact,presence_id,presence_data,call_info) " @@ -3678,18 +3725,13 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status to_user, to_host, from_user, from_host, contact_user, contact_host, astate, "outbound", user_agent, profile->name, mod_sofia_globals.hostname, switch_str_nil(full_contact), - switch_str_nil(presence_id), switch_str_nil(presence_data), switch_str_nil(call_info)); + switch_str_nil(presence_id), switch_str_nil(presence_data), switch_str_nil(p)); switch_assert(sql); sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); - } - - if (call_info) { - su_free(profile->home, call_info); - } - + } } else if (status == 200 && (profile->pres_type)) { char *sql = NULL; const char *presence_data = switch_channel_get_variable(channel, "presence_data"); @@ -3705,6 +3747,12 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status } + end: + + if (call_info) { + su_free(nua_handle_home(nh), call_info); + } + if (!session && (status == 180 || status == 183 || status == 200)) { /* nevermind */ nua_handle_bind(nh, NULL); @@ -5891,10 +5939,16 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ char *sql; char cid[512] = ""; char *str; + char *p = NULL; + if (sip->sip_to && sip->sip_to->a_url) { + if ((p = strchr(call_info_str, ';'))) { + p++; + } + sql = switch_mprintf("select call_id from sip_dialogs where call_info='%q' and sip_from_user='%q' and sip_from_host='%q'", - call_info_str, sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host); + switch_str_nil(p), sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host); if ((str = sofia_glue_execute_sql2str(profile, profile->ireg_mutex, sql, cid, sizeof(cid)))) { bnh = nua_handle_by_call_id(nua, str); @@ -5930,6 +5984,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ } if ((uuid = switch_channel_get_variable(b_channel, SWITCH_SIGNAL_BOND_VARIABLE))) { + switch_channel_set_variable(b_channel, "presence_call_info", NULL); one_leg = 0; } else { uuid = switch_core_session_get_uuid(b_session); @@ -5952,7 +6007,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if (!one_leg && (!b_tech_pvt || !sofia_test_flag(b_tech_pvt, TFLAG_SIP_HOLD)) && (!c_tech_pvt || !sofia_test_flag(c_tech_pvt, TFLAG_SIP_HOLD))) { - char *ext = switch_core_session_sprintf(b_session, "conference:%s@sla+flags{mintwo}", uuid); + char *ext = switch_core_session_sprintf(b_session, "answer,conference:%s@sla+flags{mintwo}", uuid); switch_channel_set_flag(c_channel, CF_REDIRECT); switch_ivr_session_transfer(b_session, ext, "inline", NULL); @@ -6117,13 +6172,18 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ const char *presence_data = switch_channel_get_variable(channel, "presence_data"); const char *presence_id = switch_channel_get_variable(channel, "presence_id"); char *full_contact = ""; + char *p = NULL; + if (sip->sip_contact) { full_contact = sip_header_as_string(nua_handle_home(tech_pvt->nh), (void *) sip->sip_contact); } if (call_info_str) { - switch_channel_set_variable(channel, "presence_call_info", call_info_str); + if ((p = strchr(call_info_str, ';'))) { + p++; + switch_channel_set_variable(channel, "presence_call_info", p); + } } @@ -6136,7 +6196,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ to_user, to_host, dialog_from_user, dialog_from_host, contact_user, contact_host, "confirmed", "inbound", user_agent, profile->name, mod_sofia_globals.hostname, switch_str_nil(full_contact), - switch_str_nil(presence_id), switch_str_nil(presence_data), switch_str_nil(call_info_str)); + switch_str_nil(presence_id), switch_str_nil(presence_data), switch_str_nil(p)); switch_assert(sql); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index bd4f6fc844..2afb15f55c 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -3831,7 +3831,8 @@ int sofia_glue_init_sql(sofia_profile_t *profile) " contact VARCHAR(255),\n" " presence_id VARCHAR(255),\n" " presence_data VARCHAR(255),\n" - " call_info VARCHAR(255)\n" + " call_info VARCHAR(255),\n" + " call_info_state VARCHAR(255)\n" ");\n"; char sub_sql[] = @@ -3917,6 +3918,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile) "create index sd_hostname on sip_dialogs (hostname)", "create index sd_presence_data on sip_dialogs (presence_data)", "create index sd_call_info on sip_dialogs (call_info)", + "create index sd_call_info on sip_dialogs (call_info_state)", "create index sp_hostname on sip_presence (hostname)", "create index sa_nonce on sip_authentication (nonce)", "create index sa_hostname on sip_authentication (hostname)", @@ -3986,7 +3988,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile) } free(test_sql); - test_sql = switch_mprintf("delete from sip_dialogs where hostname='%q' and call_info like '%%'", mod_sofia_globals.hostname); + test_sql = switch_mprintf("delete from sip_dialogs where hostname='%q' and call_info_state like '%%'", mod_sofia_globals.hostname); if (switch_odbc_handle_exec(odbc_dbh, test_sql, NULL) != SWITCH_ODBC_SUCCESS) { switch_odbc_handle_exec(odbc_dbh, "DROP TABLE sip_dialogs", NULL); @@ -4053,7 +4055,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile) switch_core_db_test_reactive(db, test_sql, "DROP TABLE sip_subscriptions", sub_sql); free(test_sql); - test_sql = switch_mprintf("delete from sip_dialogs where hostname='%q' and call_info like '%%'", mod_sofia_globals.hostname); + test_sql = switch_mprintf("delete from sip_dialogs where hostname='%q' and call_info_state like '%%'", mod_sofia_globals.hostname); switch_core_db_test_reactive(db, test_sql, "DROP TABLE sip_dialogs", dialog_sql); free(test_sql); @@ -4131,6 +4133,7 @@ int sofia_glue_init_sql(sofia_profile_t *profile) switch_core_db_exec(db, "create index if not exists sd_presence_id on sip_dialogs (presence_id)", NULL, NULL, NULL); switch_core_db_exec(db, "create index if not exists sd_presence_data on sip_dialogs (presence_data)", NULL, NULL, NULL); switch_core_db_exec(db, "create index if not exists sd_call_info on sip_dialogs (call_info)", NULL, NULL, NULL); + switch_core_db_exec(db, "create index if not exists sd_call_info on sip_dialogs (call_info_state)", NULL, NULL, NULL); switch_core_db_exec(db, "create index if not exists sp_hostname on sip_presence (hostname)", NULL, NULL, NULL); diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 9407006a78..2f9388de3d 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -35,13 +35,21 @@ #include "mod_sofia.h" #define SUB_OVERLAP 300 +struct state_helper { + switch_hash_t *hash; + sofia_profile_t *profile; + switch_memory_pool_t *pool; +}; + static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char **columnNames); static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char **columnNames); static int sofia_presence_sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames); static int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames); static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames); -static int broadsoft_sla_callback(void *pArg, int argc, char **argv, char **columnNames); +static int broadsoft_sla_gather_state_callback(void *pArg, int argc, char **argv, char **columnNames); +static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char **columnNames); +static void sync_sla(sofia_profile_t *profile, const char *to_user, const char *to_host, switch_bool_t clear, switch_bool_t unseize); struct resub_helper { sofia_profile_t *profile; @@ -589,51 +597,29 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) } if (call_info) { - sql = switch_mprintf("select sip_subscriptions.call_id,sip_subscriptions.expires,'%q',3, sip_dialogs.state,sip_dialogs.call_info, " - "sip_subscriptions.sub_to_host,'%q',event " - "from sip_subscriptions left join sip_dialogs on sip_subscriptions.sub_to_user=sip_dialogs.sip_from_user " - "and sip_subscriptions.sub_to_host=sip_dialogs.sip_from_host " - "where sip_subscriptions.hostname='%q' " - "and sub_to_user='%q' and sub_to_host='%q' " - "and (event='call-info' or event='line-seize') and sip_dialogs.call_info='%q'", - call_info, - call_info_state, - mod_sofia_globals.hostname, - euser, - host, - call_info - ); - if (mod_sofia_globals.debug_presence > 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql); +#if 0 + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SLA EVENT:\n"); + DUMP_EVENT(event); } - sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, broadsoft_sla_callback, profile); - switch_safe_free(sql); - - - - sql = switch_mprintf("select sip_subscriptions.call_id,sip_subscriptions.expires,'',3, sip_dialogs.state,sip_dialogs.call_info, " - "sip_subscriptions.sub_to_host,'',event " - "from sip_subscriptions inner join sip_dialogs on sip_subscriptions.sub_to_user=sip_dialogs.sip_from_user " - "and sip_subscriptions.sub_to_host=sip_dialogs.sip_from_host " - "where sip_subscriptions.hostname='%q' " - "and sub_to_user='%q' and sub_to_host='%q' " - "and event='call-info' and sip_dialogs.call_info!='%q'", - mod_sofia_globals.hostname, - euser, - host, - call_info - ); +#endif - if (mod_sofia_globals.debug_presence > 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"PRES SQL %s\n", sql); + sql = switch_mprintf("update sip_dialogs set call_info_state='%q' where hostname='%q' and sip_dialogs.sip_from_user='%q' " + "and sip_dialogs.sip_from_host='%q' and call_info='%q'", + call_info_state, + mod_sofia_globals.hostname, + euser, host, call_info); + + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STATE SQL %s\n", sql); } - - sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, broadsoft_sla_callback, profile); + sofia_glue_actually_execute_sql(profile, sql, profile->ireg_mutex); switch_safe_free(sql); - + + sync_sla(profile, euser, host, SWITCH_TRUE, SWITCH_TRUE); } - + if ((sql = switch_mprintf( @@ -1463,46 +1449,29 @@ static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char return 0; } -static int broadsoft_sla_callback(void *pArg, int argc, char **argv, char **columnNames) +static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char **columnNames) { + struct state_helper *sh = (struct state_helper *) pArg; + char key[256] = ""; + char *data = NULL, *tmp; char *call_id = argv[0]; char *expires = argv[1]; - char *header = argv[2]; - char *onoff = argv[3]; - char *state = NULL; - char *call_info = NULL; - char *call_info_state = NULL; - char *event = NULL; - char *host = NULL; - sofia_profile_t *profile = (sofia_profile_t *) pArg; - nua_handle_t *nh; + char *user = argv[2]; + char *host = argv[3]; + char *event = argv[4]; + int i; char sstr[128] = "", expires_str[128] = ""; time_t exptime = 3600; - int on = atoi(onoff); - char buf[512] = ""; - const char *r_state = "idle"; - int i; + nua_handle_t *nh; - if (mod_sofia_globals.debug_presence > 1) { + if (mod_sofia_globals.debug_sla > 1) { for(i = 0; i < argc; i++) { - printf("COL [%s]=[%s]\n", columnNames[i], argv[i]); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"SLA3: %d [%s]=[%s]\n", i, columnNames[i], argv[i]); } - printf("\non=%d\n\n", on); } - if (on >= 2 && argc >= 7) { - state = argv[4]; - call_info = argv[5]; - host = argv[6]; - call_info_state = argv[7]; - if (argc > 8) event = argv[8]; - } else { - call_info = header; - } - - if (zstr(event)) { - event = "call-info"; - } + switch_snprintf(key, sizeof(key), "%s%s", user, host); + data = switch_core_hash_find(sh->hash, key); if (expires) { long tmp = atol(expires); @@ -1514,63 +1483,160 @@ static int broadsoft_sla_callback(void *pArg, int argc, char **argv, char **colu } else { switch_snprintf(sstr, sizeof(sstr), "terminated;reason=noresource"); } - + switch_snprintf(expires_str, sizeof(expires_str), "%u", (unsigned)exptime); - if (zstr(call_info)) { - call_info = header; - } + data = switch_core_hash_find(sh->hash, key); - if (on == 3) { - if (!zstr(call_info_state)) { - r_state = call_info_state; - } else if (!zstr(argv[4])) { - r_state = "active"; - } else { - r_state = "idle"; - } - } else if (on) { - r_state = "seized"; + if (data) { + tmp = switch_core_sprintf(sh->pool, "%s,;appearance-index=*;appearance-state=idle", data, host); + } else { + tmp = switch_core_sprintf(sh->pool, ";appearance-index=*;appearance-state=idle", host); } + if (!strcasecmp(event, "line-seize") && (nh = nua_handle_by_call_id(sh->profile->nua, call_id))) { + char *hack; - if (zstr(call_info)) { - switch_snprintf(buf, sizeof(buf), ";apperance-index=*", host); - call_info = buf; + if ((hack = (char *)switch_stristr("=seized", tmp))) { + 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()); + return 0; } - if (mod_sofia_globals.debug_presence > 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[%s][%s][%s][%s]\n", event, call_info, call_id, r_state); - } - - if (!strcasecmp(event, "line-seize") && (nh = nua_handle_by_call_id(profile->nua, call_id))) { - if (strcasecmp(r_state, "seized")) { - char *new_header = switch_mprintf("%s;appearance-state=%s", call_info, r_state); - nua_notify(nh, - SIPTAG_EXPIRES_STR("0"), - SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), - SIPTAG_EVENT_STR("line-seize"), SIPTAG_CALL_INFO_STR(new_header), TAG_END()); - switch_safe_free(new_header); - - } - return 0; - } - - if (profile && call_id && call_info && (nh = nua_handle_by_call_id(profile->nua, call_id))) { - char *new_header = switch_mprintf("%s;appearance-state=%s", call_info, r_state); - + if (!strcasecmp(event, "call-info") && (nh = nua_handle_by_call_id(sh->profile->nua, call_id))) { nua_notify(nh, TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)), SIPTAG_SUBSCRIPTION_STATE_STR(sstr), - SIPTAG_EVENT_STR("call-info"), SIPTAG_CALL_INFO_STR(new_header), TAG_END()); + SIPTAG_EVENT_STR("call-info"), SIPTAG_CALL_INFO_STR(tmp), TAG_END()); - switch_safe_free(new_header); } - return 0; } +static int broadsoft_sla_gather_state_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct state_helper *sh = (struct state_helper *) pArg; + char key[256] = ""; + char *data = NULL, *tmp; + char *user = argv[0]; + char *host = argv[1]; + char *info = argv[2]; + char *state = argv[3]; + int i; + + if (mod_sofia_globals.debug_sla > 1) { + for(i = 0; i < argc; i++) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"SLA2: %d [%s]=[%s]\n", i, columnNames[i], argv[i]); + } + } + + if (zstr(info)) { + return 0; + } + + if (zstr(state)) { + state = "idle"; + } + + switch_snprintf(key, sizeof(key), "%s%s", user, host); + + data = switch_core_hash_find(sh->hash, key); + + if (data) { + tmp = switch_core_sprintf(sh->pool, "%s,;%s;appearance-state=%s", data, host, info, state); + } else { + tmp = switch_core_sprintf(sh->pool, ";%s;appearance-state=%s", host, info, state); + } + + switch_core_hash_insert(sh->hash, key, tmp); + + return 0; +} + +static void sync_sla(sofia_profile_t *profile, const char *to_user, const char *to_host, switch_bool_t clear, switch_bool_t unseize) +{ + struct state_helper *sh; + switch_memory_pool_t *pool; + char *sql; + + switch_core_new_memory_pool(&pool); + sh = switch_core_alloc(pool, sizeof(*sh)); + sh->pool = pool; + switch_core_hash_init(&sh->hash, sh->pool); + + sql = switch_mprintf("select sip_from_user,sip_from_host,call_info,call_info_state from sip_dialogs " + "where hostname='%q' " + "and sip_from_user='%q' and sip_from_host='%q' ", + mod_sofia_globals.hostname, + to_user, + to_host + ); + + + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql); + } + sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, broadsoft_sla_gather_state_callback, sh); + switch_safe_free(sql); + + + if (unseize) { + sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event " + "from sip_subscriptions " + "where hostname='%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 + ); + } else { + sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event " + "from sip_subscriptions " + "where hostname='%q' " + "and sub_to_user='%q' and sub_to_host='%q' " + "and (event='call-info')", + mod_sofia_globals.hostname, + to_user, + to_host + ); + } + + + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql); + } + sh->profile = profile; + sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, broadsoft_sla_notify_callback, sh); + switch_safe_free(sql); + sh = NULL; + switch_core_destroy_memory_pool(&pool); + + + + if (clear) { + sql = switch_mprintf("delete from sip_dialogs where sip_from_user='%q' and sip_from_host='%q' and call_info_state='seized'", + to_user, + to_host + ); + + + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql); + } + sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); + } + +} + + void sofia_presence_handle_sip_i_subscribe(int status, char const *phrase, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, @@ -1758,7 +1824,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, if ((p = strchr(protocol, '+'))) { *p = '\0'; } - + 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, "login", profile->name); @@ -1831,7 +1897,8 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_mutex_lock(profile->ireg_mutex); switch_assert(sql != NULL); - sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); + sofia_glue_actually_execute_sql(profile, sql, NULL); + switch_safe_free(sql); if (sub_state == nua_substate_terminated) { sstr = switch_mprintf("terminated"); @@ -1843,7 +1910,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_snprintf(accept + strlen(accept), sizeof(accept) - strlen(accept), "%s%s ", ap->ac_type, ap->ac_next ? "," : ""); ap = ap->ac_next; } - + /* negative in exptime means keep bumping up sub time to avoid a snafu where every device has it's own rules about subscriptions that somehow barely resemble the RFC not that I blame them because the RFC MAY be amibiguous and SHOULD be deleted. So to avoid the problem we keep resetting the expiration date of the subscription so it never expires. @@ -1865,13 +1932,17 @@ void sofia_presence_handle_sip_i_subscribe(int status, (long)switch_epoch_time_now(NULL) + exp_delta, full_agent, accept, profile->name,mod_sofia_globals.hostname, network_port, network_ip); - if (mod_sofia_globals.debug_presence > 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s SUBSCRIBE %s@%s %s@%s\n", profile->name, from_user, from_host, to_user, to_host); + 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); } - switch_assert(sql != NULL); - sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); + sofia_glue_actually_execute_sql(profile, sql, profile->ireg_mutex); + switch_safe_free(sql); + sstr = switch_mprintf("active;expires=%ld", exp_delta); } @@ -1939,79 +2010,82 @@ void sofia_presence_handle_sip_i_subscribe(int status, if (sub_state == nua_substate_terminated) { char *full_call_info = NULL; + char *p = NULL; 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("0"), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), - TAG_IF(full_call_info, SIPTAG_CALL_INFO_STR(full_call_info)), - TAG_END()); + 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 (!strcasecmp(event, "line-seize")) { - if (full_call_info) { - sql = switch_mprintf("select call_id,expires,'%q',0 from sip_subscriptions where hostname='%q' " + if (!strcasecmp(event, "line-seize")) { + sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_TRUE); + +#if 0 + + + sql = switch_mprintf("select call_id,expires,'%q',0,sub_to_host from sip_subscriptions where hostname='%q' " "and sub_to_user='%q' and sub_to_host='%q' " - "and event='call-info' and contact != '%q'", - full_call_info, + "and event='call-info' ", + switch_str_nil(p), mod_sofia_globals.hostname, to_user, - to_host, - contact_str + to_host ); - if (mod_sofia_globals.debug_presence > 1) { + if (mod_sofia_globals.debug_sla > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "UNSEIZE SQL %s\n", sql); } sofia_glue_execute_sql_callback(profile, NULL, sql, broadsoft_sla_callback, profile); switch_safe_free(sql); +#endif } - } - - if (full_call_info) { + su_free(profile->home, full_call_info); - } - + } } 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); - } - - - nua_notify(nh, - SIPTAG_EXPIRES_STR(exp_delta_str), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), - SIPTAG_EVENT_STR("line-seize"), SIPTAG_CALL_INFO_STR(full_call_info), TAG_END()); - - if (full_call_info) { - sql = switch_mprintf("select sip_subscriptions.call_id,sip_subscriptions.expires,'%q',4, sip_dialogs.state,sip_dialogs.call_info, " - "sip_subscriptions.sub_to_host,'','call-info' " - "from sip_subscriptions left join sip_dialogs on sip_subscriptions.sub_to_user=sip_dialogs.sip_from_user " - "and sip_subscriptions.sub_to_host=sip_dialogs.sip_from_host " - "where sip_subscriptions.hostname='%q' " - "and sub_to_user='%q' and sub_to_host='%q' " - "and event='call-info'and sip_subscriptions.contact != '%q'", - full_call_info, - mod_sofia_globals.hostname, - to_user, - to_host, - contact_str - ); - - if (mod_sofia_globals.debug_presence > 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SEIZE SQL %s\n", sql); + if ((p = strchr(full_call_info, ';'))) { + p++; } - sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, broadsoft_sla_callback, profile); + 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("insert into sip_dialogs (sip_from_user,sip_from_host,call_info,call_info_state,hostname) " + "values ('%q','%q','%q','seized','%q')", + to_user, + to_host, + switch_str_nil(p), + mod_sofia_globals.hostname + ); + + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SEIZE SQL %s\n", sql); + } + sofia_glue_actually_execute_sql(profile, sql, profile->ireg_mutex); switch_safe_free(sql); + sync_sla(profile, to_user, to_host, SWITCH_TRUE, SWITCH_FALSE); + su_free(profile->home, full_call_info); } } @@ -2019,40 +2093,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, if (!strcasecmp(event, "call-info")) { - -#if 0 - int x = 0; - for (x = 1; x < 5; x++) { - char tmp[128] = ""; - - switch_snprintf(tmp, sizeof(tmp), ";apperance-index=%d;appearance-state=idle", to_host, x); - nua_notify(nh, - SIPTAG_EXPIRES_STR(exp_delta_str), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), - SIPTAG_EVENT_STR("call-info"), SIPTAG_CALL_INFO_STR(tmp), TAG_END()); - } -#endif - - - - sql = switch_mprintf("select sip_subscriptions.call_id,sip_subscriptions.expires,'',2, sip_dialogs.state,sip_dialogs.call_info, " - "sip_subscriptions.sub_to_host " - "from sip_subscriptions inner join sip_dialogs on sip_subscriptions.sub_to_user=sip_dialogs.sip_from_user " - "and sip_subscriptions.sub_to_host=sip_dialogs.sip_from_host " - "where sip_subscriptions.hostname='%q' " - "and sub_to_user='%q' and sub_to_host='%q' " - "and event='call-info' and sip_subscriptions.contact != '%q'", - mod_sofia_globals.hostname, - to_user, - to_host, - contact_str - ); - - if (mod_sofia_globals.debug_presence > 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CALL-INFO SQL %s\n", sql); - } - sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, broadsoft_sla_callback, profile); - switch_safe_free(sql); + sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE); } } @@ -2061,21 +2102,14 @@ void sofia_presence_handle_sip_i_subscribe(int status, sent_reply++; -#if 0 - nua_notify(nh, - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event), - SIPTAG_EXPIRES_STR(exp_delta_str), - SIPTAG_CONTENT_TYPE_STR("application/notice"), - SIPTAG_PAYLOAD_STR("Note: Come to ClueCon http://www.cluecon.com\n\n"), TAG_END()); -#endif - switch_safe_free(sstr); 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," "full_via,expires,user_agent,accept,profile_name,network_ip" - " from sip_subscriptions where event='message-summary' and sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')", + " from sip_subscriptions where event='message-summary' and sip_user='%q' " + "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); diff --git a/src/switch_channel.c b/src/switch_channel.c index 3fac2eaa48..0e980d0031 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -512,6 +512,7 @@ SWITCH_DECLARE(void) switch_channel_presence(switch_channel_t *channel, const ch call_info_state = "alerting"; } } + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "presence-call-info-state", call_info_state); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "presence-call-info", call_info); } @@ -1920,6 +1921,10 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_chan switch_channel_state_t last_state; switch_event_t *event; + if (hangup_cause == SWITCH_CAUSE_LOSE_RACE) { + switch_channel_set_variable(channel, "presence_call_info", NULL); + } + switch_mutex_lock(channel->state_mutex); last_state = channel->state; channel->state = CS_HANGUP;