From a37b5ac823cc5daefac6ab33a16d6f44c747ba9c Mon Sep 17 00:00:00 2001
From: fiaxh <git@mx.ax.lt>
Date: Tue, 11 Apr 2017 18:06:01 +0200
Subject: MUC improvements

---
 xmpp-vala/CMakeLists.txt                           |   1 +
 xmpp-vala/src/module/presence/module.vala          |   4 +-
 xmpp-vala/src/module/xep/0045_muc/flag.vala        |  21 +++--
 xmpp-vala/src/module/xep/0045_muc/module.vala      | 100 ++++++++-------------
 xmpp-vala/src/module/xep/0045_muc/status_code.vala |  58 ++++++++++++
 5 files changed, 111 insertions(+), 73 deletions(-)
 create mode 100644 xmpp-vala/src/module/xep/0045_muc/status_code.vala

(limited to 'xmpp-vala')

diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt
index 7c8ce6e6..240ee02e 100644
--- a/xmpp-vala/CMakeLists.txt
+++ b/xmpp-vala/CMakeLists.txt
@@ -41,6 +41,7 @@ SOURCES
     "src/module/xep/0030_service_discovery/module.vala"
     "src/module/xep/0045_muc/flag.vala"
     "src/module/xep/0045_muc/module.vala"
+    "src/module/xep/0045_muc/status_code.vala"
     "src/module/xep/0048_bookmarks/module.vala"
     "src/module/xep/0048_bookmarks/conference.vala"
     "src/module/xep/0049_private_xml_storage.vala"
