aboutsummaryrefslogtreecommitdiff
path: root/xmpp-vala/src/module/roster/module.vala
blob: c9400b3acd0bc5ee3029dda12c4059f8aa831148 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using Gee;

using Xmpp.Core;

namespace Xmpp.Roster {
    private const string NS_URI = "jabber:iq:roster";

    public class Module : XmppStreamModule, Iq.Handler {
        public const string ID = "roster_module";
        public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, ID);

        public signal void received_roster(XmppStream stream, Collection<Item> roster);
        public signal void item_removed(XmppStream stream, Item roster_item);
        public signal void item_updated(XmppStream stream, Item roster_item);

        public bool interested_resource = true;

        /**
         * Add a jid to the roster
         */
        public void add_jid(XmppStream stream, string jid, string? handle = null) {
            Item roster_item = new Item();
            roster_item.jid = jid;
            if (handle != null) {
                roster_item.name = handle;
            }
            roster_set(stream, roster_item);
        }

        /**
         * Remove a jid from the roster
         */
        public void remove_jid(XmppStream stream, string jid) {
            Item roster_item = new Item();
            roster_item.jid = jid;
            roster_item.subscription = Item.SUBSCRIPTION_REMOVE;

            roster_set(stream, roster_item);
        }

        /**
         * Set a handle for a jid
         * @param   handle  Handle to be set. If null, any handle will be removed.
         */
        public void set_jid_handle(XmppStream stream, string jid, string? handle) {
            Item roster_item = new Item();
            roster_item.jid = jid;
            if (handle != null) {
                roster_item.name = handle;
            }

            roster_set(stream, roster_item);
        }

        public void on_iq_set(XmppStream stream, Iq.Stanza iq) {
            StanzaNode? query_node = iq.stanza.get_subnode("query", NS_URI);
            if (query_node == null) return;

            Flag flag = Flag.get_flag(stream);
            Item item = new Item.from_stanza_node(query_node.get_subnode("item", NS_URI));
            switch (item.subscription) {
                case Item.SUBSCRIPTION_REMOVE:
                    flag.roster_items.unset(item.jid);
                    item_removed(stream, item);
                    break;
                default:
                    flag.roster_items[item.jid] = item;
                    item_updated(stream, item);
                    break;
            }
        }

        public void on_iq_get(XmppStream stream, Iq.Stanza iq) { }

        public static void require(XmppStream stream) {
            if (stream.get_module(IDENTITY) == null) stream.add_module(new Module());
        }

        public override void attach(XmppStream stream) {
            Iq.Module.require(stream);
            stream.get_module(Iq.Module.IDENTITY).register_for_namespace(NS_URI, this);
            Presence.Module.require(stream);
            stream.get_module(Presence.Module.IDENTITY).initial_presence_sent.connect(roster_get);
            stream.add_flag(new Flag());
        }

        public override void detach(XmppStream stream) {
            stream.get_module(Presence.Module.IDENTITY).initial_presence_sent.disconnect(roster_get);
        }

        internal override string get_ns() { return NS_URI; }
        internal override string get_id() { return ID; }

        private void roster_get(XmppStream stream) {
            Flag.get_flag(stream).iq_id = random_uuid();
            StanzaNode query_node = new StanzaNode.build("query", NS_URI).add_self_xmlns();
            Iq.Stanza iq = new Iq.Stanza.get(query_node, Flag.get_flag(stream).iq_id);
            stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, new IqResponseListenerImpl());
        }

        private class IqResponseListenerImpl : Iq.ResponseListener, Object {
            public void on_result(XmppStream stream, Iq.Stanza iq) {
                Flag flag = Flag.get_flag(stream);
                if (iq.id == flag.iq_id) {
                    StanzaNode? query_node = iq.stanza.get_subnode("query", NS_URI);
                    foreach (StanzaNode item_node in query_node.sub_nodes) {
                        Item item = new Item.from_stanza_node(item_node);
                        flag.roster_items[item.jid] = item;
                    }
                    stream.get_module(Module.IDENTITY).received_roster(stream, flag.roster_items.values);
                }
            }
        }

        private void roster_set(XmppStream stream, Item roster_item) {
            StanzaNode query_node = new StanzaNode.build("query", NS_URI).add_self_xmlns()
                                    .put_node(roster_item.stanza_node);
            Iq.Stanza iq = new Iq.Stanza.set(query_node);
            stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, null);
        }
    }
}