2 * Copyright (C) 2017 Andy Spencer <andy753421@gmail.com>
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.
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.
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/>.
30 #include <sys/timerfd.h>
80 xmpp_channel_t system;
109 char msg_jid[JID_LEN];
110 char msg_usr[JID_LEN];
111 char msg_srv[JID_LEN];
112 char msg_res[JID_LEN];
114 xmpp_channel_t *msg_chan;
117 /* Helper functions */
118 static void srv_notice(xmpp_server_t *srv, const char *fmt, ...)
120 static char buf[1024];
124 vsnprintf(buf, sizeof(buf), fmt, ap);
127 chat_recv(&srv->system.channel, NULL, buf);
130 static void chan_notice(xmpp_channel_t *chan, const char *fmt, ...)
132 static char buf[1024];
136 vsnprintf(buf, sizeof(buf), fmt, ap);
139 chat_recv(&chan->channel, NULL, buf);
142 static void split_jid(const char *jid, char *usr, char *srv, char *res)
147 if (usr) usr[0] = '\0';
148 if (srv) srv[0] = '\0';
149 if (res) res[0] = '\0';
151 for (int i = 0; jid && jid[i]; i++) {
162 if (ptr && (pos+1) < JID_LEN) {
168 //debug("JID: '%s' usr=[%s] srv=[%s] res=[%s]",
169 // jid, usr, srv, res);
172 static xmpp_channel_t *find_dest(xmpp_server_t *srv,
173 const char *jid, int is_muc)
175 static char jid_usr[JID_LEN];
176 static char jid_srv[JID_LEN];
177 static char dest[JID_LEN];
178 xmpp_channel_t *chan;
180 split_jid(jid, jid_usr, jid_srv, NULL);
181 snprintf(dest, JID_LEN, "%s@%s", jid_usr,
182 jid_srv[0] ? jid_srv :
183 is_muc ? srv->muc : srv->srv);
185 /* Server channels */
186 if (match(jid, srv->srv))
189 /* Find existing channels */
190 for (channel_t *cur = channels; cur; cur = cur->next) {
191 if (cur->server != &srv->server)
193 chan = (xmpp_channel_t *)cur;
194 if (match(chan->dest, dest))
198 /* Create a new channel */
199 chan = (xmpp_channel_t *)add_channel(jid_usr, &srv->server);
200 strncpy(chan->dest, dest, JID_LEN);
204 static xmpp_user_t *find_jid(xmpp_server_t *srv, const char *jid, int create)
208 /* Find existing channels */
209 for (user_t *cur = users; cur; cur = cur->next) {
210 if (cur->server != &srv->server)
212 usr = (xmpp_user_t *)cur;
213 if (match(usr->jid, jid))
217 /* Create a new channel */
218 usr = (xmpp_user_t *)add_user(jid, &srv->server);
219 strncpy(usr->jid, jid, JID_LEN);
223 static const char *find_attr(const char **attrs, const char *name)
225 for (int i = 0; attrs[i] && attrs[i+1]; i += 2)
226 if (match(attrs[i+0], name))
231 /* Callback functions */
232 static void xmpp_run(xmpp_server_t *srv, int idle,
233 const char *start, const char **attrs,
234 const char *end, const char *data);
236 static void on_start(void *_srv, const char *tag, const char **attrs)
238 xmpp_server_t *srv = _srv;
239 xmpp_run(srv, 0, tag, attrs, NULL, reset(&srv->buf));
242 static void on_data(void *_srv, const char *data, int len)
244 xmpp_server_t *srv = _srv;
245 append(&srv->buf, data, len);
248 static void on_end(void *_srv, const char *tag)
250 xmpp_server_t *srv = _srv;
251 xmpp_run(srv, 0, NULL, NULL, tag, reset(&srv->buf));
254 static void on_send(void *_srv)
256 xmpp_server_t *srv = _srv;
257 xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
260 static void on_recv(void *_srv, char *buf, int len)
262 xmpp_server_t *srv = _srv;
264 XML_Parse(srv->expat, buf, len, 0);
265 xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
268 static void on_err(void *_srv, int errno)
270 xmpp_server_t *srv = _srv;
271 xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
274 static void on_timer(void *_srv)
277 xmpp_server_t *srv = _srv;
278 while (read(srv->timer, &buf, sizeof(buf)) > 0)
279 xmpp_run(srv, 1, NULL, NULL, NULL, NULL);
282 /* XMPP State machine */
283 static void xmpp_run(xmpp_server_t *srv, int idle,
284 const char *start, const char **attrs,
285 const char *end, const char *data)
289 debug("%*s \"%s\"", srv->indent*4, "", data);
291 debug("%*s<%s>", srv->indent*4, "", start);
292 for (int i = 0; attrs[i] && attrs[i+1]; i += 2) {
293 debug("%*s%s=\"%s\"%s",
295 attrs[i+0], attrs[i+1],
296 attrs[i+2] ? "" : ">");
304 /* Connection Handling */
305 if (srv->state == XMPP_CONNECT && !start && !end) {
306 srv->net.send = on_send;
307 srv->net.recv = on_recv;
308 srv->net.err = on_err;
310 net_open(&srv->net, srv->host, srv->port);
312 srv->timer = timerfd_create(CLOCK_MONOTONIC,
313 TFD_NONBLOCK|TFD_CLOEXEC);
315 error("creating timer fd");
316 struct timespec tspec = {srv->timeout, 0};
317 struct itimerspec itspec = {tspec, tspec};
318 timerfd_settime(srv->timer, 0, &itspec, NULL);
319 poll_add(&srv->poll, srv->timer, on_timer, srv);
320 poll_ctl(&srv->poll, 1, 0, 1);
322 if (!(srv->expat = XML_ParserCreate(NULL)))
323 error("Error creating XML parser");
324 XML_SetUserData(srv->expat, srv);
325 XML_SetStartElementHandler(srv->expat, on_start);
326 XML_SetEndElementHandler(srv->expat, on_end);
327 XML_SetCharacterDataHandler(srv->expat, on_data);
329 debug("xmpp: connect -> stream");
330 srv->state = XMPP_SEND_STREAM;
332 if (srv->state == XMPP_ENCRYPT && !start && !end) {
333 net_encrypt(&srv->net);
335 if (!(XML_ParserReset(srv->expat, NULL)))
336 error("Error resetting XML parser");
337 XML_SetUserData(srv->expat, srv);
338 XML_SetStartElementHandler(srv->expat, on_start);
339 XML_SetEndElementHandler(srv->expat, on_end);
340 XML_SetCharacterDataHandler(srv->expat, on_data);
342 debug("xmpp: encrypt -> stream");
343 srv->state = XMPP_SEND_STREAM;
345 if (srv->state == XMPP_RESTART && !start && !end) {
346 if (!(XML_ParserReset(srv->expat, NULL)))
347 error("Error resetting XML parser");
348 XML_SetUserData(srv->expat, srv);
349 XML_SetStartElementHandler(srv->expat, on_start);
350 XML_SetEndElementHandler(srv->expat, on_end);
351 XML_SetCharacterDataHandler(srv->expat, on_data);
353 debug("xmpp: restart -> stream");
354 srv->state = XMPP_SEND_STREAM;
358 if (srv->state == XMPP_SEND_STREAM) {
359 if (net_print(&srv->net,
360 "<?xml version='1.0'?>"
366 " xmlns='jabber:client'"
367 " xmlns:stream='http://etherx.jabber.org/streams'>",
368 srv->jid, srv->srv)) {
369 debug("xmpp: stream -> features");
370 srv->state = XMPP_RECV_FEATURES;
373 if (srv->state == XMPP_RECV_FEATURES) {
374 if (match(start, "starttls")) {
375 debug("xmpp: features -> starttls");
376 srv->state = XMPP_SEND_STARTTLS;
378 if (match(start, "mechanisms")) {
379 debug("xmpp: features -> auth");
380 srv->state = XMPP_SEND_AUTH;
382 if (match(start, "bind")) {
383 debug("xmpp: features -> bind");
384 srv->state = XMPP_SEND_BIND;
389 if (srv->state == XMPP_SEND_STARTTLS) {
390 if (net_print(&srv->net,
391 "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>")) {
392 debug("xmpp: startls -> proceed");
393 srv->state = XMPP_RECV_PROCEED;
396 if (srv->state == XMPP_RECV_PROCEED) {
397 if (match(start, "proceed")) {
398 debug("xmpp: proceed -> encrypt");
399 srv->state = XMPP_ENCRYPT;
404 if (srv->state == XMPP_SEND_AUTH) {
405 static char plain[AUTH_LEN];
406 static char coded[AUTH_LEN];
408 len = snprintf(plain, AUTH_LEN, "%s%c%s%c%s",
409 srv->user, '\0', srv->user, '\0', srv->pass);
410 len = base64(plain, len, coded, AUTH_LEN);
411 if (net_print(&srv->net,
413 " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'"
414 " mechanism='PLAIN'>%.*s</auth>",
416 debug("xmpp: auth -> success");
417 srv->state = XMPP_RECV_SUCCESS;
420 if (srv->state == XMPP_RECV_SUCCESS) {
421 if (match(start, "success")) {
422 debug("xmpp: success -> restart");
423 srv->state = XMPP_RESTART;
428 if (srv->state == XMPP_SEND_BIND) {
429 const char *resource = srv->jid;
430 while (*resource && *resource != '/')
432 while (*resource && *resource == '/')
434 if (net_print(&srv->net,
435 "<iq id='bind' type='set'>"
436 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
437 "<resource>%s</resource>"
441 debug("xmpp: bind -> jid");
442 srv->state = XMPP_RECV_JID;
445 if (srv->state == XMPP_RECV_JID) {
446 if (match(start, "jid")) {
447 debug("xmpp: jid -> session");
448 srv->state = XMPP_SEND_SESSION;
451 if (srv->state == XMPP_SEND_SESSION) {
452 if (net_print(&srv->net,
453 "<iq id='session' type='set' to='%s'>"
454 "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
457 debug("xmpp: session -> presence");
458 srv->state = XMPP_SEND_PRESENCE;
461 if (srv->state == XMPP_SEND_PRESENCE) {
462 if (net_print(&srv->net, "<presence/>")) {
463 debug("xmpp: presence -> join");
464 srv->state = XMPP_SEND_JOIN;
467 if (srv->state == XMPP_SEND_JOIN) {
468 for (channel_t *cur = channels; cur; cur = cur->next) {
469 if (cur->server != &srv->server)
471 xmpp_channel_t *chan = (xmpp_channel_t *)cur;
475 "<presence id='join' from='%s' to='%s/%s'>"
476 "<x xmlns='http://jabber.org/protocol/muc'/>"
478 srv->jid, chan->dest, srv->nick);
480 debug("xmpp: join -> ready");
481 srv->state = XMPP_READY;
485 xmpp_channel_t *chan = NULL;
487 if (srv->state >= XMPP_READY && idle) {
489 net_print(&srv->net, " ");
492 if (srv->state == XMPP_READY) {
493 srv->state = match(start, "iq") ? XMPP_IN_IQ :
494 match(start, "message") ? XMPP_IN_MESSAGE :
495 match(start, "presence") ? XMPP_IN_PRESENCE :
497 if (srv->state != XMPP_READY) {
498 const char *from = find_attr(attrs, "from") ?: "";
499 strncpy(srv->msg_jid, from, JID_LEN);
500 split_jid(srv->msg_jid, srv->msg_usr,
501 srv->msg_srv, srv->msg_res);
503 if (match(srv->msg_srv, srv->muc)) {
504 srv->msg_from = srv->msg_res[0] ? srv->msg_res : NULL;
505 srv->msg_chan = find_dest(srv, srv->msg_jid, 1);
507 srv->msg_from = srv->msg_usr[0] ? srv->msg_usr : NULL;
508 srv->msg_chan = find_dest(srv, srv->msg_jid, 0);
511 debug("xmpp: %s -- jid=[%s] from=[%s] chan=[%s]",
513 srv->msg_jid, srv->msg_from,
514 srv->msg_chan->channel.name);
517 if (srv->state > XMPP_READY) {
518 if (srv->msg_chan && srv->msg_chan != &srv->system)
519 chan = srv->msg_chan;
523 if (srv->state == XMPP_IN_IQ) {
524 if (match(start, "item") && chan) {
525 static char res[JID_LEN];
526 split_jid(find_attr(attrs, "jid"),
528 chan_notice(chan, "user: %s", res);
530 if (match(start, "item") && !chan) {
531 srv_notice(srv, "item: [%s] %s",
532 find_attr(attrs, "jid"),
533 find_attr(attrs, "name"));
535 if (match(start, "identity")) {
536 srv_notice(srv, "identity: %s",
537 find_attr(attrs, "name"));
539 if (match(start, "feature")) {
540 srv_notice(srv, "feature: %s",
541 find_attr(attrs, "var"));
543 if (match(start, "field")) {
544 debug("xmpp: %s -- type=[%s] label=[%s]", end,
545 find_attr(attrs, "type"),
546 find_attr(attrs, "label"));
547 if (!find_attr(attrs, "label"))
549 chan_notice(chan, "%-36s -- %s (%s)",
550 find_attr(attrs, "var"),
551 find_attr(attrs, "label"),
552 find_attr(attrs, "type"));
554 if (match(end, "title")) {
555 debug("xmpp: title -- jid=[%s]",
557 chan_notice(chan, "Title: %s", data);
559 if (match(end, "instructions")) {
560 debug("xmpp: instructions -- jid=[%s]",
562 chan_notice(chan, "%s", data);
567 if (srv->state == XMPP_IN_IQ) {
568 if (match(start, "vCard")) {
570 chan_notice(chan, "vCard for %s", chan->dest);
571 srv->state = XMPP_IN_VCARD;
574 if (srv->state == XMPP_IN_VCARD) {
575 if (end && chan && data) {
576 xmpp_user_t *usr = NULL;
577 chan_notice(chan, "%-12s -- %s", end, data);
579 usr = find_jid(srv, srv->msg_from, 1);
580 if (usr && match(end, "FN"))
581 strset(&usr->user.full, data);
583 if (match(end, "vCard")) {
584 srv->state = XMPP_IN_IQ;
589 if (srv->state == XMPP_IN_MESSAGE) {
590 if (match(start, "delay")) {
591 const char *ts = find_attr(attrs, "stamp");
594 strptime(ts, "%Y-%m-%dT%H:%M:%S", &tm);
595 srv->stamp = timegm(&tm);
598 if (match(end, "subject") && chan) {
599 strset(&chan->channel.topic, data);
601 if (match(end, "body")) {
602 strset(&srv->body, data);
604 if (match(end, "message")) {
605 debug("xmpp: body (%s) -- chan=[%s] jid=[%s] from=[%s]",
606 srv->msg_from == srv->msg_usr ? "user" : "chat" ,
607 srv->msg_chan->channel.name,
608 srv->msg_jid, srv->msg_from);
610 xmpp_user_t *usr = NULL;
612 usr = find_jid(srv, srv->msg_from, 1);
613 chat_recv(&chan->channel, &usr->user, srv->body);
614 message_t *msg = &messages[history-1];
615 msg->when = srv->stamp ?: msg->when;
618 strset(&srv->body, NULL);
623 if (srv->state == XMPP_IN_PRESENCE) {
624 static char alias[JID_LEN];
626 if (match(start, "item")) {
627 if ((jid = find_attr(attrs, "jid")))
628 strncpy(alias, jid, JID_LEN);
630 if (match(end, "presence") && chan) {
631 if (alias[0] && !srv->quiet)
632 chan_notice(chan, "%s (%s) entered room.",
633 srv->msg_from, alias);
634 else if (!srv->quiet)
635 chan_notice(chan, "%s entered room.",
642 if (srv->state == XMPP_IN_IQ ||
643 srv->state == XMPP_IN_MESSAGE ||
644 srv->state == XMPP_IN_PRESENCE) {
645 if (match(end, "iq") ||
646 match(end, "message") ||
647 match(end, "presence")) {
648 srv->state = XMPP_READY;
650 srv->msg_jid[0] = '\0';
651 srv->msg_usr[0] = '\0';
652 srv->msg_srv[0] = '\0';
653 srv->msg_res[0] = '\0';
654 srv->msg_from = NULL;
655 srv->msg_chan = NULL;
659 if (match(start, "stream:error"))
661 if (match(end, "stream:error"))
664 if (match(end, "text")) {
665 debug("xmpp: error: %s", data);
666 srv_notice(srv, "error: %s", data);
674 for (server_t *cur = servers; cur; cur = cur->next) {
675 if (cur->protocol != XMPP)
678 xmpp_server_t *srv = (xmpp_server_t*)cur;
679 srv->system.channel.server = &srv->server;
680 srv->system.channel.name = srv->server.name;
681 srv_notice(srv, "XMPP Server: %s", srv->server.name);
686 srv->srv = strcopy(srv->host);
688 error("jid is required");
692 xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
694 for (channel_t *cur = channels; cur; cur = cur->next) {
695 if (cur->server->protocol != XMPP)
698 xmpp_channel_t *chan = (xmpp_channel_t*)cur;
699 xmpp_server_t *srv = (xmpp_server_t*)cur->server;
701 chan->room = strcopy(cur->name);
702 snprintf(chan->dest, JID_LEN, "%s@%s",
703 chan->room, srv->muc);
707 server_t *xmpp_server(void)
709 return new0(xmpp_server_t);
712 user_t *xmpp_user(void)
714 return new0(xmpp_user_t);
717 channel_t *xmpp_channel(void)
719 return new0(xmpp_channel_t);
722 void xmpp_config(server_t *server, channel_t *channel,
723 const char *group, const char *name,
724 const char *key, const char *value)
726 xmpp_server_t *srv = (xmpp_server_t*)server;
727 xmpp_channel_t *chan = (xmpp_channel_t*)channel;
730 if (match(key, "connect"))
731 srv->connect = get_bool(value);
732 else if (match(key, "timeout"))
733 srv->timeout = get_number(value);
734 else if (match(key, "host"))
735 srv->host = get_string(value);
736 else if (match(key, "port"))
737 srv->port = get_number(value);
738 else if (match(key, "srv"))
739 srv->srv = get_string(value);
740 else if (match(key, "muc"))
741 srv->muc = get_string(value);
742 else if (match(key, "nick"))
743 srv->nick = get_string(value);
744 else if (match(key, "jid"))
745 srv->jid = get_string(value);
746 else if (match(key, "user"))
747 srv->user = get_string(value);
748 else if (match(key, "pass"))
749 srv->pass = get_string(value);
750 else if (match(key, "quiet"))
751 srv->quiet = get_bool(value);
754 if (match(key, "room"))
755 chan->room = get_string(value);
756 else if (match(key, "join"))
757 chan->join = get_bool(value);
761 void xmpp_send(channel_t *channel, const char *text)
763 xmpp_channel_t *chan = (xmpp_channel_t*)channel;
764 xmpp_server_t *srv = (xmpp_server_t*)channel->server;
767 /* Handle commands */
768 if (text[0] == '/') {
769 if (prefix(text, "/items", &arg)) {
771 "<iq id='items' type='get' from='%s' to='%s'>"
772 "<query xmlns='http://jabber.org/protocol/disco#items'/>"
774 srv->jid, arg ?: srv->srv);
776 else if (prefix(text, "/info", &arg)) {
778 "<iq id='info' type='get' from='%s' to='%s'>"
779 "<query xmlns='http://jabber.org/protocol/disco#info'/>"
781 srv->jid, arg ?: srv->srv);
783 else if (prefix(text, "/names", &arg)) {
785 chan = find_dest(srv, arg, 1);
786 if (chan == &srv->system) {
787 chan_notice(chan, "Cannot get names from server");
791 "<iq id='list' type='get' from='%s' to='%s'>"
792 "<query xmlns='http://jabber.org/protocol/disco#items'/>"
794 srv->jid, chan->dest);
796 else if (prefix(text, "/join", &arg)) {
798 chan_notice(chan, "usage: /join <channel>");
802 "<presence id='join' from='%s' to='%s/%s'>"
803 "<x xmlns='http://jabber.org/protocol/muc'/>"
805 srv->jid, chan->dest, srv->nick);
806 chan = find_dest(srv, arg, 1);
807 chan_notice(chan, "Room: %s", arg);
809 else if (prefix(text, "/config", &arg)) {
811 chan_notice(chan, "Unimplemented: /config <arg>");
815 "<iq id='config' type='get' from='%s' to='%s'>"
816 "<query xmlns='http://jabber.org/protocol/muc#owner'/>"
818 srv->jid, chan->dest);
820 else if (prefix(text, "/query", &arg)) {
822 chan_notice(chan, "usage: /query <user>");
825 chan = find_dest(srv, arg, 0);
826 chan_notice(chan, "User: %s", arg);
828 else if (prefix(text, "/vcard", &arg)) {
830 chan = find_dest(srv, arg, 0);
833 "<iq id='vcard' type='get' from='%s' to='%s'>"
834 "<vCard xmlns='vcard-temp'/>"
836 srv->jid, chan->dest);
839 chan_notice(chan, "Unknown command %s", text);
842 debug("message: [%s]", text);
843 if (chan == &srv->system) {
844 chan_notice(chan, "Cannot send to server");
846 else if (!chan->dest) {
847 chan_notice(chan, "No destination for message");
849 else if (chan->room) {
851 "<message id='chat%d' from='%s' to='%s' type='groupchat'>"
854 srv->id++, srv->jid, chan->dest, text);
857 "<message id='chat%d' from='%s' to='%s'>"
860 srv->id++, srv->jid, chan->dest, text);
861 chat_recv(channel, &srv->myself.user, text);