From 55282e063dacfa041083d878c69c7d37b0e36ed7 Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 5 Aug 2013 21:20:07 +0100 Subject: [PATCH 1/4] Handle when servers dont send status 101 or jid for MUC nick changes --- src/muc.c | 16 +++++++++++- src/muc.h | 3 ++- src/xmpp/presence.c | 8 +++--- src/xmpp/stanza.c | 59 ++++++++++++++++++++++++++++++++++++++------- src/xmpp/stanza.h | 2 +- 5 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/muc.c b/src/muc.c index 464d3e1b..89391ddd 100644 --- a/src/muc.c +++ b/src/muc.c @@ -167,17 +167,30 @@ muc_room_is_active(Jid *jid) } } +char * +muc_get_old_nick(const char * const room, const char * const new_nick) +{ + ChatRoom *chat_room = g_hash_table_lookup(rooms, room); + + if ((chat_room != NULL) && (chat_room->pending_nick_change)) { + return g_hash_table_lookup(chat_room->nick_changes, new_nick); + } + + return NULL; +} + /* * Flag that the user has sent a nick change to the service * and is awaiting the response */ void -muc_set_room_pending_nick_change(const char * const room) +muc_set_room_pending_nick_change(const char * const room, const char * const new_nick) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room != NULL) { chat_room->pending_nick_change = TRUE; + g_hash_table_insert(chat_room->nick_changes, strdup(new_nick), strdup(chat_room->nick)); } } @@ -210,6 +223,7 @@ muc_complete_room_nick_change(const char * const room, const char * const nick) free(chat_room->nick); chat_room->nick = strdup(nick); chat_room->pending_nick_change = FALSE; + g_hash_table_remove(chat_room->nick_changes, nick); } } diff --git a/src/muc.h b/src/muc.h index b0458378..3d12452e 100644 --- a/src/muc.h +++ b/src/muc.h @@ -36,10 +36,11 @@ gboolean muc_room_is_active(Jid *jid); GList* muc_get_active_room_list(void); char * muc_get_room_nick(const char * const room); -void muc_set_room_pending_nick_change(const char * const room); +void muc_set_room_pending_nick_change(const char * const room, const char * const new_nick); gboolean muc_is_room_pending_nick_change(const char * const room); void muc_complete_room_nick_change(const char * const room, const char * const nick); +char * muc_get_old_nick(const char * const room, const char * const new_nick); gboolean muc_add_to_roster(const char * const room, const char * const nick, const char * const show, const char * const status, diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index f072196d..63462a56 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -567,13 +567,13 @@ _room_presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, // handle self presence if (stanza_is_muc_self_presence(stanza, jabber_get_fulljid())) { char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); - gboolean nick_change = stanza_is_room_nick_change(stanza); + char *new_nick = stanza_is_room_nick_change(stanza); if ((type != NULL) && (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0)) { // leave room if not self nick change - if (nick_change) { - muc_set_room_pending_nick_change(room); + if (new_nick != NULL) { + muc_set_room_pending_nick_change(room, new_nick); } else { prof_handle_leave_room(room); } @@ -606,7 +606,7 @@ _room_presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, if ((type != NULL) && (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0)) { // handle nickname change - if (stanza_is_room_nick_change(stanza)) { + if (stanza_is_room_nick_change(stanza) != NULL) { char *new_nick = stanza_get_new_nick(stanza); muc_set_roster_pending_nick_change(room, new_nick, nick); } else { diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 2e2f9858..c03aa398 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -31,6 +31,8 @@ #include "xmpp/stanza.h" #include "xmpp/capabilities.h" +#include "muc.h" + static int _field_compare(FormField *f1, FormField *f2); xmpp_stanza_t * @@ -508,50 +510,89 @@ stanza_is_muc_self_presence(xmpp_stanza_t * const stanza, x_children = xmpp_stanza_get_next(x_children); } + // for servers that don't send status 110 or Jid property + char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); + if (from != NULL) { + Jid *jidp = jid_create(from); + if (muc_room_is_active(jidp)) { + char *nick = muc_get_room_nick(jidp->barejid); + if (nick != NULL) { + if (strcmp(jidp->resourcepart, nick) == 0) { + return TRUE; + } else if (muc_is_room_pending_nick_change(jidp->barejid)) { + char *new_nick = jidp->resourcepart; + if (new_nick != NULL) { + char *old_nick = muc_get_old_nick(jidp->barejid, new_nick); + if (old_nick != NULL) { + if (strcmp(old_nick, nick) == 0) { + return TRUE; + } + } + } + } + } + } + } + return FALSE; } -gboolean +char * stanza_is_room_nick_change(xmpp_stanza_t * const stanza) { if (stanza == NULL) { - return FALSE; + return NULL; } if (strcmp(xmpp_stanza_get_name(stanza), STANZA_NAME_PRESENCE) != 0) { - return FALSE; + return NULL; } xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); if (x == NULL) { - return FALSE; + return NULL; } char *ns = xmpp_stanza_get_ns(x); if (ns == NULL) { - return FALSE; + return NULL; } if (strcmp(ns, STANZA_NS_MUC_USER) != 0) { - return FALSE; + return NULL; } xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); if (x_children == NULL) { - return FALSE; + return NULL; } + gboolean is_nick_change = FALSE; while (x_children != NULL) { if (strcmp(xmpp_stanza_get_name(x_children), STANZA_NAME_STATUS) == 0) { char *code = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_CODE); if (strcmp(code, "303") == 0) { - return TRUE; + is_nick_change = TRUE; + break; } } x_children = xmpp_stanza_get_next(x_children); } - return FALSE; + if (is_nick_change) { + xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); + while (x_children != NULL) { + if (strcmp(xmpp_stanza_get_name(x_children), STANZA_NAME_ITEM) == 0) { + char *new_nick = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_NICK); + if (new_nick != NULL) { + return new_nick; + } + } + x_children = xmpp_stanza_get_next(x_children); + } + } + + return NULL; } char * diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index ad777f24..50b14c75 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -146,7 +146,7 @@ gboolean stanza_get_delay(xmpp_stanza_t * const stanza, GTimeVal *tv_stamp); gboolean stanza_is_muc_presence(xmpp_stanza_t * const stanza); gboolean stanza_is_muc_self_presence(xmpp_stanza_t * const stanza, const char * const self_jid); -gboolean stanza_is_room_nick_change(xmpp_stanza_t * const stanza); +char * stanza_is_room_nick_change(xmpp_stanza_t * const stanza); char * stanza_get_new_nick(xmpp_stanza_t * const stanza); From 1525be613303e0682a6fb78c5457d53207b05936 Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 5 Aug 2013 22:55:11 +0100 Subject: [PATCH 2/4] Refactor MUC self presence checks --- src/xmpp/stanza.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index c03aa398..f4259d6f 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -511,24 +511,30 @@ stanza_is_muc_self_presence(xmpp_stanza_t * const stanza, } // for servers that don't send status 110 or Jid property + + // first check if 'from' attribute identifies this user char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (from != NULL) { Jid *jidp = jid_create(from); if (muc_room_is_active(jidp)) { char *nick = muc_get_room_nick(jidp->barejid); - if (nick != NULL) { - if (strcmp(jidp->resourcepart, nick) == 0) { + if (g_strcmp0(jidp->resourcepart, nick) == 0) { + return TRUE; + } + } + jid_destroy(jidp); + } + + // secondly check if the new nickname maps to a pending nick change for this user + if (from != NULL) { + Jid *jidp = jid_create(from); + if (muc_is_room_pending_nick_change(jidp->barejid)) { + char *new_nick = jidp->resourcepart; + if (new_nick != NULL) { + char *nick = muc_get_room_nick(jidp->barejid); + char *old_nick = muc_get_old_nick(jidp->barejid, new_nick); + if (g_strcmp0(old_nick, nick) == 0) { return TRUE; - } else if (muc_is_room_pending_nick_change(jidp->barejid)) { - char *new_nick = jidp->resourcepart; - if (new_nick != NULL) { - char *old_nick = muc_get_old_nick(jidp->barejid, new_nick); - if (old_nick != NULL) { - if (strcmp(old_nick, nick) == 0) { - return TRUE; - } - } - } } } } From c6e9a7455d1aa34c0b8386c8e6bc8f855cb29a2a Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 5 Aug 2013 23:08:30 +0100 Subject: [PATCH 3/4] Undo change to stanza check for nick change return value --- src/xmpp/presence.c | 4 ++-- src/xmpp/stanza.c | 34 +++++++++------------------------- src/xmpp/stanza.h | 2 +- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index 63462a56..c05ba198 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -567,7 +567,7 @@ _room_presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, // handle self presence if (stanza_is_muc_self_presence(stanza, jabber_get_fulljid())) { char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); - char *new_nick = stanza_is_room_nick_change(stanza); + char *new_nick = stanza_get_new_nick(stanza); if ((type != NULL) && (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0)) { @@ -606,7 +606,7 @@ _room_presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, if ((type != NULL) && (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0)) { // handle nickname change - if (stanza_is_room_nick_change(stanza) != NULL) { + if (stanza_is_room_nick_change(stanza)) { char *new_nick = stanza_get_new_nick(stanza); muc_set_roster_pending_nick_change(room, new_nick, nick); } else { diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index f4259d6f..4d232b7b 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -543,62 +543,46 @@ stanza_is_muc_self_presence(xmpp_stanza_t * const stanza, return FALSE; } -char * +gboolean stanza_is_room_nick_change(xmpp_stanza_t * const stanza) { if (stanza == NULL) { - return NULL; + return FALSE; } if (strcmp(xmpp_stanza_get_name(stanza), STANZA_NAME_PRESENCE) != 0) { - return NULL; + return FALSE; } xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); if (x == NULL) { - return NULL; + return FALSE; } char *ns = xmpp_stanza_get_ns(x); if (ns == NULL) { - return NULL; + return FALSE; } if (strcmp(ns, STANZA_NS_MUC_USER) != 0) { - return NULL; + return FALSE; } xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); if (x_children == NULL) { - return NULL; + return FALSE; } - gboolean is_nick_change = FALSE; while (x_children != NULL) { if (strcmp(xmpp_stanza_get_name(x_children), STANZA_NAME_STATUS) == 0) { char *code = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_CODE); if (strcmp(code, "303") == 0) { - is_nick_change = TRUE; - break; + return TRUE; } } x_children = xmpp_stanza_get_next(x_children); } - if (is_nick_change) { - xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); - while (x_children != NULL) { - if (strcmp(xmpp_stanza_get_name(x_children), STANZA_NAME_ITEM) == 0) { - char *new_nick = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_NICK); - if (new_nick != NULL) { - return new_nick; - } - } - - x_children = xmpp_stanza_get_next(x_children); - } - } - - return NULL; + return FALSE; } char * diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 50b14c75..ad777f24 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -146,7 +146,7 @@ gboolean stanza_get_delay(xmpp_stanza_t * const stanza, GTimeVal *tv_stamp); gboolean stanza_is_muc_presence(xmpp_stanza_t * const stanza); gboolean stanza_is_muc_self_presence(xmpp_stanza_t * const stanza, const char * const self_jid); -char * stanza_is_room_nick_change(xmpp_stanza_t * const stanza); +gboolean stanza_is_room_nick_change(xmpp_stanza_t * const stanza); char * stanza_get_new_nick(xmpp_stanza_t * const stanza); From 42eef398b4eb4d311dd97037af715d4d4119adf4 Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 5 Aug 2013 23:12:10 +0100 Subject: [PATCH 4/4] Free Jid --- src/xmpp/stanza.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 4d232b7b..e470c3b0 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -538,6 +538,7 @@ stanza_is_muc_self_presence(xmpp_stanza_t * const stanza, } } } + jid_destroy(jidp); } return FALSE;