From 3a32d9e53cdccb7d27290ab073755b67a8a1b4ee Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 20 Oct 2006 06:17:00 +0000 Subject: [PATCH] Presence and Chat Gateway Code This is some brand new stuff to gateway chat/presence/audio from one protocol to another So far it only works between google/jingle and SIP All I had to test the SIP end was X-Lite and Eyebeam and GoogleTalk on the jingle end. With this setup registered X-Lite's can chat with each other and call each other as well as X-Lite to GoogleTalk and GoogleTalk to X-Lite audio calls. Chat May also be done between X-Lite and jabber You'll also need a jabber server configured for component login so you can interface. We have only tested with jabberd2 so far. Configure DNS so srv records for jabber for your subdomain (fs.mydomain.com in the example) so the jabber records are pointed at your jabber server. RELEVANT CONFIGS git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3115 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- conf/freeswitch.xml | 34 +- libs/libdingaling/src/libdingaling.c | 41 +- libs/libdingaling/src/libdingaling.h | 3 +- .../mod_dialplan_xml/mod_dialplan_xml.c | 5 + .../endpoints/mod_dingaling/mod_dingaling.c | 165 +++++--- src/mod/endpoints/mod_sofia/mod_sofia.c | 352 ++++++++++-------- 6 files changed, 382 insertions(+), 218 deletions(-) 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); }