about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2014-10-05 20:52:34 +0100
committerJames Booth <boothj5@gmail.com>2014-10-05 20:52:34 +0100
commitd12534c58e5c466d2b9443e196df151205c2b879 (patch)
tree330aa0b7a7a749552b4a99d11edccc6c3059e9f8
parentac7bc02c63a5aed8decfcbbdc5582e9e5b389030 (diff)
downloadprofani-tty-d12534c58e5c466d2b9443e196df151205c2b879.tar.gz
Implemented /room kick command
-rw-r--r--src/server_events.c33
-rw-r--r--src/server_events.h6
-rw-r--r--src/ui/core.c117
-rw-r--r--src/ui/ui.h10
-rw-r--r--src/xmpp/iq.c1
-rw-r--r--src/xmpp/presence.c39
-rw-r--r--src/xmpp/stanza.c150
-rw-r--r--src/xmpp/stanza.h9
8 files changed, 334 insertions, 31 deletions
diff --git a/src/server_events.c b/src/server_events.c
index f920e1a9..0bb017b8 100644
--- a/src/server_events.c
+++ b/src/server_events.c
@@ -490,6 +490,7 @@ void
 handle_leave_room(const char * const room)
 {
     muc_leave(room);
+    ui_leave_room(room);
 }
 
 void
@@ -511,7 +512,22 @@ void
 handle_room_destroy(const char * const room)
 {
     muc_leave(room);
-    ui_room_destroyed(room);
+    ui_room_destroy(room);
+}
+
+void
+handle_room_destroyed(const char * const room, const char * const new_jid, const char * const password,
+    const char * const reason)
+{
+    muc_leave(room);
+    ui_room_destroyed(room, reason, new_jid, password);
+}
+
+void
+handle_room_kicked(const char * const room, const char * const actor, const char * const reason)
+{
+    muc_leave(room);
+    ui_room_kicked(room, actor, reason);
 }
 
 void
@@ -539,12 +555,6 @@ handle_room_config_submit_result_error(const char * const room, const char * con
 }
 
 void
