diff --git a/conf/freeswitch.xml b/conf/freeswitch.xml index bfbc344ba7..0477623624 100644 --- a/conf/freeswitch.xml +++ b/conf/freeswitch.xml @@ -113,8 +113,8 @@ - - + + @@ -268,10 +268,12 @@ - - - - + + + + + + @@ -296,7 +298,23 @@ - + + + + + + + + + + + + + + + + + diff --git a/libs/libdingaling/src/libdingaling.c b/libs/libdingaling/src/libdingaling.c index 8a4a8e9b59..656bf84521 100644 --- a/libs/libdingaling/src/libdingaling.c +++ b/libs/libdingaling/src/libdingaling.c @@ -712,7 +712,7 @@ static int on_presence(void *user_data, ikspak *pak) if (!type || (type && strcasecmp(type, "probe"))) { if (handle->session_callback) { - handle->session_callback(handle, NULL, signal, to, from, status ? status : "n/a", show ? show : "n/a"); + handle->session_callback(handle, NULL, signal, to, id, status ? status : "n/a", show ? show : "n/a"); } } @@ -720,7 +720,7 @@ static int on_presence(void *user_data, ikspak *pak) return IKS_FILTER_EAT; } -static void do_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *message) +static void do_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *rpid, char *message) { iks *pres; char buf[512]; @@ -743,21 +743,28 @@ static void do_presence(ldl_handle_t *handle, char *from, char *to, char *type, iks_insert_attrib(pres, "type", type); } - - - if (message) { - if ((tag = iks_insert (pres, "status"))) { - iks_insert_cdata(tag, message ? message : "", 0); - if ((tag = iks_insert(pres, "c"))) { - iks_insert_attrib(tag, "node", "http://www.freeswitch.org/xmpp/client/caps"); - iks_insert_attrib(tag, "ver", "1.0.0.1"); - iks_insert_attrib(tag, "ext", "sidebar voice-v1"); - iks_insert_attrib(tag, "client", "libdingaling2"); - iks_insert_attrib(tag, "xmlns", "http://jabber.org/protocol/caps"); - } + if (rpid) { + if ((tag = iks_insert (pres, "show"))) { + iks_insert_cdata(tag, rpid, 0); } } - + + if (message) { + if ((tag = iks_insert (pres, "status"))) { + iks_insert_cdata(tag, message, 0); + } + } + + if (message || rpid) { + if ((tag = iks_insert(pres, "c"))) { + iks_insert_attrib(tag, "node", "http://www.freeswitch.org/xmpp/client/caps"); + iks_insert_attrib(tag, "ver", "1.0.0.1"); + iks_insert_attrib(tag, "ext", "sidebar voice-v1"); + iks_insert_attrib(tag, "client", "libdingaling"); + iks_insert_attrib(tag, "xmlns", "http://jabber.org/protocol/caps"); + } + } + apr_queue_push(handle->queue, pres); } } @@ -1559,9 +1566,9 @@ void *ldl_handle_get_private(ldl_handle_t *handle) return handle->private_info; } -void ldl_handle_send_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *message) +void ldl_handle_send_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *rpid, char *message) { - do_presence(handle, from, to, type, message); + do_presence(handle, from, to, type, rpid, message); } void ldl_handle_send_msg(ldl_handle_t *handle, char *from, char *to, char *subject, char *body) diff --git a/libs/libdingaling/src/libdingaling.h b/libs/libdingaling/src/libdingaling.h index c71bb9ed64..88b9ec9303 100644 --- a/libs/libdingaling/src/libdingaling.h +++ b/libs/libdingaling/src/libdingaling.h @@ -369,9 +369,10 @@ void ldl_session_send_msg(ldl_session_t *session, char *subject, char *body); \param from the from address \param to the to address \param type the type of presence + \param rpid data for the icon \param message a status message */ -void ldl_handle_send_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *message); +void ldl_handle_send_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *rpid, char *message); /*! \brief Send a message diff --git a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c index d0f99e8df1..1a83259825 100644 --- a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c +++ b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c @@ -94,6 +94,11 @@ static void perform_substitution(pcre *re, int match_count, char *data, char *fi for (x = 0; x < (len-1) && x < strlen(data);) { if (data[x] == '$') { x++; + + if (!(data[x] > 47 && data[x] < 58)) { + substituted[y++] = data[x-1]; + continue; + } while (data[x] > 47 && data[x] < 58) { index[z++] = data[x]; diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c index 8411fd5ba5..382f884936 100644 --- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c +++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c @@ -47,7 +47,9 @@ static switch_memory_pool_t *module_pool = NULL; static char sub_sql[] = "CREATE TABLE subscriptions (\n" " sub_from VARCHAR(255),\n" -" sub_to VARCHAR(255)\n" +" sub_to VARCHAR(255),\n" +" show VARCHAR(255),\n" +" status VARCHAR(255)\n" ");\n"; @@ -186,6 +188,38 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi static ldl_status handle_response(ldl_handle_t *handle, char *id); static switch_status_t load_config(void); +static char *translate_rpid(char *in, char *ext) +{ + char *r = NULL; + + if (in && (strstr(in, "null") || strstr(in, "NULL"))) { + in = NULL; + } + + if (!in) { + in = ext; + } + + if (!in) { + return NULL; + } + + if (!strcasecmp(in, "busy")) { + r = "dnd"; + } + + if (!strcasecmp(in, "unavailable")) { + r = "dnd"; + } + + if (ext && !strcasecmp(ext, "idle")) { + r = "away"; + } else if (ext && !strcasecmp(ext, "away")) { + r = "away"; + } + + return r; +} static int sub_callback(void *pArg, int argc, char **argv, char **columnNames) { @@ -194,16 +228,17 @@ static int sub_callback(void *pArg, int argc, char **argv, char **columnNames) char *sub_from = argv[0]; char *sub_to = argv[1]; char *type = argv[2]; - char *show = argv[3]; + char *rpid = argv[3]; + char *status = argv[4]; if (switch_strlen_zero(type)) { type = NULL; } else if (!strcasecmp(type, "unavailable")) { - show = NULL; + status = NULL; } - - - ldl_handle_send_presence(profile->handle, sub_to, sub_from, type, show); + rpid = translate_rpid(rpid, status); + + ldl_handle_send_presence(profile->handle, sub_to, sub_from, type, rpid, status); return 0; } @@ -215,9 +250,17 @@ static int rost_callback(void *pArg, int argc, char **argv, char **columnNames) char *sub_from = argv[0]; char *sub_to = argv[1]; char *show = argv[2]; + char *status = argv[3]; + if (!strcasecmp(status, "n/a")) { + if (!strcasecmp(show, "dnd")) { + status = "Busy"; + } else if (!strcasecmp(show, "away")) { + status = "Idle"; + } + } - ldl_handle_send_presence(profile->handle, sub_to, sub_from, NULL, show); + ldl_handle_send_presence(profile->handle, sub_to, sub_from, NULL, show, status); return 0; } @@ -229,22 +272,17 @@ static void pres_event_handler(switch_event_t *event) void *val; char *from = switch_event_get_header(event, "from"); char *status= switch_event_get_header(event, "status"); - char *show= switch_event_get_header(event, "show"); - char *type = NULL; + char *rpid = switch_event_get_header(event, "rpid"); + char *type = switch_event_get_header(event, "event_subtype"); char *sql; switch_core_db_t *db; char *p; if (status && !strcasecmp(status, "n/a")) { - status = show; - if (status && !strcasecmp(status, "n/a")) { - status = NULL; - } + status = NULL; } - - switch(event->event_id) { case SWITCH_EVENT_PRESENCE_IN: if (!status) { @@ -259,12 +297,12 @@ static void pres_event_handler(switch_event_t *event) } - if ((p = strchr(from, '/'))) { *p = '\0'; } - sql = switch_mprintf("select *,'%q','%q' from subscriptions where sub_to='%q'", type ? type : "", status ? status : "unavailable", from); + sql = switch_mprintf("select sub_from, sub_to,'%q','%q','%q' from subscriptions where sub_to='%q'", + type ? type : "", rpid, status ? status : "unavailable", from); for (hi = switch_hash_first(apr_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) { char *errmsg; switch_hash_this(hi, NULL, NULL, &val); @@ -326,7 +364,7 @@ static switch_status_t chat_send(char *from, char *to, char *subject, char *body static void roster_event_handler(switch_event_t *event) { char *status= switch_event_get_header(event, "status"); - char *show= switch_event_get_header(event, "show"); + char *from= switch_event_get_header(event, "from"); char *event_type = switch_event_get_header(event, "event_type"); struct mdl_profile *profile = NULL; switch_hash_index_t *hi; @@ -334,19 +372,19 @@ static void roster_event_handler(switch_event_t *event) char *sql; switch_core_db_t *db; - if (status && !strcasecmp(status, "n/a")) { - status = show; - if (status && !strcasecmp(status, "n/a")) { - status = NULL; - } + status = NULL; } if (switch_strlen_zero(event_type)) { event_type="presence"; } - sql = switch_mprintf("select *,'%q' from subscriptions", show ? show : "unavilable"); + if (from) { + sql = switch_mprintf("select *,'%q' from subscriptions where sub_from='%q'", status ? status : "", from); + } else { + sql = switch_mprintf("select *,'%q' from subscriptions", status ? status : ""); + } for (hi = switch_hash_first(apr_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) { char *errmsg; @@ -457,6 +495,12 @@ static void *SWITCH_THREAD_FUNC handle_thread_run(switch_thread_t *thread, void { ldl_handle_t *handle = obj; struct mdl_profile *profile = NULL; + switch_event_t *event; + + if (switch_event_create(&event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", MDL_CHAT_NAME); + switch_event_fire(&event); + } profile = ldl_handle_get_private(handle); globals.handles++; @@ -1307,7 +1351,7 @@ static switch_status_t channel_outgoing_channel(switch_core_session_t *session, snprintf(ubuf, sizeof(ubuf), "%s@%s/talk", u, profile_name); user = ubuf; } else { - user = mdl_profile->login; + user = (char *) modname; } if ((mdl_profile = switch_core_hash_find(globals.profile_hash, profile_name))) { @@ -1554,25 +1598,6 @@ static void set_profile_val(struct mdl_profile *profile, char *var, char *val) if (switch_true(val)) { profile->user_flags |= LDL_FLAG_TLS; } - } else if (!strcasecmp(var, "component")) { - if (switch_true(val)) { - char dbname[256]; - switch_core_db_t *db; - - profile->user_flags |= LDL_FLAG_COMPONENT; - switch_mutex_init(&profile->mutex, SWITCH_MUTEX_NESTED, module_pool); - snprintf(dbname, sizeof(dbname), "dingaling_%s", profile->name); - profile->dbname = switch_core_strdup(module_pool, dbname); - - if ((db = switch_core_db_open_file(profile->dbname))) { - switch_core_db_test_reactive(db, "select * from subscriptions", sub_sql); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n"); - return; - } - switch_core_db_close(db); - - } } else if (!strcasecmp(var, "sasl")) { if (!strcasecmp(val, "plain")) { profile->user_flags |= LDL_FLAG_SASL_PLAIN; @@ -1669,6 +1694,7 @@ static switch_status_t dl_login(char *arg, switch_core_session_t *session, switc } } + if (profile && init_profile(profile, 1) == SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "OK\n"); } else { @@ -1715,7 +1741,14 @@ static switch_status_t load_config(void) } } - for (xmlint = switch_xml_child(cfg, "interface"); xmlint; xmlint = xmlint->next) { + if (!(xmlint = switch_xml_child(cfg, "profile"))) { + if ((xmlint = switch_xml_child(cfg, "interface"))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "!!!!!!! DEPRICATION WARNING 'interface' is now 'profile' !!!!!!!\n"); + } + } + + for (; xmlint; xmlint = xmlint->next) { + char *type = (char *) switch_xml_attr_soft(xmlint, "type"); for (param = switch_xml_child(xmlint, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); @@ -1732,6 +1765,31 @@ static switch_status_t load_config(void) set_profile_val(profile, var, val); } + + if (type && !strcasecmp(type, "component")) { + char dbname[256]; + switch_core_db_t *db; + + if (!profile->login && profile->name) { + profile->login = switch_core_strdup(module_pool, profile->name); + } + + switch_set_flag(profile, TFLAG_AUTO); + profile->message = ""; + profile->user_flags |= LDL_FLAG_COMPONENT; + switch_mutex_init(&profile->mutex, SWITCH_MUTEX_NESTED, module_pool); + snprintf(dbname, sizeof(dbname), "dingaling_%s", profile->name); + profile->dbname = switch_core_strdup(module_pool, dbname); + + if ((db = switch_core_db_open_file(profile->dbname))) { + switch_core_db_test_reactive(db, "select * from subscriptions", sub_sql); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n"); + continue; + } + switch_core_db_close(db); + } + if (profile) { init_profile(profile, switch_test_flag(profile, TFLAG_AUTO) ? 1 : 0); profile = NULL; @@ -1815,7 +1873,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi case LDL_SIGNAL_SUBSCRIBE: if ((profile->user_flags & LDL_FLAG_COMPONENT)) { - if ((sql = switch_mprintf("insert into subscriptions values('%q','%q')", from, to))) { + if ((sql = switch_mprintf("insert into subscriptions values('%q','%q','%q','%q')", from, to, msg, subject))) { execute_sql(profile->dbname, sql, profile->mutex); switch_core_db_free(sql); } @@ -1829,17 +1887,30 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi } break; case LDL_SIGNAL_PRESENCE_IN: + + if ((sql = switch_mprintf("update subscriptions set show='%q', status='%q' where sub_from='%q'", msg, subject, from))) { + execute_sql(profile->dbname, sql, profile->mutex); + switch_core_db_free(sql); + } + if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", MDL_CHAT_NAME); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->login); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", from); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", msg); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", subject); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "show", "%s", msg); switch_event_fire(&event); } break; + case LDL_SIGNAL_PRESENCE_OUT: + + if ((sql = switch_mprintf("update subscriptions set show='%q', status='%q' where sub_from='%q'", msg, subject, from))) { + execute_sql(profile->dbname, sql, profile->mutex); + switch_core_db_free(sql); + } + if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", MDL_CHAT_NAME); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->login); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 6c39a07a97..0ad54eeb58 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -43,9 +43,6 @@ struct outbound_reg; typedef struct outbound_reg outbound_reg_t; -struct sip_presence; -typedef struct sip_presence sip_presence_t; - struct sofia_profile; typedef struct sofia_profile sofia_profile_t; #define NUA_MAGIC_T sofia_profile_t @@ -53,7 +50,6 @@ typedef struct sofia_profile sofia_profile_t; struct sofia_private { switch_core_session_t *session; outbound_reg_t *oreg; - sip_presence_t *presence; }; typedef struct sofia_private sofia_private_t; @@ -86,6 +82,7 @@ static char reg_sql[] = " host VARCHAR(255),\n" " contact VARCHAR(1024),\n" " status VARCHAR(255),\n" +" rpid VARCHAR(255),\n" " expires INTEGER(8)" ");\n"; @@ -211,13 +208,6 @@ struct outbound_reg { }; -struct sip_presence { - sofia_private_t sofia_private; - nua_handle_t *nh; - sofia_profile_t *profile; -}; - - struct sofia_profile { int debug; char *name; @@ -251,7 +241,6 @@ struct sofia_profile { switch_mutex_t *ireg_mutex; switch_mutex_t *oreg_mutex; outbound_reg_t *registrations; - sip_presence_t *presence; su_home_t *home; switch_hash_t *profile_hash; switch_hash_t *chat_hash; @@ -2673,16 +2662,14 @@ static uint8_t handle_register(nua_t *nua, switch_event_t *s_event; char *from_user = (char *) from->a_url->url_user; char *from_host = (char *) from->a_url->url_host; - char contact_str[1025] = ""; + char contact_str[1024] = ""; char buf[512]; char *passwd = NULL; uint8_t stale = 0, ret = 0, forbidden = 0; auth_res_t auth_res; long exptime = 60; switch_event_t *event; - - - + char *rpid = "unknown"; if (sip->sip_contact) { char *port = (char *) contact->m_url->url_port; @@ -2824,76 +2811,84 @@ static uint8_t handle_register(nua_t *nua, } reg: - if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) { - sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Registered', %ld)", - from_user, - from_host, - contact_str, - (long) time(NULL) + (long)exptime); + if (exptime) { + if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) { + sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Registered', '%q', %ld)", + from_user, + from_host, + contact_str, + rpid, + (long) time(NULL) + (long)exptime); - } else { - sql = switch_mprintf("update sip_registrations set contact='%q', expires=%ld where user='%q' and host='%q'", - contact_str, - (long) time(NULL) + (long)exptime, - from_user, - from_host); + } else { + sql = switch_mprintf("update sip_registrations set contact='%q', expires=%ld, rpid='%q' where user='%q' and host='%q'", + contact_str, + (long) time(NULL) + (long)exptime, + rpid, + from_user, + from_host); - } + } - if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", profile->name); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-user", "%s", from_user); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-host", "%s", from_host); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", contact_str); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long)exptime); - switch_event_fire(&s_event); - } + if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", profile->name); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-user", "%s", from_user); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-host", "%s", from_host); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", contact_str); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long)exptime); + switch_event_fire(&s_event); + } - if (sql) { - execute_sql(profile->dbname, sql, profile->ireg_mutex); - switch_safe_free(sql); - sql = NULL; - } + if (sql) { + execute_sql(profile->dbname, sql, profile->ireg_mutex); + switch_safe_free(sql); + sql = NULL; + } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Register from [%s@%s] contact [%s] expires %ld\n", - from_user, - from_host, + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Register:\nFrom: [%s@%s]\nContact: [%s]\nExpires: [%ld]\n", + from_user, + from_host, contact_str, (long)exptime ); - - if (switch_event_create(&event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host); - switch_event_fire(&event); - } - - if (exptime) { if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_NAME, from_user, from_host); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Registered"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "show", "Registered"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); switch_event_fire(&event); } } else { + if ((sql = switch_mprintf("delete from sip_subscriptions where user='%q' and host='%q'", from_user, from_host))) { + execute_sql(profile->dbname, sql, profile->ireg_mutex); + switch_safe_free(sql); + sql = NULL; + } if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_NAME, from_user, from_host); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "unavailable"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "show", "unavailable"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", rpid); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); switch_event_fire(&event); } } + + if (switch_event_create(&event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host); + switch_event_fire(&event); + } + if (regtype == REG_REGISTER) { nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(contact), NUTAG_WITH_THIS(nua), @@ -2920,9 +2915,9 @@ static int sub_reg_callback(void *pArg, int argc, char **argv, char **columnName switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", from); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", status); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "show", status); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe"); switch_event_fire(&event); } @@ -2935,30 +2930,31 @@ static int sub_callback(void *pArg, int argc, char **argv, char **columnNames) char *pl; char *id, *note; uint32_t in = atoi(argv[0]); - char *msg = argv[1]; - char *proto = argv[2]; - char *user = argv[3]; - char *host = argv[4]; - char *sub_to_user = argv[5]; - char *sub_to_host = argv[6]; - char *event = argv[7]; - char *contact = argv[8]; - char *callid = argv[9]; - char *full_from = argv[10]; - char *full_via = argv[11]; + char *status = argv[1]; + char *rpid = argv[2]; + char *proto = argv[3]; + char *user = argv[4]; + char *host = argv[5]; + char *sub_to_user = argv[6]; + char *sub_to_host = argv[7]; + char *event = argv[8]; + char *contact = argv[9]; + char *callid = argv[10]; + char *full_from = argv[11]; + char *full_via = argv[12]; nua_handle_t *nh; - char *doing; char *to; char *open; + if (!rpid) { + rpid = "unknown"; + } if (in) { - note = switch_mprintf("%s", msg); - doing="available"; + note = switch_mprintf("%s", status); open = "open"; } else { note = NULL; - doing="unavailable"; open = "closed"; } @@ -2984,9 +2980,8 @@ static int sub_callback(void *pArg, int argc, char **argv, char **columnNames) "\r\n" "\r\n" "\r\n" - "\r\n" "%s\r\n" - "", id, open, doing, note); + "", id, open, rpid, note); nh = nua_handle(profile->nua, NULL, TAG_END()); @@ -3022,7 +3017,7 @@ static void sip_i_subscribe(int status, tagi_t tags[]) { if (sip) { - long exp; + long exp, exp_raw; sip_to_t const *to = sip->sip_to; sip_from_t const *from = sip->sip_from; sip_contact_t const *contact = sip->sip_contact; @@ -3040,7 +3035,7 @@ static void sip_i_subscribe(int status, char *full_via = NULL; switch_core_db_t *db; char *errmsg; - + char *sstr; if (from) { from_user = (char *) from->a_url->url_user; @@ -3094,9 +3089,9 @@ static void sip_i_subscribe(int status, full_from = sip_header_as_string(profile->home, (void *)sip->sip_from); full_via = sip_header_as_string(profile->home, (void *)sip->sip_via); - - exp = (long) time(NULL) + (sip->sip_expires ? sip->sip_expires->ex_delta : 60); - + exp_raw = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600); + exp = (long) time(NULL) + exp_raw; + if ((sql = switch_mprintf("delete from sip_subscriptions where " "proto='%q' and user='%q' and host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q';\n" @@ -3123,27 +3118,29 @@ static void sip_i_subscribe(int status, switch_safe_free(sql); } - + sstr = switch_mprintf("active;expires=%ld", exp_raw); + nua_respond(nh, SIP_202_ACCEPTED, - SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=3600"), + SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), SIPTAG_CONTACT_STR(to_str), TAG_END()); - + switch_safe_free(sstr); + if (!(db = switch_core_db_open_file(profile->dbname))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); goto end; } - if ((sql = switch_mprintf("select 'sip+%q@%q',status from sip_registrations where user='%q' and host='%q'", to_user, to_host, to_user, to_host))) { + if ((sql = switch_mprintf("select 'sip+%q@%q',status,rpid from sip_registrations where user='%q' and host='%q'", + to_user, to_host, to_user, to_host))) { switch_mutex_lock(profile->ireg_mutex); switch_core_db_exec(db, sql, sub_reg_callback, profile, &errmsg); switch_mutex_unlock(profile->ireg_mutex); - switch_core_db_close(db); switch_safe_free(sql); } - + switch_core_db_close(db); end: if (event) { @@ -3449,6 +3446,7 @@ static void sip_i_publish(nua_t *nua, sip_from_t const *from = sip->sip_from; char *from_user = NULL; char *from_host = NULL; + char *rpid = "unknown"; sip_payload_t *payload = sip->sip_payload; char *event_type; @@ -3458,7 +3456,7 @@ static void sip_i_publish(nua_t *nua, } if (payload) { - switch_xml_t xml, note, person, tuple, status, basic; + switch_xml_t xml, note, person, tuple, status, basic, act; switch_event_t *event; uint8_t in = 0; char *sql; @@ -3474,6 +3472,14 @@ static void sip_i_publish(nua_t *nua, note_txt = note->txt; } + if (person && (act = switch_xml_child(person, "rpid:activities"))) { + if ((rpid = strchr(act->child->name, ':'))) { + rpid++; + } else { + rpid = act->child->name; + } + } + if (!strcasecmp(status_txt, "open")) { if (switch_strlen_zero(note_txt)) { note_txt = "Available"; @@ -3485,7 +3491,8 @@ static void sip_i_publish(nua_t *nua, } } - if ((sql = switch_mprintf("update sip_registrations set status='%q' where user='%q' and host='%q'", note_txt, from_user, from_host))) { + if ((sql = switch_mprintf("update sip_registrations set status='%q',rpid='%q' where user='%q' and host='%q'", + note_txt, rpid, from_user, from_host))) { execute_sql(profile->dbname, sql, profile->ireg_mutex); switch_safe_free(sql); } @@ -3495,17 +3502,18 @@ static void sip_i_publish(nua_t *nua, if (in) { if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_NAME, from_user, from_host); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", note_txt); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "show", "%s", status_txt); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type); switch_event_fire(&event); } } else { if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_NAME, from_user, from_host); @@ -3630,7 +3638,8 @@ static void sip_i_invite(nua_t *nua, switch_channel_set_variable(channel, "endpoint_disposition", "INBOUND CALL"); set_chat_hash(tech_pvt, sip); - + switch_channel_set_variable(channel, "sip_fromuser", (char *) from->a_url->url_user); + switch_channel_set_variable(channel, "sip_fromhost", (char *) from->a_url->url_host); if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), (char *) from->a_url->url_user, profile->dialplan, @@ -3840,10 +3849,12 @@ static void event_callback(nua_event_t event, tech_pvt = switch_core_session_get_private(session); } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d][%s] session: %s\n", - nua_event_name (event), status, phrase, - session ? switch_channel_get_name(switch_core_session_get_channel(session)) : "n/a" - ); + if (status != 100 && status != 200) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d][%s] session: %s\n", + nua_event_name (event), status, phrase, + session ? switch_channel_get_name(switch_core_session_get_channel(session)) : "n/a" + ); + } if ((profile->pflags & PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) { sip_authorization_t const *authorization = NULL; @@ -3982,6 +3993,7 @@ static void event_callback(nua_event_t event, case nua_i_active: case nua_i_ack: case nua_i_terminated: + case nua_r_set_params: break; default: @@ -4144,24 +4156,17 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void switch_event_fire(&s_event); } - if (profile->pflags & PFLAG_PRESENCE) { - if (!(profile->presence = switch_core_alloc(profile->pool, sizeof(*profile->presence)))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); - return NULL; - } - - profile->presence->nh = nua_handle(profile->nua, NULL, SIPTAG_CONTACT_STR(profile->url), TAG_END()); - - profile->presence->sofia_private.presence = profile->presence; - nua_handle_bind(profile->presence->nh, &profile->presence->sofia_private); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Creating presence for %s\n", profile->url); - } switch_mutex_lock(globals.hash_mutex); switch_core_hash_insert(globals.profile_hash, profile->name, profile); switch_mutex_unlock(globals.hash_mutex); + if (profile->pflags & PFLAG_PRESENCE) { + if (switch_event_create(&s_event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_NAME); + switch_event_fire(&s_event); + } + } while(globals.running == 1) { if (++ireg_loops >= IREG_SECONDS) { @@ -4491,11 +4496,16 @@ static void event_handler(switch_event_t *event) char *from_host = switch_event_get_header(event, "orig-from-host"); char *contact_str = switch_event_get_header(event, "orig-contact"); char *exp_str = switch_event_get_header(event, "orig-expires"); + char *rpid = switch_event_get_header(event, "orig-rpid"); long expires = (long)time(NULL) + atol(exp_str); char *profile_name = switch_event_get_header(event, "orig-profile-name"); sofia_profile_t *profile; char buf[512]; + if (!rpid) { + rpid = "unknown"; + } + if (!profile_name || !(profile = (sofia_profile_t *) switch_core_hash_find(globals.profile_hash, profile_name))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n"); return; @@ -4503,17 +4513,19 @@ static void event_handler(switch_event_t *event) if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) { - sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Regestered', %ld)", - from_user, - from_host, - contact_str, - expires); + sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Regestered', '%q', %ld)", + from_user, + from_host, + contact_str, + rpid, + expires); } else { - sql = switch_mprintf("update sip_registrations set contact='%q', expires=%ld where user='%q' and host='%q'", - contact_str, - expires, - from_user, - from_host); + sql = switch_mprintf("update sip_registrations set contact='%q', rpid='%q', expires=%ld where user='%q' and host='%q'", + contact_str, + rpid, + expires, + from_user, + from_host); } @@ -4603,7 +4615,7 @@ static void cancel_presence(void) switch_hash_index_t *hi; void *val; - if ((sql = switch_mprintf("select 0,'%q',* from sip_subscriptions where event='presence'"))) { + if ((sql = switch_mprintf("select 0,'unavailable','unavailable',* from sip_subscriptions where event='presence'"))) { for (hi = switch_hash_first(apr_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, NULL, NULL, &val); profile = (sofia_profile_t *) val; @@ -4625,24 +4637,82 @@ static void cancel_presence(void) } + +static char *translate_rpid(char *in, char *ext) +{ + char *r = NULL; + + if (in && (strstr(in, "null") || strstr(in, "NULL"))) { + in = NULL; + } + + if (!in) { + in = ext; + } + + if (!in) { + return NULL; + } + + if (!strcasecmp(in, "dnd")) { + r = "busy"; + } + + if (ext && !strcasecmp(ext, "away")) { + r = "idle"; + } + + return r; +} + static void pres_event_handler(switch_event_t *event) { sofia_profile_t *profile; switch_hash_index_t *hi; void *val; char *from = switch_event_get_header(event, "from"); + char *rpid = switch_event_get_header(event, "rpid"); char *status= switch_event_get_header(event, "status"); - char *show= switch_event_get_header(event, "show"); char *event_type = switch_event_get_header(event, "event_type"); - char *sql = NULL; - char *user = NULL, *host = NULL; + char *sql = NULL, *sql2 = NULL; + char *euser = NULL, *user = NULL, *host = NULL; char *errmsg; char *resource; switch_core_db_t *db; + if (rpid && !strcasecmp(rpid, "n/a")) { + rpid = NULL; + } + + if (status && !strcasecmp(status, "n/a")) { + status = NULL; + } + + if (rpid) { + rpid = translate_rpid(rpid, status); + } + + if (!status) { + status = "Available"; + + if (rpid) { + if (!strcasecmp(rpid, "busy")) { + status = "Busy"; + } else if (!strcasecmp(rpid, "unavailable")) { + status = "Idle"; + } else if (!strcasecmp(rpid, "away")) { + status = "Idle"; + } + } + } if (event->event_id == SWITCH_EVENT_ROSTER) { - sql = switch_mprintf("select 1,'%q',* from sip_subscriptions where event='presence'", status ? status : "Available"); + + if (from) { + sql = switch_mprintf("select 1,'%q',%q',* from sip_subscriptions where event='presence' and full_from like '%%%q%%'", status, rpid, from); + } else { + sql = switch_mprintf("select 1,'%q',%q',* from sip_subscriptions where event='presence'", status, rpid); + } for (hi = switch_hash_first(apr_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, NULL, NULL, &val); @@ -4667,13 +4737,6 @@ static void pres_event_handler(switch_event_t *event) return; } - if (status && !strcasecmp(status, "n/a")) { - status = show; - if (status && !strcasecmp(status, "n/a")) { - status = NULL; - } - } - if (switch_strlen_zero(event_type)) { event_type="presence"; } @@ -4685,6 +4748,11 @@ static void pres_event_handler(switch_event_t *event) if ((resource = strchr(host, '/'))) { *resource++ = '\0'; } + if ((euser = strchr(user, '+'))) { + euser++; + } else { + euser = user; + } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); return; @@ -4701,19 +4769,12 @@ static void pres_event_handler(switch_event_t *event) switch(event->event_id) { case SWITCH_EVENT_PRESENCE_IN: - if (!status) { - status = "Available"; - } - - sql = switch_mprintf("select 1,'%q',* from sip_subscriptions where event='%q' and sub_to_user='%q' and sub_to_host='%q'", - status , event_type, user, host); + sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='%q' and sub_to_user='%q' and sub_to_host='%q'", + status , rpid, event_type, euser, host); break; case SWITCH_EVENT_PRESENCE_OUT: - if (!status) { - status = "Unavailable"; - } - sql = switch_mprintf("select 0,'%q',* from sip_subscriptions where event='%q' and sub_to_user='%q' and sub_to_host='%q'", - status, event_type, user, host); + sql = switch_mprintf("select 0,'%q','%q',* from sip_subscriptions where event='%q' and sub_to_user='%q' and sub_to_host='%q'", + status, rpid, event_type, euser, host); break; default: break; @@ -4734,18 +4795,19 @@ static void pres_event_handler(switch_event_t *event) switch_mutex_lock(profile->ireg_mutex); switch_core_db_exec(db, sql, sub_callback, profile, &errmsg); switch_mutex_unlock(profile->ireg_mutex); - switch_safe_free(sql); - - if ((sql = switch_mprintf("select 'sip+%q@%q',status from sip_registrations where user='%q' and host='%q'", user, host, user, host))) { + + + if ((sql2 = switch_mprintf("select 'sip+%q@%q',status,rpid from sip_registrations where user='%q' and host='%q'", euser, host, user, host))) { switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sub_reg_callback, profile, &errmsg); + switch_core_db_exec(db, sql2, sub_reg_callback, profile, &errmsg); switch_mutex_unlock(profile->ireg_mutex); - switch_core_db_close(db); - switch_safe_free(sql); + switch_safe_free(sql2); } + switch_core_db_close(db); } } + switch_safe_free(sql); switch_safe_free(user); }