]> Pileus Git - ~andy/lamechat/blob - xmpp.c
Make logfile optional.
[~andy/lamechat] / xmpp.c
1 /*
2  * Copyright (C) 2017 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <expat.h>
27 #include <time.h>
28
29 #include "util.h"
30 #include "conf.h"
31 #include "chat.h"
32 #include "view.h"
33 #include "net.h"
34
35 /* Constants */
36 #define ID_LEN   256
37 #define AUTH_LEN 512
38 #define JID_LEN  256
39
40 /* XMPP types */
41 typedef enum {
42         XMPP_DEAD,
43         XMPP_CONNECT,
44         XMPP_ENCRYPT,
45         XMPP_RESTART,
46         XMPP_SEND_STREAM,
47         XMPP_RECV_FEATURES,
48         XMPP_SEND_STARTTLS,
49         XMPP_RECV_PROCEED,
50         XMPP_SEND_AUTH,
51         XMPP_RECV_SUCCESS,
52         XMPP_SEND_BIND,
53         XMPP_RECV_JID,
54         XMPP_SEND_SESSION,
55         XMPP_SEND_PRESENCE,
56         XMPP_SEND_ROSTER,
57         XMPP_SEND_ROOMS,
58         XMPP_SEND_JOIN,
59         XMPP_READY,
60         XMPP_IN_IQ,
61         XMPP_IN_VCARD,
62         XMPP_IN_ROSTER,
63         XMPP_IN_ROOMS,
64         XMPP_IN_MESSAGE,
65         XMPP_IN_PRESENCE,
66 } xmpp_state_t;
67
68 typedef struct {
69         user_t          user;
70         char            dest[JID_LEN];
71         int             muc;
72         char           *full_name;
73         char           *mention_name;
74 } xmpp_user_t;
75
76 typedef struct {
77         channel_t       channel;
78         char            dest[JID_LEN];
79         const char     *type;
80         int             muc;
81
82         char           *room;
83         char           *name;
84         int             join;
85 } xmpp_channel_t;
86
87 typedef struct {
88         server_t        server;
89         xmpp_user_t     myself;
90         xmpp_channel_t  system;
91
92         int             connect;
93         int             timeout;
94         int             noverify;
95         const char     *host;
96         int             port;
97         const char     *srv;
98         const char     *muc;
99         const char     *nick;
100         const char     *jid;
101         const char     *user;
102         const char     *pass;
103         int             quiet;
104
105         idle_t          idle;
106
107         net_t           net;
108         XML_Parser      expat;
109         xmpp_state_t    state;
110         buf_t           buf;
111         buf_t           html;
112         int             level;
113         int             id;
114         char           *bind;
115
116         char            msg_id[ID_LEN];
117         xmpp_channel_t *msg_chan;
118         xmpp_user_t    *msg_usr;
119         char           *msg_body;
120         char           *msg_html;
121         stamp_t         msg_stamp;
122
123         int             in_html;
124         int             in_error;
125 } xmpp_server_t;
126
127 /* Helper functions */
128 static void srv_notice(xmpp_server_t *srv, const char *fmt, ...)
129 {
130         static char buf[1024];
131
132         va_list ap;
133         va_start(ap, fmt);
134         vsnprintf(buf, sizeof(buf), fmt, ap);
135         va_end(ap);
136
137         debug("xmpp: srv_notice: [%s]", buf);
138         chat_recv(&srv->system.channel, NULL, buf);
139 }
140
141 static void chan_notice(xmpp_channel_t *chan, const char *fmt, ...)
142 {
143         static char buf[1024];
144
145         va_list ap;
146         va_start(ap, fmt);
147         vsnprintf(buf, sizeof(buf), fmt, ap);
148         va_end(ap);
149
150         debug("xmpp: chan_notice -- %s [%s]",
151                         chan->channel.name, buf);
152         chat_recv(&chan->channel, NULL, buf);
153 }
154
155 static void split_jid(const char *jid, char *usr, char *srv, char *res)
156 {
157         char *ptr = usr;
158         int   pos = 0;
159
160         if (usr) usr[0] = '\0';
161         if (srv) srv[0] = '\0';
162         if (res) res[0] = '\0';
163
164         while (jid && *jid == ' ')
165                 jid++;
166         for (int i = 0; jid && jid[i]; i++) {
167                 switch (jid[i]) {
168                         case '@':
169                                 ptr = srv;
170                                 pos = 0;
171                                 continue;
172                         case '/':
173                                 ptr = res;
174                                 pos = 0;
175                                 continue;
176                 }
177                 if (ptr && (pos+1) < JID_LEN) {
178                         ptr[pos++] = jid[i];
179                         ptr[pos] = '\0';
180                 }
181         }
182         while (ptr && pos >= 1 && ptr[pos-1] == ' ')
183                 ptr[--pos] = '\0';
184
185         //debug("JID: '%s' usr=[%s] srv=[%s] res=[%s]",
186         //              jid, usr, srv, res);
187 }
188
189 static xmpp_channel_t *find_channel(xmpp_server_t *srv,
190                 const char *jid, int is_muc)
191 {
192         static char jid_usr[JID_LEN];
193         static char jid_srv[JID_LEN];
194         static char dest[JID_LEN];
195         xmpp_channel_t *chan;
196
197         /* Server channels */
198         if (!jid || match(jid, srv->srv))
199                 return &srv->system;
200
201         /* Parse JID and check for MUC */
202         split_jid(jid, jid_usr, jid_srv, NULL);
203         if (match(jid_srv, srv->muc))
204                 is_muc = 1;
205
206         /* Find resource-less JID */
207         snprintf(dest, JID_LEN, "%s@%s", jid_usr,
208                  jid_srv[0] ? jid_srv  :
209                  is_muc     ? srv->muc : srv->srv);
210
211         /* Find existing channels */
212         for (channel_t *cur = channels; cur; cur = cur->next) {
213                 if (cur->server != &srv->server)
214                         continue;
215                 chan = (xmpp_channel_t *)cur;
216                 if (match(chan->dest, dest))
217                         return chan;
218         }
219
220         /* Create a new channel */
221         chan = new0(xmpp_channel_t);
222         chan->muc = is_muc;
223         chan->type = is_muc ? "muc" : "usr";
224         chan->channel.server = &srv->server;
225         chan->channel.name = strcopy(jid_usr);
226         strncpy(chan->dest, dest, JID_LEN);
227         add_channel(&chan->channel);
228         return chan;
229 }
230
231 static xmpp_user_t *find_user(xmpp_server_t *srv,
232                 const char *jid, int is_muc)
233 {
234         static char jid_usr[JID_LEN];
235         static char jid_srv[JID_LEN];
236         static char jid_res[JID_LEN];
237         static char dest[JID_LEN];
238         xmpp_user_t *usr;
239
240         /* Server channels */
241         if (!jid || match(jid, srv->srv))
242                 return NULL;
243
244         /* Parse JID and check for MUC */
245         split_jid(jid, jid_usr, jid_srv, jid_res);
246         if (match(jid_srv, srv->muc))
247                 is_muc = 1;
248
249         /* Channel notices have no resource */
250         if (is_muc && !jid_res[0])
251                 return NULL;
252
253         /* Ignore resources for real users */
254         if (is_muc)
255                 snprintf(dest, JID_LEN, "%s@%s/%s",
256                          jid_usr,
257                          jid_srv[0] ? jid_srv : srv->muc,
258                          jid_res);
259         else
260                 snprintf(dest, JID_LEN, "%s@%s",
261                          jid_usr,
262                          jid_srv[0] ? jid_srv : srv->srv);
263
264         /* Find existing users */
265         for (user_t *cur = users; cur; cur = cur->next) {
266                 if (cur->server != &srv->server)
267                         continue;
268                 usr = (xmpp_user_t *)cur;
269                 if (match(usr->dest, dest)) {
270                         debug("xmpp: found user: \"%s\" -> "
271                                "name=[%s] dest=[%s] alias=[%s]",
272                                         jid, usr->user.name, usr->dest,
273                                         usr->user.alias ? usr->user.alias->name : "(none)");
274                         return usr;
275                 }
276         }
277
278         /* Create a new user */
279         usr = new0(xmpp_user_t);
280         usr->user.server = &srv->server;
281         if (is_muc) {
282                 usr->user.name = strcopy(jid_res);
283                 usr->full_name = strcopy(jid_res);
284         } else {
285                 usr->user.name = strcopy(jid_usr);
286         }
287         usr->muc = is_muc;
288         strncpy(usr->dest, dest, JID_LEN);
289         add_user(&usr->user);
290
291         /* Send vcard probe */
292         debug("xmpp: added user: \"%s\"%s -> name=[%s] dest=[%s]",
293                         jid, is_muc ? " (muc)" : "",
294                         usr->user.name, usr->dest);
295
296         return usr;
297 }
298
299 static int match_user(xmpp_user_t *usr, const char *ptrn)
300 {
301         char tmp[32];
302
303         const char *user = usr->dest;
304         const char *full = usr->full_name;
305         const char *nick = usr->mention_name;
306
307         /* Match all users */
308         if (!ptrn || !ptrn[0])
309                 return 1;
310
311         /* Match user id and mention name */
312         if (user && strcasestr(user, ptrn) == user)
313                 return 1;
314         if (nick && strcasestr(nick, ptrn) == nick)
315                 return 1;
316
317         /* Full name matching */
318         if (!full || !full[0])
319                 return 0;
320
321         /* Match first name */
322         if (strcasestr(full, ptrn) == full)
323                 return 1;
324
325         /* Match last name */
326         snprintf(tmp, sizeof(tmp), " %s", ptrn);
327         if (strcasestr(full, tmp))
328                 return 1;
329         snprintf(tmp, sizeof(tmp), "-%s", ptrn);
330         if (strcasestr(full, tmp))
331                 return 1;
332
333         /* Match first initial last name */
334         if (tolower(full[0]) == tolower(ptrn[0])) {
335                 snprintf(tmp, sizeof(tmp), " %s", &ptrn[1]);
336                 if (strcasestr(full, tmp))
337                         return 1;
338                 snprintf(tmp, sizeof(tmp), "-%s", &ptrn[1]);
339                 if (strcasestr(full, tmp))
340                         return 1;
341         }
342
343         return 0;
344 }
345
346 static int match_channel(xmpp_channel_t *chan, const char *ptrn)
347 {
348         const char *dest = chan->dest;
349         const char *room = chan->room;
350
351         /* Match all users */
352         if (!ptrn || !ptrn[0])
353                 return 1;
354
355         /* Match dest and channel name */
356         if (dest && strcasestr(dest, ptrn))
357                 return 1;
358         if (room && strcasestr(room, ptrn))
359                 return 1;
360
361         return 0;
362 }
363
364 static void complete_xmpp_user(xmpp_server_t *srv, const char *prefix, int mention)
365 {
366         for (user_t *cur = users; cur; cur = cur->next) {
367                 if (cur->server != &srv->server)
368                         continue;
369                 xmpp_user_t *usr = (xmpp_user_t *)cur;
370                 if (usr->muc)
371                         continue;
372                 if (match_user(usr, prefix)) {
373                         if (!mention)
374                                 complete_item(prefix, usr->dest, usr->full_name);
375                         else if (usr->mention_name)
376                                 complete_item(prefix, usr->mention_name, usr->full_name);
377                         else
378                                 complete_item(prefix, usr->full_name, "");
379                 }
380         }
381 }
382
383 static void complete_xmpp_channel(xmpp_server_t *srv, const char *prefix)
384 {
385         for (channel_t *cur = channels; cur; cur = cur->next) {
386                 if (cur->server != &srv->server)
387                         continue;
388                 xmpp_channel_t *chan = (xmpp_channel_t *)cur;
389                 if (!chan->muc)
390                         continue;
391                 if (match_channel(chan, prefix))
392                         complete_item(prefix, chan->dest, chan->name ?: chan->room);
393         }
394 }
395
396 static const char *find_attr(const char **attrs, const char *name)
397 {
398         for (int i = 0; attrs[i] && attrs[i+1]; i += 2)
399                 if (match(attrs[i+0], name))
400                         return attrs[i+1];
401         return NULL;
402 }
403
404 static void lookup_user(xmpp_server_t *srv, xmpp_user_t *usr)
405 {
406         if (usr->full_name)
407                 return;
408         net_print(&srv->net,
409                 "<iq id='auto-vcard' type='get' from='%s' to='%s'>"
410                 "<vCard xmlns='vcard-temp'/>"
411                 "</iq>",
412                 srv->bind, usr->dest);
413 }
414
415 /* Callback functions */
416 static void xmpp_run(xmpp_server_t *srv, int idle,
417                 const char *start, const char **attrs,
418                 const char *end, const char *data);
419
420 static void on_start(void *_srv, const char *tag, const char **attrs)
421 {
422         xmpp_server_t *srv = _srv;
423         xmpp_run(srv, 0, tag, attrs, NULL, reset(&srv->buf));
424 }
425
426 static void on_data(void *_srv, const char *data, int len)
427 {
428         xmpp_server_t *srv = _srv;
429         append(&srv->buf, data, len);
430 }
431
432 static void on_end(void *_srv, const char *tag)
433 {
434         xmpp_server_t *srv = _srv;
435         xmpp_run(srv, 0, NULL, NULL, tag, reset(&srv->buf));
436 }
437
438 static void on_send(void *_srv)
439 {
440         xmpp_server_t *srv = _srv;
441         xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
442 }
443
444 static void on_recv(void *_srv, char *buf, int len)
445 {
446         xmpp_server_t *srv = _srv;
447         if (len > 0)
448                 XML_Parse(srv->expat, buf, len, 0);
449         xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
450 }
451
452 static void on_err(void *_srv, int err)
453 {
454         xmpp_server_t *srv = _srv;
455         srv_notice(srv, "Server disconnected");
456         srv->state = XMPP_DEAD;
457 }
458
459 static void on_timer(void *_srv)
460 {
461         xmpp_server_t *srv = _srv;
462         xmpp_run(srv, 1, NULL, NULL, NULL, NULL);
463 }
464
465 /* XMPP State machine */
466 static void xmpp_run(xmpp_server_t *srv, int idle,
467                 const char *start, const char **attrs,
468                 const char *end, const char *data)
469 {
470         /* Debug print */
471         if (data)
472                 debug("%*s \"%s\"", srv->level*4, "", data);
473         if (start) {
474                 debug("%*s<%s>", srv->level*4, "", start);
475                 for (int i = 0; attrs[i] && attrs[i+1]; i += 2) {
476                         debug("%*s%s=\"%s\"%s",
477                                 srv->level*4+8, "",
478                                 attrs[i+0], attrs[i+1],
479                                 attrs[i+2] ? "" : ">");
480                 }
481         }
482         if (start)
483                 srv->level++;
484         if (end)
485                 srv->level--;
486
487         /* Connection Handling */
488         if (srv->state == XMPP_CONNECT && !start && !end) {
489                 srv->net.send = on_send;
490                 srv->net.recv = on_recv;
491                 srv->net.err  = on_err;
492                 srv->net.data = srv;
493
494                 srv->idle.timer = on_timer;
495                 srv->idle.data  = srv;
496
497                 net_open(&srv->net, srv->host, srv->port);
498                 idle_add(&srv->idle);
499                 idle_set(&srv->idle, srv->timeout, srv->timeout);
500
501                 if (!(srv->expat = XML_ParserCreate(NULL)))
502                         error("creating XML parser");
503                 XML_SetUserData(srv->expat, srv);
504                 XML_SetStartElementHandler(srv->expat, on_start);
505                 XML_SetEndElementHandler(srv->expat, on_end);
506                 XML_SetCharacterDataHandler(srv->expat, on_data);
507
508                 debug("xmpp: connect -> stream");
509                 srv->level = 0;
510                 srv->state = XMPP_SEND_STREAM;
511         }
512         if (srv->state == XMPP_ENCRYPT && !start && !end) {
513                 net_encrypt(&srv->net, srv->noverify ? NET_NOVERIFY : 0);
514
515                 if (!(XML_ParserReset(srv->expat, NULL)))
516                         error("resetting XML parser");
517                 XML_SetUserData(srv->expat, srv);
518                 XML_SetStartElementHandler(srv->expat, on_start);
519                 XML_SetEndElementHandler(srv->expat, on_end);
520                 XML_SetCharacterDataHandler(srv->expat, on_data);
521
522                 debug("xmpp: encrypt -> stream");
523                 srv->level = 0;
524                 srv->state = XMPP_SEND_STREAM;
525         }
526         if (srv->state == XMPP_RESTART && !start && !end) {
527                 if (!(XML_ParserReset(srv->expat, NULL)))
528                         error("resetting XML parser");
529                 XML_SetUserData(srv->expat, srv);
530                 XML_SetStartElementHandler(srv->expat, on_start);
531                 XML_SetEndElementHandler(srv->expat, on_end);
532                 XML_SetCharacterDataHandler(srv->expat, on_data);
533
534                 debug("xmpp: restart -> stream");
535                 srv->level = 0;
536                 srv->state = XMPP_SEND_STREAM;
537         }
538
539         /* Idle handling */
540         if (srv->state > XMPP_CONNECT && idle) {
541                 debug("xmpp: idle");
542                 net_print(&srv->net, " ");
543         }
544
545         /* Stream Start */
546         if (srv->state == XMPP_SEND_STREAM) {
547                 if (net_print(&srv->net,
548                     "<?xml version='1.0'?>"
549                     "<stream:stream"
550                     " from='%s'"
551                     " to='%s'"
552                     " version='1.0'"
553                     " xml:lang='en'"
554                     " xmlns='jabber:client'"
555                     " xmlns:stream='http://etherx.jabber.org/streams'>",
556                     srv->jid, srv->srv)) {
557                         debug("xmpp: stream -> features");
558                         srv->state = XMPP_RECV_FEATURES;
559                 }
560         }
561         if (srv->state == XMPP_RECV_FEATURES) {
562                 if (match(start, "starttls")) {
563                         debug("xmpp: features -> starttls");
564                         srv->state = XMPP_SEND_STARTTLS;
565                 }
566                 if (match(start, "mechanisms")) {
567                         debug("xmpp: features -> auth");
568                         srv->state = XMPP_SEND_AUTH;
569                 }
570                 if (match(start, "bind")) {
571                         debug("xmpp: features -> bind");
572                         srv->state = XMPP_SEND_BIND;
573                 }
574         }
575
576         /* Start TLS */
577         if (srv->state == XMPP_SEND_STARTTLS) {
578                 if (net_print(&srv->net,
579                     "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>")) {
580                         debug("xmpp: startls -> proceed");
581                         srv->state = XMPP_RECV_PROCEED;
582                 }
583         }
584         if (srv->state == XMPP_RECV_PROCEED) {
585                 if (match(start, "proceed")) {
586                         debug("xmpp: proceed -> encrypt");
587                         srv->state = XMPP_ENCRYPT;
588                 }
589         }
590
591         /* Authentication */
592         if (srv->state == XMPP_SEND_AUTH) {
593                 static char plain[AUTH_LEN];
594                 static char coded[AUTH_LEN];
595                 int len;
596                 len = snprintf(plain, AUTH_LEN, "%s%c%s%c%s",
597                                 srv->user, '\0', srv->user, '\0', srv->pass);
598                 len = base64(plain, len, coded, AUTH_LEN);
599                 if (net_print(&srv->net,
600                     "<auth"
601                     " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'"
602                     " mechanism='PLAIN'>%.*s</auth>",
603                         len, coded)) {
604                         debug("xmpp: auth -> success");
605                         srv->state = XMPP_RECV_SUCCESS;
606                 }
607         }
608         if (srv->state == XMPP_RECV_SUCCESS) {
609                 if (match(start, "failure")) {
610                         debug("xmpp: success -> dead");
611                         srv_notice(srv, "Authentication failure");
612                         srv->state = XMPP_DEAD;
613                 }
614                 if (match(start, "success")) {
615                         debug("xmpp: success -> restart");
616                         srv_notice(srv, "Authentication success");
617                         srv->state = XMPP_RESTART;
618                 }
619         }
620
621         /* Binding */
622         if (srv->state == XMPP_SEND_BIND) {
623                 const char *resource = srv->jid;
624                 while (*resource && *resource != '/')
625                         resource++;
626                 while (*resource && *resource == '/')
627                         resource++;
628                 if (net_print(&srv->net,
629                     "<iq id='bind' type='set'>"
630                     "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
631                     "<resource>%s</resource>"
632                     "</bind>"
633                     "</iq>",
634                     resource)) {
635                         debug("xmpp: bind -> jid");
636                         srv->state = XMPP_RECV_JID;
637                 }
638         }
639         if (srv->state == XMPP_RECV_JID) {
640                 if (match(end, "jid")) {
641                         debug("xmpp: jid -> session");
642                         strset(&srv->bind, data ?: srv->jid);
643                         srv->state = XMPP_SEND_SESSION;
644                 }
645         }
646         if (srv->state == XMPP_SEND_SESSION) {
647                 if (net_print(&srv->net,
648                     "<iq id='session' type='set' to='%s'>"
649                     "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
650                     "</iq>",
651                     srv->srv)) {
652                         debug("xmpp: session -> presence");
653                         srv->state = XMPP_SEND_PRESENCE;
654                 }
655         }
656         if (srv->state == XMPP_SEND_PRESENCE) {
657                 if (net_print(&srv->net, "<presence/>")) {
658                         debug("xmpp: presence -> roster");
659                         srv->state = XMPP_SEND_ROSTER;
660                 }
661         }
662         if (srv->state == XMPP_SEND_ROSTER) {
663                 if (net_print(&srv->net,
664                     "<iq id='roster' type='get'>"
665                     "<query xmlns='jabber:iq:roster'/>"
666                     "</iq>")) {
667                         debug("xmpp: roster -> rooms");
668                         srv->state = XMPP_SEND_ROOMS;
669                 }
670         }
671         if (srv->state == XMPP_SEND_ROOMS) {
672                 if (net_print(&srv->net,
673                     "<iq id='rooms' type='get' to='%s'>"
674                     "<query xmlns='http://jabber.org/protocol/disco#items'/>"
675                     "</iq>",
676                     srv->muc)) {
677                         debug("xmpp: rooms -> join");
678                         srv->state = XMPP_SEND_JOIN;
679                 }
680         }
681         if (srv->state == XMPP_SEND_JOIN) {
682                 for (channel_t *cur = channels; cur; cur = cur->next) {
683                         if (cur->server != &srv->server)
684                                 continue;
685                         xmpp_channel_t *chan = (xmpp_channel_t *)cur;
686                         if (!chan->join)
687                                 continue;
688                         if (!srv->quiet)
689                                 chan_notice(chan, "XMPP Channel: %s", chan->channel.name);
690                         net_print(&srv->net,
691                                 "<presence id='join' from='%s' to='%s/%s'>"
692                                 "<x xmlns='http://jabber.org/protocol/muc'/>"
693                                 "</presence>",
694                                 srv->bind, chan->dest, srv->nick);
695                 }
696                 debug("xmpp: join -> ready");
697                 srv->state = XMPP_READY;
698         }
699
700         /* Start message */
701         if (srv->state == XMPP_READY && start) {
702                 const char *id   = find_attr(attrs, "id");
703                 const char *from = find_attr(attrs, "from");
704                 const char *type = find_attr(attrs, "type");
705                 int is_muc = match(type, "groupchat");
706
707                 /* Ignore presence errors (federated remote timeout, etc) */
708                 if (match(type, "error"))
709                         return;
710
711                 strncpy(srv->msg_id, id ?: "", ID_LEN);
712
713                 srv->msg_chan = find_channel(srv, from, is_muc);
714                 srv->msg_usr  = find_user(srv, from, is_muc);
715
716                 if (match(start, "iq"))
717                         srv->state = XMPP_IN_IQ;
718                 if (match(start, "message"))
719                         srv->state = XMPP_IN_MESSAGE;
720                 if (match(start, "presence"))
721                         srv->state = XMPP_IN_PRESENCE;
722
723                 if (srv->state != XMPP_READY)
724                         debug("xmpp: ready -> in_%s -- "
725                               "from=[%s] -> chan=[%s:%s] user=[%s]",
726                                 start, from,
727                                 srv->msg_chan->type,
728                                 srv->msg_chan->channel.name,
729                                 srv->msg_usr ? srv->msg_usr->user.name : "(none)");
730         }
731
732         /* Shorthand Message Data */
733         xmpp_channel_t *chan  = NULL;
734         xmpp_user_t    *usr   = NULL;
735         xmpp_user_t    *alias = NULL;
736
737         if (srv->state > XMPP_READY) {
738                 chan = srv->msg_chan;
739                 usr  = srv->msg_usr;
740                 if (usr)
741                         alias = (xmpp_user_t*)usr->user.alias;
742         }
743
744         /* Info/Queries */
745         if (srv->state == XMPP_IN_IQ) {
746                 if (match(start, "item")) {
747                         if (chan == &srv->system) {
748                                 srv_notice(srv, "item: [%s] %s",
749                                                 find_attr(attrs, "jid"),
750                                                 find_attr(attrs, "name"));
751                         } else if (chan->muc) {
752                                 const char  *jid = find_attr(attrs, "jid");
753                                 xmpp_user_t *usr = find_user(srv, jid, 1);
754                                 if (jid && usr)
755                                         chan_notice(chan, "User: %s (%s)",
756                                                         usr->user.name, jid);
757                         } else {
758                                 chan_notice(chan, "item: [%s] %s",
759                                                 find_attr(attrs, "jid"),
760                                                 find_attr(attrs, "name"));
761                         }
762                 }
763                 if (match(start, "identity")) {
764                         srv_notice(srv, "identity: %s",
765                                         find_attr(attrs, "name"));
766                 }
767                 if (match(start, "feature")) {
768                         srv_notice(srv, "feature: %s",
769                                         find_attr(attrs, "var"));
770                 }
771                 if (match(start, "field")) {
772                         debug("xmpp: %s -- type=[%s] label=[%s]", end,
773                                 find_attr(attrs, "type"),
774                                 find_attr(attrs, "label"));
775                         if (!find_attr(attrs, "label"))
776                                 return;
777                         chan_notice(chan, "%-36s -- %s (%s)",
778                                 find_attr(attrs, "var"),
779                                 find_attr(attrs, "label"),
780                                 find_attr(attrs, "type"));
781                 }
782                 if (match(end, "title")) {
783                         debug("xmpp: title -- chan=[%s]",
784                                 end, chan->dest);
785                         chan_notice(chan, "Title: %s", data);
786                 }
787                 if (match(end, "instructions")) {
788                         debug("xmpp: instructions -- chan=[%s]",
789                                 end, chan->dest);
790                         chan_notice(chan, "%s", data);
791                 }
792         }
793
794         /* vCards */
795         if (srv->state == XMPP_IN_IQ) {
796                 if (match(start, "vCard")) {
797                         if (!match(srv->msg_id, "auto-vcard"))
798                                 chan_notice(chan, "Begin vCard (%s)",
799                                                 usr ?  usr->user.name :
800                                                 chan->channel.name);
801                         srv->state = XMPP_IN_VCARD;
802                 }
803         }
804         if (srv->state == XMPP_IN_VCARD) {
805                 if (end && srv->level == 3) {
806                         if (!match(srv->msg_id, "auto-vcard") &&
807                             !match(end, "BINVAL"))
808                                 chan_notice(chan, "  %s -> %s", end, data ?: "...");
809                 }
810                 if (usr) {
811                         if (match(end, "FN")) {
812                                 strset(&chan->channel.name, data);
813                                 strset(&usr->user.name, data);
814                                 strset(&usr->full_name, data);
815                                 chat_update();
816                         }
817                 }
818         }
819         if (srv->state == XMPP_IN_VCARD) {
820                 if (match(end, "vCard")) {
821                         if (!match(srv->msg_id, "auto-vcard"))
822                                 chan_notice(chan, "End vCard");
823                         srv->state = XMPP_IN_IQ;
824                 }
825         }
826
827         /* Rosters */
828         if (srv->state == XMPP_IN_IQ) {
829                 if (match(srv->msg_id, "roster"))
830                         srv->state = XMPP_IN_ROSTER;
831         }
832         if (srv->state == XMPP_IN_ROSTER) {
833                 if (match(start, "item")) {
834                         // Todo: cleanup name setting
835                         const char     *jid   = find_attr(attrs, "jid");
836                         const char     *fname = find_attr(attrs, "name");
837                         const char     *mname = find_attr(attrs, "mention_name");
838                         xmpp_user_t    *usr   = find_user(srv, jid, 0);
839                         xmpp_channel_t *chan  = find_channel(srv, jid, 0);
840                         if (usr) {
841                                 strset(&usr->full_name,     fname);
842                                 strset(&usr->user.name,     fname);
843                                 strset(&usr->mention_name,  mname);
844                         }
845                         if (chan) {
846                                 strset(&chan->channel.name, fname);
847                         }
848                 }
849         }
850         if (srv->state == XMPP_IN_ROSTER) {
851                 if (match(end, "iq"))
852                         srv->state = XMPP_IN_IQ;
853         }
854
855         /* Rooms */
856         if (srv->state == XMPP_IN_IQ) {
857                 if (match(srv->msg_id, "rooms"))
858                         srv->state = XMPP_IN_ROOMS;
859         }
860         if (srv->state == XMPP_IN_ROOMS) {
861                 if (match(start, "item")) {
862                         const char     *jid  = find_attr(attrs, "jid");
863                         xmpp_channel_t *chan = find_channel(srv, jid, 1);
864                         if (jid && chan) {
865                                 strset(&chan->room,
866                                        find_attr(attrs, "name"));
867                                 strset(&chan->name,
868                                        find_attr(attrs, "name"));
869                         }
870                 }
871         }
872         if (srv->state == XMPP_IN_ROOMS) {
873                 if (match(end, "iq"))
874                         srv->state = XMPP_IN_IQ;
875         }
876
877         /* Messages */
878         if (srv->state == XMPP_IN_MESSAGE) {
879                 if (match(start, "delay")) {
880                         const char *ts = find_attr(attrs, "stamp");
881                         if (ts) {
882                                 struct tm tm = {};
883                                 strptime(ts, "%Y-%m-%dT%H:%M:%S", &tm);
884                                 srv->msg_stamp = timegm(&tm);
885                         }
886                 }
887                 if (match(end, "subject")) {
888                         strset(&chan->channel.topic, data);
889                         if (!srv->quiet)
890                                 chan_notice(chan, "Topic: %s", data);
891                 }
892                 if (match(end, "body") && data) {
893                         strset(&srv->msg_body, data);
894                 }
895                 if (match(start, "html")) {
896                         srv->in_html = 1;
897                 }
898                 if (srv->in_html && data) {
899                         append(&srv->html, data, strlen(data));
900                 }
901                 if (match(end, "html")) {
902                         strset(&srv->msg_html, reset(&srv->html));
903                         srv->in_html = 0;
904                 }
905                 if (match(end, "message")) {
906                         debug("xmpp: body (%s) -- chan=[%s] from=[%s]",
907                                 chan->type,
908                                 chan->channel.name,
909                                 usr ? usr->user.name : "(none)");
910                         char *content = srv->msg_body;
911                         if (srv->msg_html)
912                                 content = despace(srv->msg_html);
913                         if (usr && !usr->muc)
914                                 lookup_user(srv, usr);
915                         if (content) {
916                                 chat_recv(&chan->channel, &usr->user, content);
917                                 message_t *msg = &messages[history-1];
918                                 msg->when = srv->msg_stamp ?: msg->when;
919                         }
920                         srv->msg_stamp = 0;
921                         strset(&srv->msg_body, NULL);
922                         strset(&srv->msg_html, NULL);
923                 }
924
925         }
926
927         /* Presence */
928         if (srv->state == XMPP_IN_PRESENCE) {
929                 if (match(start, "item") && usr) {
930                         const char  *jid   = find_attr(attrs, "jid");
931                         xmpp_user_t *alias = find_user(srv, jid, 0);
932                         if (alias)
933                                 usr->user.alias = &alias->user;
934                         if (alias && !alias->full_name && usr->full_name) {
935                                 strset(&alias->user.name, usr->full_name);
936                                 strset(&alias->full_name, usr->full_name);
937                         }
938                         xmpp_channel_t *chan  = find_channel(srv, jid, 0);
939                         if (alias && alias->full_name && chan) {
940                                 strset(&chan->channel.name, alias->full_name);
941                         }
942                 }
943                 if (match(end, "presence") && !srv->quiet) {
944                         if (alias)
945                                 chan_notice(chan, "%s (%s) entered room.",
946                                                 usr->user.name, alias->user.name);
947                         else if (usr)
948                                 chan_notice(chan, "%s entered room.",
949                                                 usr->user.name);
950                 }
951         }
952
953         /* End messages */
954         if (srv->state == XMPP_IN_IQ)
955                 if (match(end, "iq"))
956                         srv->state = XMPP_READY;
957         if (srv->state == XMPP_IN_MESSAGE)
958                 if (match(end, "message"))
959                         srv->state = XMPP_READY;
960         if (srv->state == XMPP_IN_PRESENCE)
961                 if (match(end, "presence"))
962                         srv->state = XMPP_READY;
963
964         /* Error handling */
965         if (match(start, "stream:error"))
966                 srv->in_error = 1;
967         if (match(end, "stream:error"))
968                 srv->in_error = 0;
969         if (srv->in_error) {
970                 if (match(end, "text")) {
971                         debug("xmpp: error: %s", data);
972                         srv_notice(srv, "error: %s", data);
973                 }
974         }
975 }
976
977 /* XMPP functions */
978 void xmpp_init(void)
979 {
980         static char jid_usr[JID_LEN];
981         static char jid_srv[JID_LEN];
982         static char jid_res[JID_LEN];
983
984         for (server_t *cur = servers; cur; cur = cur->next) {
985                 if (cur->protocol != XMPP)
986                         continue;
987
988                 xmpp_server_t *srv = (xmpp_server_t*)cur;
989                 split_jid(srv->jid, jid_usr, jid_srv, jid_res);
990
991                 if (!srv->jid)
992                         error("jid is required");
993                 if (!srv->host)
994                         srv->host = strcopy(jid_srv);
995                 if (!srv->port)
996                         srv->port = 5222;
997                 if (!srv->muc)
998                         srv->muc = strcopy(srv->host);
999                 if (!srv->srv)
1000                         srv->srv = strcopy(srv->host);
1001                 if (!srv->user)
1002                         srv->user = strcopy(jid_usr);
1003                 if (!srv->nick)
1004                         srv->nick = strcopy(jid_usr);
1005                 if (!srv->timeout)
1006                         srv->timeout = 60;
1007
1008                 srv->system.type  = "sys";
1009                 srv->system.channel.server = &srv->server;
1010                 srv->system.channel.name = strcopy(srv->server.name);
1011
1012                 strncpy(srv->myself.dest, srv->jid, JID_LEN);
1013                 srv->myself.user.server = &srv->server;
1014                 srv->myself.user.name = strcopy(srv->nick);
1015
1016                 if (srv->connect && !srv->quiet)
1017                         srv_notice(srv, "XMPP Server: %s", srv->server.name);
1018                 if (srv->connect) {
1019                         srv->state = XMPP_CONNECT;
1020                         xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
1021                 }
1022         }
1023         for (channel_t *cur = channels; cur; cur = cur->next) {
1024                 if (cur->server->protocol != XMPP)
1025                         continue;
1026
1027                 xmpp_channel_t *chan = (xmpp_channel_t*)cur;
1028                 xmpp_server_t *srv = (xmpp_server_t*)cur->server;
1029                 chan->muc = 1;
1030                 chan->type = "muc";
1031                 if (!chan->room)
1032                         chan->room = strcopy(cur->name);
1033                 snprintf(chan->dest, JID_LEN, "%s@%s",
1034                          chan->room, srv->muc);
1035         }
1036 }
1037
1038 void xmpp_config(server_t *server, channel_t *channel,
1039                  const char *group, const char *name,
1040                  const char *key, const char *value)
1041 {
1042         xmpp_server_t  *srv  = (xmpp_server_t*)server;
1043         xmpp_channel_t *chan = (xmpp_channel_t*)channel;
1044
1045         if (match(group, "server")) {
1046                 if (match(key, "protocol")) {
1047                         xmpp_server_t *srv = new0(xmpp_server_t);
1048                         srv->server.protocol = XMPP;
1049                         srv->server.name = strcopy(get_name(name));
1050                         add_server(&srv->server);
1051                 }
1052                 else if (match(key, "connect"))
1053                         srv->connect = get_bool(value);
1054                 else if (match(key, "timeout"))
1055                         srv->timeout = get_number(value);
1056                 else if (match(key, "noverify"))
1057                         srv->noverify = get_bool(value);
1058                 else if (match(key, "host"))
1059                         srv->host = get_string(value);
1060                 else if (match(key, "port"))
1061                         srv->port = get_number(value);
1062                 else if (match(key, "srv"))
1063                         srv->srv = get_string(value);
1064                 else if (match(key, "muc"))
1065                         srv->muc = get_string(value);
1066                 else if (match(key, "nick"))
1067                         srv->nick = get_string(value);
1068                 else if (match(key, "jid"))
1069                         srv->jid = get_string(value);
1070                 else if (match(key, "user"))
1071                         srv->user = get_string(value);
1072                 else if (match(key, "pass"))
1073                         srv->pass = get_string(value);
1074                 else if (match(key, "quiet"))
1075                         srv->quiet = get_bool(value);
1076         }
1077         if (match(group, "channel")) {
1078                 if (match(key, "server")) {
1079                         xmpp_channel_t *chan = new0(xmpp_channel_t);
1080                         chan->channel.server = &srv->server;
1081                         chan->channel.name = strcopy(get_name(name));
1082                         add_channel(&chan->channel);
1083                 }
1084                 else if (match(key, "room"))
1085                         chan->room = get_string(value);
1086                 else if (match(key, "join"))
1087                         chan->join = get_bool(value);
1088         }
1089         if (match(group, "autojoin")) {
1090                 xmpp_channel_t *chan = new0(xmpp_channel_t);
1091                 chan->channel.server = &srv->server;
1092                 chan->channel.name = strcopy(key);
1093                 chan->room = get_string(value);
1094                 chan->join = 1;
1095                 add_channel(&chan->channel);
1096         }
1097 }
1098
1099 void xmpp_complete(channel_t *channel, const char *text)
1100 {
1101         xmpp_server_t *srv = (xmpp_server_t*)channel->server;
1102         const char *arg;
1103
1104         if (suffix(text, "@", &arg)) {
1105                 complete_xmpp_user(srv, arg, 1);
1106         }
1107         else if (prefix(text, "/join ", &arg)) {
1108                 complete_xmpp_channel(srv, arg);
1109         }
1110         else if (prefix(text, "/query ", &arg)) {
1111                 complete_xmpp_user(srv, arg, 0);
1112         }
1113         else if (prefix(text, "/vcard ", &arg)) {
1114                 complete_xmpp_user(srv, arg, 0);
1115         }
1116         else {
1117                 complete_args(text,
1118                               "/items ",  "Query XMPP server 'items'",
1119                               "/info ",   "Query XMPP server 'info'",
1120                               "/names ",  "Query XMPP channel users",
1121                               "/join",    "Join XMPP (muc) room",
1122                               "/config ", "Configure XMPP (muc) room",
1123                               "/query ",  "Open XMPP user chat",
1124                               "/vcard ",  "Send XMPP vCard query",
1125                               NULL);
1126         }
1127 }
1128
1129 void xmpp_send(channel_t *channel, const char *text)
1130 {
1131         static char buf[4096];
1132
1133         xmpp_channel_t *chan = (xmpp_channel_t*)channel;
1134         xmpp_server_t  *srv  = (xmpp_server_t*)channel->server;
1135         const char *arg;
1136
1137         /* Escape HTML */
1138         const char *raw = text;
1139         escape(buf, text, sizeof(buf));
1140         text = buf;
1141
1142         /* Handle commands */
1143         if (text[0] == '/' && text[1] != '/') {
1144                 if (prefix(text, "/items", &arg)) {
1145                         net_print(&srv->net,
1146                                 "<iq id='items' type='get' from='%s' to='%s'>"
1147                                 "<query xmlns='http://jabber.org/protocol/disco#items'/>"
1148                                 "</iq>",
1149                                 srv->bind, arg ?: srv->srv);
1150                 }
1151                 else if (prefix(text, "/info", &arg)) {
1152                         net_print(&srv->net,
1153                                 "<iq id='info' type='get' from='%s' to='%s'>"
1154                                 "<query xmlns='http://jabber.org/protocol/disco#info'/>"
1155                                 "</iq>",
1156                                 srv->bind, arg ?: srv->srv);
1157                 }
1158                 else if (prefix(text, "/names", &arg)) {
1159                         if (arg)
1160                                 chan = find_channel(srv, arg, 1);
1161                         if (chan == &srv->system) {
1162                                 chan_notice(chan, "Cannot get names from server");
1163                                 return;
1164                         }
1165                         net_print(&srv->net,
1166                                 "<iq id='names' type='get' from='%s' to='%s'>"
1167                                 "<query xmlns='http://jabber.org/protocol/disco#items'/>"
1168                                 "</iq>",
1169                                 srv->bind, chan->dest);
1170                 }
1171                 else if (prefix(text, "/join", &arg)) {
1172                         if (!arg) {
1173                                 chan_notice(chan, "usage: /join <channel>");
1174                                 return;
1175                         }
1176                         chan = find_channel(srv, arg, 1);
1177                         net_print(&srv->net,
1178                                 "<presence id='join' from='%s' to='%s/%s'>"
1179                                 "<x xmlns='http://jabber.org/protocol/muc'/>"
1180                                 "</presence>",
1181                                 srv->bind, chan->dest, srv->nick);
1182                         chan_notice(chan, "Room: %s", arg);
1183                 }
1184                 else if (prefix(text, "/config", &arg)) {
1185                         if (arg) {
1186                                 chan_notice(chan, "Unimplemented: /config <arg>");
1187                                 return;
1188                         }
1189                         if (chan == &srv->system) {
1190                                 chan_notice(chan, "Cannot get config from server");
1191                                 return;
1192                         }
1193                         net_print(&srv->net,
1194                                 "<iq id='config' type='get' from='%s' to='%s'>"
1195                                 "<query xmlns='http://jabber.org/protocol/muc#owner'/>"
1196                                 "</iq>",
1197                                 srv->bind, chan->dest);
1198                 }
1199                 else if (prefix(text, "/query", &arg)) {
1200                         if (!arg) {
1201                                 chan_notice(chan, "usage: /query <user>");
1202                                 return;
1203                         }
1204                         chan = find_channel(srv, arg, 0);
1205                         chan_notice(chan, "User: %s", arg);
1206                 }
1207                 else if (prefix(text, "/vcard", &arg)) {
1208                         if (arg)
1209                                 chan = find_channel(srv, arg, 0);
1210                         if (chan)
1211                                 net_print(&srv->net,
1212                                         "<iq id='vcard' type='get' from='%s' to='%s'>"
1213                                         "<vCard xmlns='vcard-temp'/>"
1214                                         "</iq>",
1215                                         srv->bind, chan->dest);
1216                 }
1217                 else {
1218                         chan_notice(chan, "Unknown command %s", text);
1219                 }
1220         } else {
1221                 debug("message: [%s]", text);
1222                 if (text[0] == '/')
1223                         text = &text[1];
1224                 if (chan == &srv->system) {
1225                         chan_notice(chan, "Cannot send to server");
1226                 }
1227                 else if (chan->muc) {
1228                         net_print(&srv->net,
1229                                 "<message id='chat%d' from='%s' to='%s' type='groupchat'>"
1230                                 "<body>%s</body>"
1231                                 "</message>",
1232                                 srv->id++, srv->bind, chan->dest, text);
1233                 } else {
1234                         net_print(&srv->net,
1235                                 "<message id='chat%d' from='%s' to='%s' type='chat'>"
1236                                 "<body>%s</body>"
1237                                 "</message>",
1238                                 srv->id++, srv->bind, chan->dest, text);
1239                         chat_recv(channel, &srv->myself.user, raw);
1240                 }
1241         }
1242 }
1243
1244 void xmpp_exit(void)
1245 {
1246 }