diff --git a/xmpp-vala/src/module/presence/module.vala b/xmpp-vala/src/module/presence/module.vala
index 3c078453..a2cdf1d7 100644
--- a/xmpp-vala/src/module/presence/module.vala
+++ b/xmpp-vala/src/module/presence/module.vala
@@ -11,7 +11,7 @@ namespace Xmpp.Presence {
         public signal void initial_presence_sent(XmppStream stream, Presence.Stanza presence);
         public signal void received_available(XmppStream stream, Presence.Stanza presence);
         public signal void received_available_show(XmppStream stream, string jid, string show);
-        public signal void received_unavailable(XmppStream stream, string jid);
+        public signal void received_unavailable(XmppStream stream, Presence.Stanza presence);
         public signal void received_subscription_request(XmppStream stream, string jid);
         public signal void received_unsubscription(XmppStream stream, string jid);
 
@@ -76,7 +76,7 @@ namespace Xmpp.Presence {
                     break;
                 case Presence.Stanza.TYPE_UNAVAILABLE:
                     stream.get_flag(Flag.IDENTITY).remove_presence(presence.from);
-                    received_unavailable(stream, presence.from);
+                    received_unavailable(stream, presence);
                     break;
                 case Presence.Stanza.TYPE_SUBSCRIBE:
                     received_subscription_request(stream, presence.from);
diff --git a/xmpp-vala/src/module/xep/0045_muc/flag.vala b/xmpp-vala/src/module/xep/0045_muc/flag.vala
index f6340a5c..e5e0af6e 100644
--- a/xmpp-vala/src/module/xep/0045_muc/flag.vala
+++ b/xmpp-vala/src/module/xep/0045_muc/flag.vala
@@ -7,7 +7,6 @@ namespace Xmpp.Xep.Muc {
 public class Flag : XmppStreamFlag {
     public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "muc");
 
-    private HashMap<string, ListenerHolder> enter_listeners = new HashMap<string, ListenerHolder>();
     private HashMap<string, string> enter_ids = new HashMap<string, string>();
     private HashMap<string, string> own_nicks = new HashMap<string, string>();
     private HashMap<string, string> subjects = new HashMap<string, string>();
@@ -32,8 +31,6 @@ public class Flag : XmppStreamFlag {
 
     public string? get_enter_id(string bare_jid) { return enter_ids[bare_jid]; }
 
-    public ListenerHolder? get_enter_listener(string bare_jid) { return enter_listeners[bare_jid]; }
-
     public bool is_muc(string jid) { return own_nicks[jid] != null; }
 
     public bool is_occupant(string jid) {
@@ -45,23 +42,33 @@ public class Flag : XmppStreamFlag {
 
     public string? get_muc_subject(string bare_jid) { return subjects[bare_jid]; }
 
-    public void set_muc_subject(string full_jid, string subject) {
+    public void set_muc_subject(string full_jid, string? subject) {
         string bare_jid = get_bare_jid(full_jid);
         subjects[bare_jid] = subject;
         subjects_by[bare_jid] = full_jid;
     }
 
-    public void start_muc_enter(string bare_jid, string presence_id, ListenerHolder listener) {
-        enter_listeners[bare_jid] = listener;
+    public void start_muc_enter(string bare_jid, string presence_id) {
         enter_ids[bare_jid] = presence_id;
     }
 
     public void finish_muc_enter(string bare_jid, string? nick = null) {
         if (nick != null) own_nicks[bare_jid] = nick;
-        enter_listeners.unset(bare_jid);
         enter_ids.unset(bare_jid);
     }
 
+    public void left_muc(XmppStream stream, string muc) {
+        own_nicks.unset(muc);
+        subjects.unset(muc);
+        subjects_by.unset(muc);
+        Gee.List<string>? occupants = stream.get_flag(Presence.Flag.IDENTITY).get_resources(muc);
+        if (occupants != null) {
+            foreach (string occupant in occupants) {
+                remove_occupant_info(occupant);
+            }
+        }
+    }
+
     public void remove_occupant_info(string full_jid) {
         occupant_real_jids.unset(full_jid);
         occupant_affiliation.unset(full_jid);
diff --git a/xmpp-vala/src/module/xep/0045_muc/module.vala b/xmpp-vala/src/module/xep/0045_muc/module.vala
index 486c342a..714bb2ca 100644
--- a/xmpp-vala/src/module/xep/0045_muc/module.vala
+++ b/xmpp-vala/src/module/xep/0045_muc/module.vala
@@ -35,8 +35,14 @@ public class Module : XmppStreamModule {
     public signal void received_occupant_jid(XmppStream stream, string jid, string? real_jid);
     public signal void received_occupant_role(XmppStream stream, string jid, string? role);
     public signal void subject_set(XmppStream stream, string subject, string jid);
+    public signal void room_configuration_changed(XmppStream stream, string jid, StatusCode code);
 
-    public void enter(XmppStream stream, string bare_jid, string nick, string? password, ListenerHolder.OnSuccess success_listener, ListenerHolder.OnError error_listener, Object? store) {
+    public signal void room_entered(XmppStream stream, string jid, string nick);
+    public signal void room_enter_error(XmppStream stream, string jid, MucEnterError error);
+    public signal void self_removed_from_room(XmppStream stream, string jid, StatusCode code);
+    public signal void removed_from_room(XmppStream stream, string jid, StatusCode? code);
+
+    public void enter(XmppStream stream, string bare_jid, string nick, string? password) {
         Presence.Stanza presence = new Presence.Stanza();
         presence.to = bare_jid + "/" + nick;
         StanzaNode x_node = new StanzaNode.build("x", NS_URI).add_self_xmlns();
@@ -45,8 +51,7 @@ public class Module : XmppStreamModule {
         }
         presence.stanza.put_node(x_node);
 
-        stream.get_flag(Flag.IDENTITY).start_muc_enter(bare_jid, presence.id, new ListenerHolder(success_listener, error_listener, store));
-
+        stream.get_flag(Flag.IDENTITY).start_muc_enter(bare_jid, presence.id);
         stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence);
     }
 
@@ -129,7 +134,6 @@ public class Module : XmppStreamModule {
             string bare_jid = get_bare_jid(presence.from);
             ErrorStanza? error_stanza = presence.get_error();
             if (flag.get_enter_id(bare_jid) == error_stanza.original_id) {
-                ListenerHolder? listener = flag.get_enter_listener(bare_jid);
                 MucEnterError? error = null;
                 if (error_stanza.condition == ErrorStanza.CONDITION_NOT_AUTHORIZED && ErrorStanza.TYPE_AUTH == error_stanza.type_) {
                     error = MucEnterError.PASSWORD_REQUIRED;
@@ -144,7 +148,7 @@ public class Module : XmppStreamModule {
                 } else if (ErrorStanza.CONDITION_ITEM_NOT_FOUND == error_stanza.condition && ErrorStanza.TYPE_CANCEL == error_stanza.type_) {
                     error = MucEnterError.ROOM_DOESNT_EXIST;
                 }
-                if (error != null && listener != null) listener.on_error(stream, error, listener.reference);
+                if (error != null) room_enter_error(stream, bare_jid, error);
                 flag.finish_muc_enter(bare_jid);
             }
         }
@@ -158,9 +162,10 @@ public class Module : XmppStreamModule {
                 ArrayList<int> status_codes = get_status_codes(x_node);
                 if (status_codes.contains(StatusCode.SELF_PRESENCE)) {
                     string bare_jid = get_bare_jid(presence.from);
-                    ListenerHolder listener = flag.get_enter_listener(bare_jid);
-                    listener.on_success(stream, listener.reference);
-                    flag.finish_muc_enter(bare_jid, get_resource_part(presence.from));
+                    if (flag.get_enter_id(bare_jid) != null) {
+                        room_entered(stream, bare_jid, get_resource_part(presence.from));
+                        flag.finish_muc_enter(bare_jid, get_resource_part(presence.from));
+                    }
                 }
                 string? affiliation = x_node["item", "affiliation"].val;
                 if (affiliation != null) {
@@ -179,10 +184,30 @@ public class Module : XmppStreamModule {
         }
     }
 
-    private void on_received_unavailable(XmppStream stream, string jid) {
+    private void on_received_unavailable(XmppStream stream, Presence.Stanza presence) {
         Flag flag = stream.get_flag(Flag.IDENTITY);
-        if (flag.is_occupant(jid)) {
-            flag.remove_occupant_info(jid);
+        if (!flag.is_occupant(presence.from)) return;
+
+        StanzaNode? x_node = presence.stanza.get_subnode("x", NS_URI_USER);
+        if (x_node == null) return;
+
+        ArrayList<int> status_codes = get_status_codes(x_node);
+
+        if (StatusCode.SELF_PRESENCE in status_codes) {
+            flag.remove_occupant_info(presence.from);
+        }
+
+        foreach (StatusCode code in USER_REMOVED_CODES) {
+            if (code in status_codes) {
+                if (StatusCode.SELF_PRESENCE in status_codes) {
+                    flag.left_muc(stream, get_bare_jid(presence.from));
+                    self_removed_from_room(stream, presence.from, code);
+                    Presence.Flag presence_flag = stream.get_flag(Presence.Flag.IDENTITY);
+                    presence_flag.remove_presence(get_bare_jid(presence.from));
+                } else {
+                    removed_from_room(stream, presence.from, code);
+                }
+            }
         }
     }
 
@@ -195,57 +220,4 @@ public class Module : XmppStreamModule {
     }
 }
 
-public enum StatusCode {
-    /** Inform user that any occupant is allowed to see the user's full JID */
-    JID_VISIBLE = 100,
-    /** Inform user that his or her affiliation changed while not in the room */
-    AFFILIATION_CHANGED = 101,
-    /** Inform occupants that room now shows unavailable members */
-    SHOWS_UNAVIABLE_MEMBERS = 102,
-    /** Inform occupants that room now does not show unavailable members */
-    SHOWS_UNAVIABLE_MEMBERS_NOT = 103,
-    /** Inform occupants that a non-privacy-related room configuration change has occurred */
-    CONFIG_CHANGE_NON_PRIVACY = 104,
-    /** Inform user that presence refers to itself */
-    SELF_PRESENCE = 110,
-    /** Inform occupants that room logging is now enabled */
-    LOGGING_ENABLED = 170,
-    /** Inform occupants that room logging is now disabled */
-    LOGGING_DISABLED = 171,
-    /** Inform occupants that the room is now non-anonymous */
-    NON_ANONYMOUS = 172,
-    /** Inform occupants that the room is now semi-anonymous */
-    SEMI_ANONYMOUS = 173,
-    /** Inform user that a new room has been created */
-    NEW_ROOM_CREATED = 201,
-    /** Inform user that service has assigned or modified occupant's roomnick */
-    MODIFIED_NICK = 210,
-    /** Inform user that he or she has been banned from the room */
-    BANNED = 301,
-    /** Inform all occupants of new room nickname */
-    ROOM_NICKNAME = 303,
-    /** Inform user that he or she has been kicked from the room */
-    KICKED = 307,
-    /** Inform user that he or she is being removed from the room */
-    REMOVED_AFFILIATION_CHANGE = 321,
-    /** Inform user that he or she is being removed from the room because the room has been changed to members-only
-    and the user is not a member */
-    REMOVED_MEMBERS_ONLY = 322,
-    /** Inform user that he or she is being removed from the room because the MUC service is being shut down */
-    REMOVED_SHUTDOWN = 332
-}
-
-public class ListenerHolder {
-    [CCode (has_target = false)] public delegate void OnSuccess(XmppStream stream, Object? store);
-    public OnSuccess on_success { get; private set; }
-    [CCode (has_target = false)] public delegate void OnError(XmppStream stream, MucEnterError error, Object? store);
-    public OnError on_error { get; private set; }
-    public Object? reference { get; private set; }
-
-    public ListenerHolder(OnSuccess on_success, OnError on_error, Object? reference = null) {
-        this.on_success = on_success;
-        this.reference = reference;
-    }
-}
-
 }
diff --git a/xmpp-vala/src/module/xep/0045_muc/status_code.vala b/xmpp-vala/src/module/xep/0045_muc/status_code.vala
new file mode 100644
index 00000000..7cb9421f
--- /dev/null
+++ b/xmpp-vala/src/module/xep/0045_muc/status_code.vala
@@ -0,0 +1,58 @@
+namespace Xmpp.Xep.Muc {
+
+public const StatusCode[] ROOM_CONFIGURATION_CODES = {
+    StatusCode.LOGGING_ENABLED,
+    StatusCode.LOGGING_DISABLED,
+    StatusCode.NON_ANONYMOUS,
+    StatusCode.SEMI_ANONYMOUS
+};
+
+public const StatusCode[] USER_REMOVED_CODES = {
+    StatusCode.BANNED,
+    StatusCode.KICKED,
+    StatusCode.REMOVED_AFFILIATION_CHANGE,
+    StatusCode.REMOVED_MEMBERS_ONLY,
+    StatusCode.REMOVED_SHUTDOWN
+};
+
+public enum StatusCode {
+    /** Inform user that any occupant is allowed to see the user's full JID */
+    JID_VISIBLE = 100,
+    /** Inform user that his or her affiliation changed while not in the room */
+    AFFILIATION_CHANGED = 101,
+    /** Inform occupants that room now shows unavailable members */
+    SHOWS_UNAVIABLE_MEMBERS = 102,
+    /** Inform occupants that room now does not show unavailable members */
+    SHOWS_UNAVIABLE_MEMBERS_NOT = 103,
+    /** Inform occupants that a non-privacy-related room configuration change has occurred */
+    CONFIG_CHANGE_NON_PRIVACY = 104,
+    /** Inform user that presence refers to itself */
+    SELF_PRESENCE = 110,
+    /** Inform occupants that room logging is now enabled */
+    LOGGING_ENABLED = 170,
+    /** Inform occupants that room logging is now disabled */
+    LOGGING_DISABLED = 171,
+    /** Inform occupants that the room is now non-anonymous */
+    NON_ANONYMOUS = 172,
+    /** Inform occupants that the room is now semi-anonymous */
+    SEMI_ANONYMOUS = 173,
+    /** Inform user that a new room has been created */
+    NEW_ROOM_CREATED = 201,
+    /** Inform user that service has assigned or modified occupant's roomnick */
+    MODIFIED_NICK = 210,
+    /** Inform user that he or she has been banned from the room */
+    BANNED = 301,
+    /** Inform all occupants of new room nickname */
+    ROOM_NICKNAME = 303,
+    /** Inform user that he or she has been kicked from the room */
+    KICKED = 307,
+    /** Inform user that he or she is being removed from the room */
+    REMOVED_AFFILIATION_CHANGE = 321,
+    /** Inform user that he or she is being removed from the room because the room has been changed to members-only
+    and the user is not a member */
+    REMOVED_MEMBERS_ONLY = 322,
+    /** Inform user that he or she is being removed from the room because the MUC service is being shut down */
+    REMOVED_SHUTDOWN = 332
+}
+
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2