-handle_room_kick(const char * const room, const char * const nick)
-{
-    ui_handle_room_kick(room, nick);
-}
-
-void
 handle_room_kick_result_error(const char * const room, const char * const nick, const char * const error)
 {
     ui_handle_room_kick_error(room, nick, error);
@@ -620,6 +630,15 @@ handle_room_member_offline(const char * const room, const char * const nick,
 }
 
 void
+handle_room_occupent_kicked(const char * const room, const char * const nick, const char * const actor,
+    const char * const reason)
+{
+    muc_roster_remove(room, nick);
+    ui_room_member_kicked(room, nick, actor, reason);
+}
+
+
+void
 handle_room_member_nick_change(const char * const room,
     const char * const old_nick, const char * const nick)
 {
diff --git a/src/server_events.h b/src/server_events.h
index 7e70e833..92988bd9 100644
--- a/src/server_events.h
+++ b/src/server_events.h
@@ -65,7 +65,6 @@ void handle_room_affiliation_list(const char * const room, const char * const af
 void handle_room_affiliation_set_error(const char * const room, const char * const jid, const char * const affiliation,
     const char * const error);
 void handle_room_affiliation_set(const char * const room, const char * const jid, const char * const affiliation);
-void handle_room_kick(const char * const room, const char * const nick);
 void handle_room_kick_result_error(const char * const room, const char * const nick, const char * const error);
 void handle_duck_result(const char * const result);
 void handle_incoming_message(char *from, char *message, gboolean priv);
@@ -91,6 +90,11 @@ void handle_room_member_offline(const char * const room, const char * const nick
     const char * const show, const char * const status);
 void handle_room_member_nick_change(const char * const room,
     const char * const old_nick, const char * const nick);
+void handle_room_destroyed(const char * const room, const char * const new_jid, const char * const password,
+    const char * const reason);
+void handle_room_kicked(const char * const room, const char * const actor, const char * const reason);
+void handle_room_occupent_kicked(const char * const room, const char * const nick, const char * const actor,
+    const char * const reason);
 void handle_group_add(const char * const contact,
     const char * const group);
 void handle_group_remove(const char * const contact,
diff --git a/src/ui/core.c b/src/ui/core.c
index 620d08d8..a0712142 100644
--- a/src/ui/core.c
+++ b/src/ui/core.c
@@ -1494,6 +1494,31 @@ _ui_room_member_offline(const char * const room, const char * const nick)
 }
 
 static void
+_ui_room_member_kicked(const char * const room, const char * const nick, const char * const actor,
+    const char * const reason)
+{
+    ProfWin *window = wins_get_by_recipient(room);
+    if (window == NULL) {
+        log_error("Received kick for room participant %s, but no window open for %s.", nick, room);
+    } else {
+        GString *message = g_string_new(nick);
+        g_string_append(message, " has been kicked from the room");
+        if (actor) {
+            g_string_append(message, " by ");
+            g_string_append(message, actor);
+        }
+        if (reason) {
+            g_string_append(message, ", reason: ");
+            g_string_append(message, reason);
+        }
+
+        win_save_vprint(window, '!', NULL, 0, COLOUR_OFFLINE, "", "<- %s", message->str);
+        g_string_free(message, TRUE);
+    }
+}
+
+
+static void
 _ui_room_member_online(const char * const room, const char * const nick,
     const char * const show, const char * const status)
 {
@@ -1691,7 +1716,7 @@ _ui_room_requires_config(const char * const room_jid)
 }
 
 static void
-_ui_room_destroyed(const char * const room_jid)
+_ui_room_destroy(const char * const room_jid)
 {
     ProfWin *window = wins_get_by_recipient(room_jid);
     if (window == NULL) {
@@ -1704,6 +1729,71 @@ _ui_room_destroyed(const char * const room_jid)
 }
 
 static void
+_ui_leave_room(const char * const room)
+{
+    ProfWin *window = wins_get_by_recipient(room);
+    if (window) {
+        int num = wins_get_num(window);
+        ui_close_win(num);
+    }
+}
+
+static void
+_ui_room_destroyed(const char * const room, const char * const reason, const char * const new_jid,
+    const char * const password)
+{
+    ProfWin *window = wins_get_by_recipient(room);
+    if (window == NULL) {
+        log_error("Received room destroy, but no window open for %s.", room);
+    } else {
+        int num = wins_get_num(window);
+        ui_close_win(num);
+        ProfWin *console = wins_get_console();
+
+        if (reason) {
+            win_save_vprint(console, '!', NULL, 0, COLOUR_TYPING, "", "<- Room destroyed: %s, reason: %s", room, reason);
+        } else {
+            win_save_vprint(console, '!', NULL, 0, COLOUR_TYPING, "", "<- Room destroyed: %s", room);
+        }
+
+        if (new_jid) {
+            if (password) {
+                win_save_vprint(console, '!', NULL, 0, COLOUR_TYPING, "", "Replacement room: %s, password: %s", new_jid, password);
+            } else {
+                win_save_vprint(console, '!', NULL, 0, COLOUR_TYPING, "", "Replacement room: %s", new_jid);
+            }
+        }
+    }
+}
+
+static void
+_ui_room_kicked(const char * const room, const char * const actor, const char * const reason)
+{
+    ProfWin *window = wins_get_by_recipient(room);
+    if (window == NULL) {
+        log_error("Received kick, but no window open for %s.", room);
+    } else {
+        int num = wins_get_num(window);
+        ui_close_win(num);
+
+        GString *message = g_string_new("Kicked from ");
+        g_string_append(message, room);
+        if (actor) {
+            g_string_append(message, " by ");
+            g_string_append(message, actor);
+        }
+        if (reason) {
+            g_string_append(message, ", reason: ");
+            g_string_append(message, reason);
+        }
+
+        ProfWin *console = wins_get_console();
+        win_save_vprint(console, '!', NULL, 0, COLOUR_TYPING, "", "<- %s", message->str);
+        g_string_free(message, TRUE);
+    }
+}
+
+static void
 _ui_room_subject(const char * const room, const char * const nick, const char * const subject)
 {
     ProfWin *window = wins_get_by_recipient(room);
@@ -1751,17 +1841,6 @@ _ui_handle_room_kick_error(const char * const room, const char * const nick, con
 }
 
 static void
-_ui_handle_room_kick(const char * const room, const char * const nick)
-{
-    ProfWin *window = wins_get_by_recipient(room);
-    if (window == NULL) {
-        log_error("Kick result received for %s, but no window open for %s.", nick, room);
-    } else {
-        win_save_vprint(window, '!', NULL, 0, 0, "", "%s has been kicked from the room", nick);
-    }
-}
-
-static void
 _ui_room_broadcast(const char * const room_jid, const char * const message)
 {
     ProfWin *window = wins_get_by_recipient(room_jid);
@@ -2766,7 +2845,7 @@ ui_init_module(void)
     ui_swap_wins = _ui_swap_wins;
     ui_update = _ui_update;
     ui_room_requires_config = _ui_room_requires_config;
-    ui_room_destroyed = _ui_room_destroyed;
+    ui_room_destroy = _ui_room_destroy;
     ui_handle_room_configuration = _ui_handle_room_configuration;
     ui_handle_room_config_submit_result = _ui_handle_room_config_submit_result;
     ui_handle_room_config_submit_result_error = _ui_handle_room_config_submit_result_error;
@@ -2783,9 +2862,13 @@ ui_init_module(void)
     ui_handle_room_info_error = _ui_handle_room_info_error;
     ui_show_room_disco_info = _ui_show_room_disco_info;
     ui_handle_room_affiliation_list_error = _ui_handle_room_affiliation_list_error;
-    ui_handle_room_affiliation_list =_ui_handle_room_affiliation_list;
-    ui_handle_room_affiliation_set_error =_ui_handle_room_affiliation_set_error;
+    ui_handle_room_affiliation_list = _ui_handle_room_affiliation_list;
+    ui_handle_room_affiliation_set_error = _ui_handle_room_affiliation_set_error;
     ui_handle_room_affiliation_set = _ui_handle_room_affiliation_set;
-    ui_handle_room_kick_error =_ui_handle_room_kick_error;
-    ui_handle_room_kick = _ui_handle_room_kick;
+    ui_handle_room_kick_error = _ui_handle_room_kick_error;
+    ui_room_destroyed = _ui_room_destroyed;
+    ui_room_kicked = _ui_room_kicked;
+    ui_leave_room = _ui_leave_room;
+    ui_room_member_kicked = _ui_room_member_kicked;
 }
+
diff --git a/src/ui/ui.h b/src/ui/ui.h
index 7f958b11..dafcceac 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -135,13 +135,18 @@ void (*ui_room_message)(const char * const room_jid, const char * const nick,
     const char * const message);
 void (*ui_room_subject)(const char * const room, const char * const nick, const char * const subject);
 void (*ui_room_requires_config)(const char * const room_jid);
-void (*ui_room_destroyed)(const char * const room_jid);
+void (*ui_room_destroy)(const char * const room_jid);
 void (*ui_show_room_info)(ProfWin *window, const char * const room);
 void (*ui_show_room_role_list)(ProfWin *window, const char * const room, muc_role_t role);
 void (*ui_show_room_affiliation_list)(ProfWin *window, const char * const room, muc_affiliation_t affiliation);
 void (*ui_handle_room_info_error)(const char * const room, const char * const error);
 void (*ui_show_room_disco_info)(const char * const room, GSList *identities, GSList *features);
-
+void (*ui_room_destroyed)(const char * const room, const char * const reason, const char * const new_jid,
+    const char * const password);
+void (*ui_room_kicked)(const char * const room, const char * const actor, const char * const reason);
+void (*ui_room_member_kicked)(const char * const room, const char * const nick, const char * const actor,
+    const char * const reason);
+void (*ui_leave_room)(const char * const room);
 void (*ui_room_broadcast)(const char * const room_jid,
     const char * const message);
 void (*ui_room_member_offline)(const char * const room, const char * const nick);
@@ -176,7 +181,6 @@ void (*ui_handle_room_affiliation_set_error)(const char * const room, const char
     const char * const affiliation, const char * const error);
 void (*ui_handle_room_affiliation_set)(const char * const room, const char * const jid, const char * const affiliation);
 void (*ui_handle_room_kick_error)(const char * const room, const char * const nick, const char * const error);
-void (*ui_handle_room_kick)(const char * const room, const char * const nick);
 void (*ui_show_form)(ProfWin *window, const char * const room, DataForm *form);
 void (*ui_show_form_field)(ProfWin *window, DataForm *form, char *tag);
 void (*ui_show_form_help)(ProfWin *window, DataForm *form);
diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c
index 4be3d97f..c24e4ecc 100644
--- a/src/xmpp/iq.c
+++ b/src/xmpp/iq.c
@@ -960,7 +960,6 @@ _room_kick_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza
         return 0;
     }
 
-    handle_room_kick(from, nick);
     free(nick);
 
     return 0;
diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c
index be2d4a01..adc6fc06 100644
--- a/src/xmpp/presence.c
+++ b/src/xmpp/presence.c
@@ -704,7 +704,30 @@ _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
             if (new_nick != NULL) {
                 muc_nick_change_start(from_room, new_nick);
             } else {
-                handle_leave_room(from_room);
+                GSList *status_codes = stanza_get_status_codes_by_ns(stanza, STANZA_NS_MUC_USER);
+
+                // room destroyed
+                if (stanza_room_destroyed(stanza)) {
+                    char *new_jid = stanza_get_muc_destroy_alternative_room(stanza);
+                    char *password = stanza_get_muc_destroy_alternative_password(stanza);
+                    char *reason = stanza_get_muc_destroy_reason(stanza);
+                    handle_room_destroyed(from_room, new_jid, password, reason);
+                    free(password);
+                    free(reason);
+
+                // kicked from room
+                } else if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0) != NULL) {
+                    char *actor = stanza_get_kick_actor(stanza);
+                    char *reason = stanza_get_kick_reason(stanza);
+                    handle_room_kicked(from_room, actor, reason);
+                    free(reason);
+
+                // normal exit
+                } else {
+                    handle_leave_room(from_room);
+                }
+
+                g_slist_free(status_codes);
             }
 
         // self online
@@ -756,7 +779,19 @@ _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
                     free(new_nick);
                 }
             } else {
-                handle_room_member_offline(from_room, from_nick, "offline", status_str);
+                GSList *status_codes = stanza_get_status_codes_by_ns(stanza, STANZA_NS_MUC_USER);
+
+                // kicked from room
+                if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0) != NULL) {
+                    char *actor = stanza_get_kick_actor(stanza);
+                    char *reason = stanza_get_kick_reason(stanza);
+                    handle_room_occupent_kicked(from_room, from_nick, actor, reason);
+                    free(reason);
+
+                // normal exit
+                } else {
+                    handle_room_member_offline(from_room, from_nick, "offline", status_str);
+                }
             }
         } else {
             // send disco info for capabilities, if not cached
diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c
index eb5f857c..07e96659 100644
--- a/src/xmpp/stanza.c
+++ b/src/xmpp/stanza.c
@@ -1010,6 +1010,156 @@ stanza_is_muc_self_presence(xmpp_stanza_t * const stanza,
     return FALSE;
 }
 
+GSList *
+stanza_get_status_codes_by_ns(xmpp_stanza_t * const stanza, char *ns)
+{
+    GSList *codes = NULL;
+    xmpp_stanza_t *ns_child = xmpp_stanza_get_child_by_ns(stanza, ns);
+    if (ns_child) {
+        xmpp_stanza_t *child = xmpp_stanza_get_children(ns_child);
+        while (child) {
+            char *name = xmpp_stanza_get_name(child);
+            if (g_strcmp0(name, STANZA_NAME_STATUS) == 0) {
+                char *code = xmpp_stanza_get_attribute(child, STANZA_ATTR_CODE);
+                if (code) {
+                    codes = g_slist_append(codes, code);
+                }
+            }
+            child = xmpp_stanza_get_next(child);
+        }
+    }
+    return codes;
+}
+
+gboolean
+stanza_room_destroyed(xmpp_stanza_t *stanza)
+{
+    char *stanza_name = xmpp_stanza_get_name(stanza);
+    if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) {
+        xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER);
+        if (x) {
+            xmpp_stanza_t *destroy = xmpp_stanza_get_child_by_name(x, STANZA_NAME_DESTROY);
+            if (destroy) {
+                return TRUE;
+            }
+        }
+    }
+
+    return FALSE;
+}
+
+char *
+stanza_get_muc_destroy_alternative_room(xmpp_stanza_t *stanza)
+{
+    char *stanza_name = xmpp_stanza_get_name(stanza);
+    if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) {
+        xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER);
+        if (x) {
+            xmpp_stanza_t *destroy = xmpp_stanza_get_child_by_name(x, STANZA_NAME_DESTROY);
+            if (destroy) {
+                char *jid = xmpp_stanza_get_attribute(destroy, STANZA_ATTR_JID);
+                if (jid) {
+                    return jid;
+                }
+            }
+        }
+    }
+
+    return NULL;
+}
+
+char *
+stanza_get_muc_destroy_alternative_password(xmpp_stanza_t *stanza)
+{
+    char *stanza_name = xmpp_stanza_get_name(stanza);
+    if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) {
+        xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER);
+        if (x) {
+            xmpp_stanza_t *destroy = xmpp_stanza_get_child_by_name(x, STANZA_NAME_DESTROY);
+            if (destroy) {
+                xmpp_stanza_t *password_st = xmpp_stanza_get_child_by_name(destroy, STANZA_NAME_PASSWORD);
+                if (password_st) {
+                    char *password = xmpp_stanza_get_text(password_st);
+                    if (password) {
+                        return password;
+                    }
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+char *
+stanza_get_muc_destroy_reason(xmpp_stanza_t *stanza)
+{
+    char *stanza_name = xmpp_stanza_get_name(stanza);
+    if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) {
+        xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER);
+        if (x) {
+            xmpp_stanza_t *destroy = xmpp_stanza_get_child_by_name(x, STANZA_NAME_DESTROY);
+            if (destroy) {
+                xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(destroy, STANZA_NAME_REASON);
+                if (reason_st) {
+                    char *reason = xmpp_stanza_get_text(reason_st);
+                    if (reason) {
+                        return reason;
+                    }
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+char *
+stanza_get_kick_actor(xmpp_stanza_t *stanza)
+{
+    char *stanza_name = xmpp_stanza_get_name(stanza);
+    if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) {
+        xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER);
+        if (x) {
+            xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, STANZA_NAME_ITEM);
+            if (item) {
+                xmpp_stanza_t *actor = xmpp_stanza_get_child_by_name(item, STANZA_NAME_ACTOR);
+                if (actor) {
+                    char *nick = xmpp_stanza_get_attribute(actor, STANZA_ATTR_NICK);
+                    if (nick) {
+                        return nick;
+                    }
+                    char *jid = xmpp_stanza_get_attribute(actor, STANZA_ATTR_JID);
+                    if (jid) {
+                        return jid;
+                    }
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+char *
+stanza_get_kick_reason(xmpp_stanza_t *stanza)
+{
+    char *stanza_name = xmpp_stanza_get_name(stanza);
+    if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) {
+        xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER);
+        if (x) {
+            xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, STANZA_NAME_ITEM);
+            if (item) {
+                xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(item, STANZA_NAME_REASON);
+                if (reason_st) {
+                    char *reason = xmpp_stanza_get_text(reason_st);
+                    if (reason) {
+                        return reason;
+                    }
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
 gboolean
 stanza_is_room_nick_change(xmpp_stanza_t * const stanza)
 {
diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h
index fefa47b6..ae673848 100644
--- a/src/xmpp/stanza.h
+++ b/src/xmpp/stanza.h
@@ -76,6 +76,7 @@
 #define STANZA_NAME_CONFERENCE "conference"
 #define STANZA_NAME_VALUE "value"
 #define STANZA_NAME_DESTROY "destroy"
+#define STANZA_NAME_ACTOR "actor"
 
 // error conditions
 #define STANZA_NAME_BAD_REQUEST "bad-request"
@@ -248,4 +249,12 @@ xmpp_stanza_t * stanza_create_roster_remove_set(xmpp_ctx_t *ctx,
 
 char * stanza_get_error_message(xmpp_stanza_t * const stanza);
 
+GSList* stanza_get_status_codes_by_ns(xmpp_stanza_t * const stanza, char *ns);
+gboolean stanza_room_destroyed(xmpp_stanza_t *stanza);
+char* stanza_get_muc_destroy_alternative_room(xmpp_stanza_t *stanza);
+char* stanza_get_muc_destroy_alternative_password(xmpp_stanza_t *stanza);
+char* stanza_get_muc_destroy_reason(xmpp_stanza_t *stanza);
+char* stanza_get_kick_actor(xmpp_stanza_t *stanza);
+char* stanza_get_kick_reason(xmpp_stanza_t *stanza);
+
 #endif