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;
110 char msg_jid[JID_LEN];
111 char msg_usr[JID_LEN];
112 char msg_srv[JID_LEN];
113 char msg_res[JID_LEN];
115 xmpp_channel_t *msg_chan;
118 /* Helper functions */
119 static void srv_notice(xmpp_server_t *srv, const char *fmt, ...)
121 static char buf[1024];
125 vsnprintf(buf, sizeof(buf), fmt, ap);
128 chat_recv(&srv->system.channel, NULL, buf);
131 static void chan_notice(xmpp_channel_t *chan, const char *fmt, ...)
133 static char buf[1024];
137 vsnprintf(buf, sizeof(buf), fmt, ap);
140 chat_recv(&chan->channel, NULL, buf);
143 static void split_jid(const char *jid, char *usr, char *srv, char *res)
148 if (usr) usr[0] = '\0';
149 if (srv) srv[0] = '\0';
150 if (res) res[0] = '\0';
152 for (int i = 0; jid && jid[i]; i++) {
163 if (ptr && (pos+1) < JID_LEN) {
169 //debug("JID: '%s' usr=[%s] srv=[%s] res=[%s]",
170 // jid, usr, srv, res);
173 static xmpp_channel_t *find_dest(xmpp_server_t *srv,
174 const char *jid, int is_muc)
176 static char jid_usr[JID_LEN];
177 static char jid_srv[JID_LEN];
178 static char dest[JID_LEN];
179 xmpp_channel_t *chan;
181 split_jid(jid, jid_usr, jid_srv, NULL);
182 snprintf(dest, JID_LEN, "%s@%s", jid_usr,
183 jid_srv[0] ? jid_srv :
184 is_muc ? srv->muc : srv->srv);
186 /* Server channels */
187 if (match(jid, srv->srv))
190 /* Find existing channels */
191 for (channel_t *cur = channels; cur; cur = cur->next) {
192 if (cur->server != &srv->server)
194 chan = (xmpp_channel_t *)cur;
195 if (match(chan->dest, dest))
199 /* Create a new channel */
200 chan = new0(xmpp_channel_t);
201 chan->channel.server = &srv->server;
202 chan->channel.name = strcopy(jid_usr);
203 strncpy(chan->dest, dest, JID_LEN);
204 add_channel(&chan->channel);
208 static xmpp_user_t *find_jid(xmpp_server_t *srv, const char *jid, int create)
212 /* Find existing users */
213 for (user_t *cur = users; cur; cur = cur->next) {
214 if (cur->server != &srv->server)
216 usr = (xmpp_user_t *)cur;
217 if (match(usr->jid, jid))
221 /* Create a new user */
222 usr = new0(xmpp_user_t);
223 usr->user.server = &srv->server;
224 usr->user.name = strcopy(jid);
225 strncpy(usr->jid, jid, JID_LEN);
226 add_user(&usr->user);
230 static const char *find_attr(const char **attrs, const char *name)
232 for (int i = 0; attrs[i] && attrs[i+1]; i += 2)
233 if (match(attrs[i+0], name))
238 /* Callback functions */
239 static void xmpp_run(xmpp_server_t *srv, int idle,
240 const char *start, const char **attrs,
241 const char *end, const char *data);
243 static void on_start(void *_srv, const char *tag, const char **attrs)
245 xmpp_server_t *srv = _srv;
246 xmpp_run(srv, 0, tag, attrs, NULL, reset(&srv->buf));
249 static void on_data(void *_srv, const char *data, int len)
251 xmpp_server_t *srv = _srv;
252 append(&srv->buf, data, len);
255 static void on_end(void *_srv, const char *tag)
257 xmpp_server_t *srv = _srv;
258 xmpp_run(srv, 0, NULL, NULL, tag, reset(&srv->buf));
261 static void on_send(void *_srv)
263 xmpp_server_t *srv = _srv;
264 xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
267 static void on_recv(void *_srv, char *buf, int len)
269 xmpp_server_t *srv = _srv;
271 XML_Parse(srv->expat, buf, len, 0);
272 xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
275 static void on_err(void *_srv, int errno)
277 xmpp_server_t *srv = _srv;
278 xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
281 static void on_timer(void *_srv)
284 xmpp_server_t *srv = _srv;
285 while (read(srv->timer, &buf, sizeof(buf)) > 0)
286 xmpp_run(srv, 1, NULL, NULL, NULL, NULL);
289 /* XMPP State machine */
290 static void xmpp_run(xmpp_server_t *srv, int idle,
291 const char *start, const char **attrs,
292 const char *end, const char *data)
296 debug("%*s \"%s\"", srv->indent*4, "", data);
298 debug("%*s<%s>", srv->indent*4, "", start);
299 for (int i = 0; attrs[i] && attrs[i+1]; i += 2) {
300 debug("%*s%s=\"%s\"%s",
302 attrs[i+0], attrs[i+1],
303 attrs[i+2] ? "" : ">");
311 /* Connection Handling */
312 if (srv->state == XMPP_CONNECT && !start && !end) {
313 srv->net.send = on_send;
314 srv->net.recv = on_recv;
315 srv->net.err = on_err;
317 net_open(&srv->net, srv->host, srv->port);
319 srv->timer = timerfd_create(CLOCK_MONOTONIC,
320 TFD_NONBLOCK|TFD_CLOEXEC);
322 error("creating timer fd");
323 struct timespec tspec = {srv->timeout, 0};
324 struct itimerspec itspec = {tspec, tspec};
325 timerfd_settime(srv->timer, 0, &itspec, NULL);
326 poll_add(&srv->poll, srv->timer, on_timer, srv);
327 poll_ctl(&srv->poll, 1, 0, 1);
329 if (!(srv->expat = XML_ParserCreate(NULL)))
330 error("Error creating XML parser");
331 XML_SetUserData(srv->expat, srv);
332 XML_SetStartElementHandler(srv->expat, on_start);
333 XML_SetEndElementHandler(srv->expat, on_end);
334 XML_SetCharacterDataHandler(srv->expat, on_data);
336 debug("xmpp: connect -> stream");
337 srv->state = XMPP_SEND_STREAM;
339 if (srv->state == XMPP_ENCRYPT && !start && !end) {
340 net_encrypt(&srv->net, srv->noverify ? NET_NOVERIFY : 0);
342 if (!(XML_ParserReset(srv->expat, NULL)))
343 error("Error resetting XML parser");
344 XML_SetUserData(srv->expat, srv);
345 XML_SetStartElementHandler(srv->expat, on_start);
346 XML_SetEndElementHandler(srv->expat, on_end);
347 XML_SetCharacterDataHandler(srv->expat, on_data);
349 debug("xmpp: encrypt -> stream");
350 srv->state = XMPP_SEND_STREAM;
352 if (srv->state == XMPP_RESTART && !start && !end) {
353 if (!(XML_ParserReset(srv->expat, NULL)))
354 error("Error resetting XML parser");
355 XML_SetUserData(srv->expat, srv);
356 XML_SetStartElementHandler(srv->expat, on_start);
357 XML_SetEndElementHandler(srv->expat, on_end);
358 XML_SetCharacterDataHandler(srv->expat, on_data);
360 debug("xmpp: restart -> stream");
361 srv->state = XMPP_SEND_STREAM;
365 if (srv->state == XMPP_SEND_STREAM) {
366 if (net_print(&srv->net,
367 "<?xml version='1.0'?>"
373 " xmlns='jabber:client'"
374 " xmlns:stream='http://etherx.jabber.org/streams'>",
375 srv->jid, srv->srv)) {
376 debug("xmpp: stream -> features");
377 srv->state = XMPP_RECV_FEATURES;
380 if (srv->state == XMPP_RECV_FEATURES) {
381 if (match(start, "starttls")) {
382 debug("xmpp: features -> starttls");
383 srv->state = XMPP_SEND_STARTTLS;
385 if (match(start, "mechanisms")) {
386 debug("xmpp: features -> auth");
387 srv->state = XMPP_SEND_AUTH;
389 if (match(start, "bind")) {
390 debug("xmpp: features -> bind");
391 srv->state = XMPP_SEND_BIND;
396 if (srv->state == XMPP_SEND_STARTTLS) {
397 if (net_print(&srv->net,
398 "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>")) {
399 debug("xmpp: startls -> proceed");
400 srv->state = XMPP_RECV_PROCEED;
403 if (srv->state == XMPP_RECV_PROCEED) {
404 if (match(start, "proceed")) {
405 debug("xmpp: proceed -> encrypt");
406 srv->state = XMPP_ENCRYPT;
411 if (srv->state == XMPP_SEND_AUTH) {
412 static char plain[AUTH_LEN];
413 static char coded[AUTH_LEN];
415 len = snprintf(plain, AUTH_LEN, "%s%c%s%c%s",
416 srv->user, '\0', srv->user, '\0', srv->pass);
417 len = base64(plain, len, coded, AUTH_LEN);
418 if (net_print(&srv->net,
420 " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'"
421 " mechanism='PLAIN'>%.*s</auth>",
423 debug("xmpp: auth -> success");
424 srv->state = XMPP_RECV_SUCCESS;
427 if (srv->state == XMPP_RECV_SUCCESS) {
428 if (match(start, "success")) {
429 debug("xmpp: success -> restart");
430 srv->state = XMPP_RESTART;
435 if (srv->state == XMPP_SEND_BIND) {
436 const char *resource = srv->jid;
437 while (*resource && *resource != '/')
439 while (*resource && *resource == '/')
441 if (net_print(&srv->net,
442 "<iq id='bind' type='set'>"
443 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
444 "<resource>%s</resource>"
448 debug("xmpp: bind -> jid");
449 srv->state = XMPP_RECV_JID;
452 if (srv->state == XMPP_RECV_JID) {
453 if (match(start, "jid")) {
454 debug("xmpp: jid -> session");
455 srv->state = XMPP_SEND_SESSION;
458 if (srv->state == XMPP_SEND_SESSION) {
459 if (net_print(&srv->net,
460 "<iq id='session' type='set' to='%s'>"
461 "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
464 debug("xmpp: session -> presence");
465 srv->state = XMPP_SEND_PRESENCE;
468 if (srv->state == XMPP_SEND_PRESENCE) {
469 if (net_print(&srv->net, "<presence/>")) {
470 debug("xmpp: presence -> join");
471 srv->state = XMPP_SEND_JOIN;
474 if (srv->state == XMPP_SEND_JOIN) {
475 for (channel_t *cur = channels; cur; cur = cur->next) {
476 if (cur->server != &srv->server)
478 xmpp_channel_t *chan = (xmpp_channel_t *)cur;
482 "<presence id='join' from='%s' to='%s/%s'>"
483 "<x xmlns='http://jabber.org/protocol/muc'/>"
485 srv->jid, chan->dest, srv->nick);
487 debug("xmpp: join -> ready");
488 srv->state = XMPP_READY;
492 xmpp_channel_t *chan = NULL;
494 if (srv->state >= XMPP_READY && idle) {
496 net_print(&srv->net, " ");
499 if (srv->state == XMPP_READY) {
500 srv->state = match(start, "iq") ? XMPP_IN_IQ :
501 match(start, "message") ? XMPP_IN_MESSAGE :
502 match(start, "presence") ? XMPP_IN_PRESENCE :
504 if (srv->state != XMPP_READY) {
505 const char *from = find_attr(attrs, "from") ?: "";
506 strncpy(srv->msg_jid, from, JID_LEN);
507 split_jid(srv->msg_jid, srv->msg_usr,
508 srv->msg_srv, srv->msg_res);
510 if (match(srv->msg_srv, srv->muc)) {
511 srv->msg_from = srv->msg_res[0] ? srv->msg_res : NULL;
512 srv->msg_chan = find_dest(srv, srv->msg_jid, 1);
514 srv->msg_from = srv->msg_usr[0] ? srv->msg_usr : NULL;
515 srv->msg_chan = find_dest(srv, srv->msg_jid, 0);
518 debug("xmpp: %s -- jid=[%s] from=[%s] chan=[%s]",
520 srv->msg_jid, srv->msg_from,
521 srv->msg_chan->channel.name);
524 if (srv->state > XMPP_READY) {
525 if (srv->msg_chan && srv->msg_chan != &srv->system)
526 chan = srv->msg_chan;
530 if (srv->state == XMPP_IN_IQ) {
531 if (match(start, "item") && chan) {
532 static char res[JID_LEN];
533 split_jid(find_attr(attrs, "jid"),
535 chan_notice(chan, "user: %s", res);
537 if (match(start, "item") && !chan) {
538 srv_notice(srv, "item: [%s] %s",
539 find_attr(attrs, "jid"),
540 find_attr(attrs, "name"));
542 if (match(start, "identity")) {
543 srv_notice(srv, "identity: %s",
544 find_attr(attrs, "name"));
546 if (match(start, "feature")) {
547 srv_notice(srv, "feature: %s",
548 find_attr(attrs, "var"));
550 if (match(start, "field")) {
551 debug("xmpp: %s -- type=[%s] label=[%s]", end,
552 find_attr(attrs, "type"),
553 find_attr(attrs, "label"));
554 if (!find_attr(attrs, "label"))
556 chan_notice(chan, "%-36s -- %s (%s)",
557 find_attr(attrs, "var"),
558 find_attr(attrs, "label"),
559 find_attr(attrs, "type"));
561 if (match(end, "title")) {
562 debug("xmpp: title -- jid=[%s]",
564 chan_notice(chan, "Title: %s", data);
566 if (match(end, "instructions")) {
567 debug("xmpp: instructions -- jid=[%s]",
569 chan_notice(chan, "%s", data);
574 if (srv->state == XMPP_IN_IQ) {
575 if (match(start, "vCard")) {
577 chan_notice(chan, "vCard for %s", chan->dest);
578 srv->state = XMPP_IN_VCARD;
581 if (srv->state == XMPP_IN_VCARD) {
582 if (end && chan && data) {
583 xmpp_user_t *usr = NULL;
584 chan_notice(chan, "%-12s -- %s", end, data);
586 usr = find_jid(srv, srv->msg_from, 1);
587 if (usr && match(end, "FN"))
588 strset(&usr->user.full, data);
590 if (match(end, "vCard")) {
591 srv->state = XMPP_IN_IQ;
596 if (srv->state == XMPP_IN_MESSAGE) {
597 if (match(start, "delay")) {
598 const char *ts = find_attr(attrs, "stamp");
601 strptime(ts, "%Y-%m-%dT%H:%M:%S", &tm);
602 srv->stamp = timegm(&tm);
605 if (match(end, "subject") && chan) {
606 strset(&chan->channel.topic, data);
608 if (match(end, "body")) {
609 strset(&srv->body, data);
611 if (match(end, "message")) {
612 debug("xmpp: body (%s) -- chan=[%s] jid=[%s] from=[%s]",
613 srv->msg_from == srv->msg_usr ? "user" : "chat" ,
614 srv->msg_chan->channel.name,
615 srv->msg_jid, srv->msg_from);
617 xmpp_user_t *usr = NULL;
619 usr = find_jid(srv, srv->msg_from, 1);
620 chat_recv(&chan->channel, &usr->user, srv->body);
621 message_t *msg = &messages[history-1];
622 msg->when = srv->stamp ?: msg->when;
625 strset(&srv->body, NULL);
630 if (srv->state == XMPP_IN_PRESENCE) {
631 static char alias[JID_LEN];
633 if (match(start, "item")) {
634 if ((jid = find_attr(attrs, "jid")))
635 strncpy(alias, jid, JID_LEN);
637 if (match(end, "presence") && chan) {
638 if (alias[0] && !srv->quiet)
639 chan_notice(chan, "%s (%s) entered room.",
640 srv->msg_from, alias);
641 else if (!srv->quiet)
642 chan_notice(chan, "%s entered room.",
649 if (srv->state == XMPP_IN_IQ ||
650 srv->state == XMPP_IN_MESSAGE ||
651 srv->state == XMPP_IN_PRESENCE) {
652 if (match(end, "iq") ||
653 match(end, "message") ||
654 match(end, "presence")) {
655 srv->state = XMPP_READY;
657 srv->msg_jid[0] = '\0';
658 srv->msg_usr[0] = '\0';
659 srv->msg_srv[0] = '\0';
660 srv->msg_res[0] = '\0';
661 srv->msg_from = NULL;
662 srv->msg_chan = NULL;
666 if (match(start, "stream:error"))
668 if (match(end, "stream:error"))
671 if (match(end, "text")) {
672 debug("xmpp: error: %s", data);
673 srv_notice(srv, "error: %s", data);
681 for (server_t *cur = servers; cur; cur = cur->next) {
682 if (cur->protocol != XMPP)
685 xmpp_server_t *srv = (xmpp_server_t*)cur;
686 srv->system.channel.server = &srv->server;
687 srv->system.channel.name = srv->server.name;
688 srv_notice(srv, "XMPP Server: %s", srv->server.name);
693 srv->srv = strcopy(srv->host);
695 error("jid is required");
699 xmpp_run(srv, 0, NULL, NULL, NULL, NULL);
701 for (channel_t *cur = channels; cur; cur = cur->next) {
702 if (cur->server->protocol != XMPP)
705 xmpp_channel_t *chan = (xmpp_channel_t*)cur;
706 xmpp_server_t *srv = (xmpp_server_t*)cur->server;
708 chan->room = strcopy(cur->name);
709 snprintf(chan->dest, JID_LEN, "%s@%s",
710 chan->room, srv->muc);
714 void xmpp_config(server_t *server, channel_t *channel,
715 const char *group, const char *name,
716 const char *key, const char *value)
718 xmpp_server_t *srv = (xmpp_server_t*)server;
719 xmpp_channel_t *chan = (xmpp_channel_t*)channel;
721 if (match(group, "server")) {
722 if (match(key, "protocol")) {
723 xmpp_server_t *srv = new0(xmpp_server_t);
724 srv->server.protocol = XMPP;
725 srv->server.name = strcopy(get_name(name));
726 add_server(&srv->server);
728 else if (match(key, "connect"))
729 srv->connect = get_bool(value);
730 else if (match(key, "timeout"))
731 srv->timeout = get_number(value);
732 else if (match(key, "noverify"))
733 srv->noverify = get_bool(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);
753 if (match(group, "channel")) {
754 if (match(key, "server")) {
755 xmpp_channel_t *chan = new0(xmpp_channel_t);
756 chan->channel.server = &srv->server;
757 chan->channel.name = strcopy(get_name(name));
758 add_channel(&chan->channel);
760 else if (match(key, "room"))
761 chan->room = get_string(value);
762 else if (match(key, "join"))
763 chan->join = get_bool(value);
767 void xmpp_send(channel_t *channel, const char *text)
769 xmpp_channel_t *chan = (xmpp_channel_t*)channel;
770 xmpp_server_t *srv = (xmpp_server_t*)channel->server;
773 /* Handle commands */
774 if (text[0] == '/') {
775 if (prefix(text, "/items", &arg)) {
777 "<iq id='items' type='get' from='%s' to='%s'>"
778 "<query xmlns='http://jabber.org/protocol/disco#items'/>"
780 srv->jid, arg ?: srv->srv);
782 else if (prefix(text, "/info", &arg)) {
784 "<iq id='info' type='get' from='%s' to='%s'>"
785 "<query xmlns='http://jabber.org/protocol/disco#info'/>"
787 srv->jid, arg ?: srv->srv);
789 else if (prefix(text, "/names", &arg)) {
791 chan = find_dest(srv, arg, 1);
792 if (chan == &srv->system) {
793 chan_notice(chan, "Cannot get names from server");
797 "<iq id='list' type='get' from='%s' to='%s'>"
798 "<query xmlns='http://jabber.org/protocol/disco#items'/>"
800 srv->jid, chan->dest);
802 else if (prefix(text, "/join", &arg)) {
804 chan_notice(chan, "usage: /join <channel>");
808 "<presence id='join' from='%s' to='%s/%s'>"
809 "<x xmlns='http://jabber.org/protocol/muc'/>"
811 srv->jid, chan->dest, srv->nick);
812 chan = find_dest(srv, arg, 1);
813 chan_notice(chan, "Room: %s", arg);
815 else if (prefix(text, "/config", &arg)) {
817 chan_notice(chan, "Unimplemented: /config <arg>");
821 "<iq id='config' type='get' from='%s' to='%s'>"
822 "<query xmlns='http://jabber.org/protocol/muc#owner'/>"
824 srv->jid, chan->dest);
826 else if (prefix(text, "/query", &arg)) {
828 chan_notice(chan, "usage: /query <user>");
831 chan = find_dest(srv, arg, 0);
832 chan_notice(chan, "User: %s", arg);
834 else if (prefix(text, "/vcard", &arg)) {
836 chan = find_dest(srv, arg, 0);
839 "<iq id='vcard' type='get' from='%s' to='%s'>"
840 "<vCard xmlns='vcard-temp'/>"
842 srv->jid, chan->dest);
845 chan_notice(chan, "Unknown command %s", text);
848 debug("message: [%s]", text);
849 if (chan == &srv->system) {
850 chan_notice(chan, "Cannot send to server");
852 else if (!chan->dest) {
853 chan_notice(chan, "No destination for message");
855 else if (chan->room) {
857 "<message id='chat%d' from='%s' to='%s' type='groupchat'>"
860 srv->id++, srv->jid, chan->dest, text);
863 "<message id='chat%d' from='%s' to='%s'>"
866 srv->id++, srv->jid, chan->dest, text);
867 chat_recv(channel, &srv->myself.user, text);