1using Gee;
2
3using Xmpp;
4using Dino.Entities;
5
6namespace Dino {
7
8public class Register : StreamInteractionModule, Object{
9    public static ModuleIdentity<Register> IDENTITY = new ModuleIdentity<Register>("registration");
10    public string id { get { return IDENTITY.id; } }
11
12    private StreamInteractor stream_interactor;
13    private Database db;
14
15    public static void start(StreamInteractor stream_interactor, Database db) {
16        Register m = new Register(stream_interactor, db);
17        stream_interactor.add_module(m);
18    }
19
20    private Register(StreamInteractor stream_interactor, Database db) {
21        this.stream_interactor = stream_interactor;
22        this.db = db;
23    }
24
25    public async ConnectionManager.ConnectionError.Source? add_check_account(Account account) {
26        XmppStream stream = new XmppStream();
27        stream.log = new XmppLog(account.bare_jid.to_string(), Application.print_xmpp);
28        stream.add_module(new Tls.Module());
29        stream.add_module(new Iq.Module());
30        stream.add_module(new Xep.SrvRecordsTls.Module());
31        stream.add_module(new Sasl.Module(account.bare_jid.to_string(), account.password));
32
33        ConnectionManager.ConnectionError.Source? ret = null;
34
35        SourceFunc callback = add_check_account.callback;
36        stream.stream_negotiated.connect(() => {
37            if (callback == null) return;
38            Idle.add((owned)callback);
39        });
40        stream.get_module(Tls.Module.IDENTITY).invalid_certificate.connect((peer_cert, errors) => {
41            if (callback == null) return;
42            ret = ConnectionManager.ConnectionError.Source.TLS;
43            Idle.add((owned)callback);
44        });
45        stream.get_module(Sasl.Module.IDENTITY).received_auth_failure.connect((stream, node) => {
46            if (callback == null) return;
47            ret = ConnectionManager.ConnectionError.Source.SASL;
48            Idle.add((owned)callback);
49        });
50        stream.connect.begin(account.domainpart, (_, res) => {
51            try {
52                stream.connect.end(res);
53            } catch (Error e) {
54                debug("Error connecting to stream: %s", e.message);
55            }
56            if (callback != null) {
57                ret = ConnectionManager.ConnectionError.Source.CONNECTION;
58                Idle.add((owned)callback);
59            }
60        });
61
62        yield;
63
64        try {
65            yield stream.disconnect();
66        } catch (Error e) {}
67        return ret;
68    }
69
70    public class ServerAvailabilityReturn {
71        public bool available { get; set; }
72        public TlsCertificateFlags? error_flags { get; set; }
73    }
74
75    public static async ServerAvailabilityReturn check_server_availability(Jid jid) {
76        XmppStream stream = new XmppStream();
77        stream.log = new XmppLog(jid.to_string(), Application.print_xmpp);
78        stream.add_module(new Tls.Module());
79        stream.add_module(new Iq.Module());
80        stream.add_module(new Xep.SrvRecordsTls.Module());
81
82        ServerAvailabilityReturn ret = new ServerAvailabilityReturn() { available=false };
83        SourceFunc callback = check_server_availability.callback;
84        stream.stream_negotiated.connect(() => {
85            if (callback != null) {
86                ret.available = true;
87                Idle.add((owned)callback);
88            }
89        });
90        stream.get_module(Tls.Module.IDENTITY).invalid_certificate.connect((peer_cert, errors) => {
91            if (callback != null) {
92                ret.error_flags = errors;
93                Idle.add((owned)callback);
94            }
95        });
96
97        stream.connect.begin(jid.domainpart, (_, res) => {
98            try {
99                stream.connect.end(res);
100            } catch (Error e) {
101                debug("Error connecting to stream: %s", e.message);
102            }
103            if (callback != null) {
104                Idle.add((owned)callback);
105            }
106        });
107
108        yield;
109
110        try {
111            yield stream.disconnect();
112        } catch (Error e) {}
113        return ret;
114    }
115
116    public static async Xep.InBandRegistration.Form? get_registration_form(Jid jid) {
117        XmppStream stream = new XmppStream();
118        stream.log = new XmppLog(jid.to_string(), Application.print_xmpp);
119        stream.add_module(new Tls.Module());
120        stream.add_module(new Iq.Module());
121        stream.add_module(new Xep.SrvRecordsTls.Module());
122        stream.add_module(new Xep.InBandRegistration.Module());
123
124        SourceFunc callback = get_registration_form.callback;
125
126        stream.stream_negotiated.connect(() => {
127            if (callback != null) {
128                Idle.add((owned)callback);
129            }
130        });
131
132        stream.connect.begin(jid.domainpart, (_, res) => {
133            try {
134                stream.connect.end(res);
135            } catch (Error e) {
136                debug("Error connecting to stream: %s", e.message);
137            }
138            if (callback != null) {
139                Idle.add((owned)callback);
140            }
141        });
142
143        yield;
144
145        Xep.InBandRegistration.Form? form = null;
146        if (stream.negotiation_complete) {
147            form = yield stream.get_module(Xep.InBandRegistration.Module.IDENTITY).get_from_server(stream, jid);
148        }
149        try {
150            yield stream.disconnect();
151        } catch (Error e) {}
152
153        return form;
154    }
155
156    public static async string? submit_form(Jid jid, Xep.InBandRegistration.Form form) {
157        XmppStream stream = new XmppStream();
158        stream.log = new XmppLog(jid.to_string(), Application.print_xmpp);
159        stream.add_module(new Tls.Module());
160        stream.add_module(new Iq.Module());
161        stream.add_module(new Xep.SrvRecordsTls.Module());
162        stream.add_module(new Xep.InBandRegistration.Module());
163
164        SourceFunc callback = submit_form.callback;
165
166        stream.stream_negotiated.connect(() => {
167            if (callback != null) {
168                Idle.add((owned)callback);
169            }
170        });
171
172        stream.connect.begin(jid.domainpart, (_, res) => {
173            try {
174                stream.connect.end(res);
175            } catch (Error e) {
176                debug("Error connecting to stream: %s", e.message);
177            }
178            if (callback != null) {
179                Idle.add((owned)callback);
180            }
181        });
182
183        yield;
184
185        string? ret = null;
186        if (stream.negotiation_complete) {
187            ret = yield stream.get_module(Xep.InBandRegistration.Module.IDENTITY).submit_to_server(stream, jid, form);
188        }
189        try {
190            yield stream.disconnect();
191        } catch (Error e) {}
192        return ret;
193    }
194}
195
196}
197