1using Gee;
2
3namespace Xmpp.Presence {
4    private const string NS_URI = "jabber:client";
5
6    public class Module : XmppStreamModule {
7        public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "presence_module");
8
9        public signal void received_presence(XmppStream stream, Presence.Stanza presence);
10        public signal void pre_send_presence_stanza(XmppStream stream, Presence.Stanza presence);
11        public signal void initial_presence_sent(XmppStream stream, Presence.Stanza presence);
12        public signal void received_available(XmppStream stream, Presence.Stanza presence);
13        public signal void received_available_show(XmppStream stream, Jid jid, string show);
14        public signal void received_unavailable(XmppStream stream, Presence.Stanza presence);
15        public signal void received_subscription_request(XmppStream stream, Jid jid);
16        public signal void received_subscription_approval(XmppStream stream, Jid jid);
17        public signal void received_unsubscription(XmppStream stream, Jid jid);
18
19        public bool available_resource = true;
20
21        public void request_subscription(XmppStream stream, Jid bare_jid) {
22            Presence.Stanza presence = new Presence.Stanza();
23            presence.to = bare_jid;
24            presence.type_ = Presence.Stanza.TYPE_SUBSCRIBE;
25            send_presence(stream, presence);
26        }
27
28        public void approve_subscription(XmppStream stream, Jid bare_jid) {
29            Presence.Stanza presence = new Presence.Stanza();
30            presence.to = bare_jid;
31            presence.type_ = Presence.Stanza.TYPE_SUBSCRIBED;
32            send_presence(stream, presence);
33        }
34
35        public void deny_subscription(XmppStream stream, Jid bare_jid) {
36            cancel_subscription(stream, bare_jid);
37        }
38
39        public void cancel_subscription(XmppStream stream, Jid bare_jid) {
40            Presence.Stanza presence = new Presence.Stanza();
41            presence.to = bare_jid;
42            presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBED;
43            send_presence(stream, presence);
44        }
45
46        public void unsubscribe(XmppStream stream, Jid bare_jid) {
47            Presence.Stanza presence = new Presence.Stanza();
48            presence.to = bare_jid;
49            presence.type_ = Presence.Stanza.TYPE_UNSUBSCRIBE;
50            send_presence(stream, presence);
51        }
52
53        public void send_presence(XmppStream stream, Presence.Stanza presence) {
54            pre_send_presence_stanza(stream, presence);
55            stream.write(presence.stanza);
56        }
57
58        public override void attach(XmppStream stream) {
59            stream.add_flag(new Flag());
60            stream.received_presence_stanza.connect(on_received_presence_stanza);
61            stream.stream_negotiated.connect(on_stream_negotiated);
62        }
63
64        public override void detach(XmppStream stream) {
65            stream.received_presence_stanza.disconnect(on_received_presence_stanza);
66            stream.stream_negotiated.disconnect(on_stream_negotiated);
67        }
68
69        private void on_received_presence_stanza(XmppStream stream, StanzaNode node) {
70            Presence.Stanza presence = new Presence.Stanza.from_stanza(node, stream.get_flag(Bind.Flag.IDENTITY).my_jid);
71            received_presence(stream, presence);
72            switch (presence.type_) {
73                case Presence.Stanza.TYPE_AVAILABLE:
74                    stream.get_flag(Flag.IDENTITY).add_presence(presence);
75                    received_available(stream, presence);
76                    received_available_show(stream, presence.from, presence.show);
77                    break;
78                case Presence.Stanza.TYPE_UNAVAILABLE:
79                    stream.get_flag(Flag.IDENTITY).remove_presence(presence.from);
80                    received_unavailable(stream, presence);
81                    break;
82                case Presence.Stanza.TYPE_SUBSCRIBE:
83                    received_subscription_request(stream, presence.from);
84                    break;
85                case Presence.Stanza.TYPE_SUBSCRIBED:
86                    received_subscription_approval(stream, presence.from);
87                    break;
88                case Presence.Stanza.TYPE_UNSUBSCRIBE:
89                    stream.get_flag(Flag.IDENTITY).remove_presence(presence.from);
90                    received_unsubscription(stream, presence.from);
91                    break;
92                case Presence.Stanza.TYPE_UNSUBSCRIBED:
93                    break;
94            }
95        }
96
97        private void on_stream_negotiated(XmppStream stream) {
98            if (available_resource) {
99                Presence.Stanza presence = new Presence.Stanza();
100                send_presence(stream, presence);
101                initial_presence_sent(stream, presence);
102            }
103        }
104
105        public override string get_ns() { return NS_URI; }
106        public override string get_id() { return IDENTITY.id; }
107    }
108
109}
110