diff --git a/src/jabber.c b/src/jabber.c index a9dc5709..8d71c51d 100644 --- a/src/jabber.c +++ b/src/jabber.c @@ -39,8 +39,6 @@ #include "muc.h" #include "stanza.h" -#include "ui.h" - static struct _jabber_conn_t { xmpp_log_t *log; xmpp_ctx_t *ctx; @@ -93,6 +91,7 @@ static int _disco_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza static int _presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata); +static char * _handle_presence_caps(xmpp_stanza_t * const stanza); void jabber_init(const int disable_tls) @@ -1063,34 +1062,37 @@ _disco_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *type = xmpp_stanza_get_type(stanza); + char *id = xmpp_stanza_get_id(stanza); if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { log_error("Roster query failed"); return 1; } else { xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); - const char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); - + char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); if (node == NULL) { return 1; } - // validate sha1 - gchar **split = g_strsplit(node, "#", -1); - char *given_sha1 = split[1]; - char *generated_sha1 = sha1_caps_str(query); - cons_show("GIVEN: %s", given_sha1); - cons_show("GEN : %s", generated_sha1); - win_current_page_off(); - ui_refresh(); + char *caps_key = NULL; + if (g_strcmp0(id, "disco") == 0) { + caps_key = node; - if (g_strcmp0(given_sha1, generated_sha1) != 0) { - log_info("Invalid SHA1 recieved for caps."); - return 1; + // validate sha1 + gchar **split = g_strsplit(node, "#", -1); + char *given_sha1 = split[1]; + char *generated_sha1 = sha1_caps_str(query); + + if (g_strcmp0(given_sha1, generated_sha1) != 0) { + log_info("Invalid SHA1 recieved for caps."); + return 1; + } + } else { + caps_key = id; } // already cached - if (caps_contains(node)) { + if (caps_contains(caps_key)) { log_info("Client info already cached."); return 1; } @@ -1115,7 +1117,7 @@ _disco_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, return 1; } - caps_add(node, name); + caps_add(caps_key, name); return 1; } @@ -1175,19 +1177,7 @@ _room_presence_handler(const char * const jid, xmpp_stanza_t * const stanza) } else { char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); char *show_str, *status_str; - char *caps_str = NULL; - - if (stanza_contains_caps(stanza)) { - caps_str = stanza_get_caps_str(stanza); - - if (caps_str != NULL) { - if (!caps_contains(caps_str)) { - xmpp_stanza_t *iq = stanza_create_disco_iq(jabber_conn.ctx, jid, caps_str); - xmpp_send(jabber_conn.conn, iq); - xmpp_stanza_release(iq); - } - } - } + char *caps_key = _handle_presence_caps(stanza); xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_STATUS); if (status != NULL) { @@ -1213,18 +1203,18 @@ _room_presence_handler(const char * const jid, xmpp_stanza_t * const stanza) show_str = "online"; } if (!muc_get_roster_received(room)) { - muc_add_to_roster(room, nick, show_str, status_str, caps_str); + muc_add_to_roster(room, nick, show_str, status_str, caps_key); } else { char *old_nick = muc_complete_roster_nick_change(room, nick); if (old_nick != NULL) { - muc_add_to_roster(room, nick, show_str, status_str, caps_str); + muc_add_to_roster(room, nick, show_str, status_str, caps_key); prof_handle_room_member_nick_change(room, old_nick, nick); } else { if (!muc_nick_in_roster(room, nick)) { - prof_handle_room_member_online(room, nick, show_str, status_str, caps_str); + prof_handle_room_member_online(room, nick, show_str, status_str, caps_key); } else { - prof_handle_room_member_presence(room, nick, show_str, status_str, caps_str); + prof_handle_room_member_presence(room, nick, show_str, status_str, caps_key); } } } @@ -1237,6 +1227,55 @@ _room_presence_handler(const char * const jid, xmpp_stanza_t * const stanza) return 1; } +static char * +_handle_presence_caps(xmpp_stanza_t * const stanza) +{ + char *caps_key = NULL; + char *node = NULL; + char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); + if (stanza_contains_caps(stanza)) { + char *hash_type = stanza_caps_get_hash(stanza); + + // xep-0115 + if (hash_type != NULL) { + + // supported hash + if (strcmp(hash_type, "sha-1") == 0) { + node = stanza_get_caps_str(stanza); + caps_key = node; + + if (node != NULL) { + if (!caps_contains(caps_key)) { + xmpp_stanza_t *iq = stanza_create_disco_iq(jabber_conn.ctx, "disco", from, node); + xmpp_send(jabber_conn.conn, iq); + xmpp_stanza_release(iq); + } + } + + // unsupported hash + } else { + node = stanza_get_caps_str(stanza); + caps_key = from; + + if (node != NULL) { + if (!caps_contains(caps_key)) { + xmpp_stanza_t *iq = stanza_create_disco_iq(jabber_conn.ctx, from, from, node); + xmpp_send(jabber_conn.conn, iq); + xmpp_stanza_release(iq); + } + } + } + + return strdup(caps_key); + + //ignore or handle legacy caps + } else { + return NULL; + } + } + return NULL; +} + static int _presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) @@ -1269,18 +1308,7 @@ _presence_handler(xmpp_conn_t * const conn, g_date_time_unref(now); } - char *caps_str = NULL; - if (stanza_contains_caps(stanza)) { - caps_str = stanza_get_caps_str(stanza); - - if (caps_str != NULL) { - if (!caps_contains(caps_str)) { - xmpp_stanza_t *iq = stanza_create_disco_iq(jabber_conn.ctx, from, caps_str); - xmpp_send(jabber_conn.conn, iq); - xmpp_stanza_release(iq); - } - } - } + char *caps_key = _handle_presence_caps(stanza); xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_STATUS); if (status != NULL) @@ -1296,7 +1324,7 @@ _presence_handler(xmpp_conn_t * const conn, show_str = "online"; if (strcmp(my_jid->barejid, from_jid->barejid) !=0) { - prof_handle_contact_online(from_jid->barejid, show_str, status_str, last_activity, caps_str); + prof_handle_contact_online(from_jid->barejid, show_str, status_str, last_activity, caps_key); } } else if (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0) { if (strcmp(my_jid->barejid, from_jid->barejid) !=0) { diff --git a/src/stanza.c b/src/stanza.c index 3abc0abd..4274ed22 100644 --- a/src/stanza.c +++ b/src/stanza.c @@ -181,14 +181,14 @@ stanza_create_roster_iq(xmpp_ctx_t *ctx) } xmpp_stanza_t * -stanza_create_disco_iq(xmpp_ctx_t *ctx, const char * const to, +stanza_create_disco_iq(xmpp_ctx_t *ctx, const char * const id, const char * const to, const char * const node) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, to); - xmpp_stanza_set_id(iq, "disco"); + xmpp_stanza_set_id(iq, id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); @@ -431,6 +431,25 @@ stanza_contains_caps(xmpp_stanza_t * const stanza) return TRUE; } +char * +stanza_caps_get_hash(xmpp_stanza_t * const stanza) +{ + xmpp_stanza_t *caps = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_C); + + if (caps == NULL) { + return NULL; + } + + if (strcmp(xmpp_stanza_get_ns(caps), STANZA_NS_CAPS) != 0) { + return NULL; + } + + char *result = xmpp_stanza_get_attribute(caps, STANZA_ATTR_HASH); + + return result; + +} + char * stanza_get_caps_str(xmpp_stanza_t * const stanza) { diff --git a/src/stanza.h b/src/stanza.h index 4e8d52be..a61f4639 100644 --- a/src/stanza.h +++ b/src/stanza.h @@ -77,6 +77,7 @@ #define STANZA_ATTR_SECONDS "seconds" #define STANZA_ATTR_NODE "node" #define STANZA_ATTR_VER "ver" +#define STANZA_ATTR_HASH "hash" #define STANZA_TEXT_AWAY "away" #define STANZA_TEXT_DND "dnd" @@ -123,8 +124,8 @@ xmpp_stanza_t* stanza_create_presence(xmpp_ctx_t *ctx, const char * const show, xmpp_stanza_t* stanza_create_roster_iq(xmpp_ctx_t *ctx); xmpp_stanza_t* stanza_create_ping_iq(xmpp_ctx_t *ctx); -xmpp_stanza_t* stanza_create_disco_iq(xmpp_ctx_t *ctx, const char * const to, - const char * const node); +xmpp_stanza_t* stanza_create_disco_iq(xmpp_ctx_t *ctx, const char * const id, + const char * const to, const char * const node); gboolean stanza_contains_chat_state(xmpp_stanza_t *stanza); @@ -139,6 +140,7 @@ char * stanza_get_new_nick(xmpp_stanza_t * const stanza); int stanza_get_idle_time(xmpp_stanza_t * const stanza); char * stanza_get_caps_str(xmpp_stanza_t * const stanza); gboolean stanza_contains_caps(xmpp_stanza_t * const stanza); +char * stanza_caps_get_hash(xmpp_stanza_t * const stanza); DataForm * stanza_get_form(xmpp_stanza_t * const stanza);