]> Pileus Git - ~andy/lamechat/commitdiff
XMPP MUC
authorAndy Spencer <andy753421@gmail.com>
Sun, 24 Sep 2017 01:11:04 +0000 (01:11 +0000)
committerAndy Spencer <andy753421@gmail.com>
Sun, 24 Sep 2017 01:11:04 +0000 (01:11 +0000)
chat.c
chat.h
util.c
util.h
view.c
xmpp.c

diff --git a/chat.c b/chat.c
index b4bfaa4e6eddae747fd9cc76cd7aca722124c771..e35271a9b6470daea18c1a8ebf912c6b613443eb 100644 (file)
--- a/chat.c
+++ b/chat.c
@@ -15,7 +15,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <stdarg.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include <time.h>
 
@@ -49,6 +51,18 @@ void chat_config(const char *group, const char *name, const char *key, const cha
        xmpp_config(group, name, key, value);
 }
 
+void chat_notice(const char *channel, const char *from, const char *fmt, ...)
+{
+       static char buf[1024];
+
+       va_list ap;
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+
+       chat_recv(channel, from, buf);
+}
+
 void chat_recv(const char *channel, const char *from, const char *msg)
 {
        append(&log_buf, NULL, sizeof(log_t));
diff --git a/chat.h b/chat.h
index 5779d4fc00e78f70e4657464160d47fbf1e8e3ab..746999e4f26f61dde6ddcb7f9dcd9f52b821b855 100644 (file)
--- a/chat.h
+++ b/chat.h
@@ -36,6 +36,7 @@ extern int    chat_len;
 /* Chat functions */
 void chat_init(void);
 void chat_config(const char *group, const char *name, const char *key, const char *value);
+void chat_notice(const char *channel, const char *from, const char *fmt, ...);
 void chat_recv(const char *channel, const char *from, const char *msg);
 void chat_send(const char *channel, const char *msg);
 void chat_exit(void);
diff --git a/util.c b/util.c
index a1ce4b5dc03a08bd7c0c43d43b112f07f4b202bc..d2e1f2f9a7579ee18010c12c1650459225525bfc 100644 (file)
--- a/util.c
+++ b/util.c
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define _GNU_SOURCE
 #define _XOPEN_SOURCE
 #define _XOPEN_SOURCE_EXTENDED
 #define _POSIX_C_SOURCE 200100
@@ -111,6 +112,25 @@ int match(const char *a, const char *b)
        return !strcmp(a, b);
 }
 
+int prefix(const char *str, const char *prefix, const char **suffix)
+{
+       while (*str && *prefix) {
+               if (*str != *prefix)
+                       return 0;
+               str++;
+               prefix++;
+       }
+       if (*prefix)
+               return 0;
+       if (*str && *str != ' ')
+               return 0;
+       while (*str && *str == ' ')
+               str++;
+       if (suffix)
+               *suffix = *str ? str : NULL;
+       return 1;
+}
+
 /* Memory functions */
 void *alloc0(int size)
 {
diff --git a/util.h b/util.h
index 95a20988f7a0f8a3b9b18a195e39db1c1e9071a3..5be3f9922995d41a756a847fdc236bd21cddb946 100644 (file)
--- a/util.h
+++ b/util.h
@@ -47,6 +47,7 @@ void util_init(void);
 void strsub(char *str, char find, char repl);
 char *strcopy(const char *str);
 int match(const char *a, const char *b);
+int prefix(const char *str, const char *prefix, const char **suffix);
 
 /* Memory functions */
 void *alloc0(int size);
diff --git a/view.c b/view.c
index 498864863a36f533a45eee27ff6ed2acd53aff38..12a386b68d235e5905a9de9768a7ff3e87b32bd8 100644 (file)
--- a/view.c
+++ b/view.c
@@ -91,9 +91,20 @@ static void print_msg(log_t *log, int *row, int print)
        time_t timep = log->when;
        struct tm *tm = localtime(&timep);
 
-       snprintf(buf, sizeof(buf), "%02d:%02d [%s] %s: ",
-                       tm->tm_hour, tm->tm_min,
-                       log->channel, log->from);
+       if (log->channel && log->from)
+               snprintf(buf, sizeof(buf), "%02d:%02d [%s] %s: ",
+                               tm->tm_hour, tm->tm_min,
+                               log->channel, log->from);
+       else if (log->channel)
+               snprintf(buf, sizeof(buf), "%02d:%02d [%s] *** ",
+                               tm->tm_hour, tm->tm_min, log->channel);
+       else if (log->from)
+               snprintf(buf, sizeof(buf), "%02d:%02d *** %s: ",
+                               tm->tm_hour, tm->tm_min, log->from);
+       else
+               snprintf(buf, sizeof(buf), "%02d:%02d *** ",
+                               tm->tm_hour, tm->tm_min);
+
 
        while (*hdr)
                print_word(&hdr, row, &col, indent, print);
diff --git a/xmpp.c b/xmpp.c
index 5d16ca000bc4d99d011dc6009c30f5e10c7a04d8..0656b9264f11916b66277cd2fefede52477d997d 100644 (file)
--- a/xmpp.c
+++ b/xmpp.c
@@ -45,6 +45,7 @@ typedef enum {
        XMPP_RECV_SUCCESS,
        XMPP_SEND_BIND,
        XMPP_RECV_JID,
+       XMPP_PRESENCE,
        XMPP_ENCRYPT,
        XMPP_RESTART,
        XMPP_READY,
@@ -56,6 +57,8 @@ typedef struct xmpp_server_t {
        int          connect;
        const char  *host;
        int          port;
+       const char  *muc;
+       const char  *nick;
        const char  *jid;
        const char  *user;
        const char  *pass;
@@ -66,6 +69,8 @@ typedef struct xmpp_server_t {
        buf_t        buf;
        int          indent;
 
+       int          in_error;
+
        struct xmpp_server_t *next;
 } xmpp_server_t;
 
@@ -82,6 +87,14 @@ static xmpp_server_t  *servers;
 static xmpp_channel_t *channels;
 
 /* Local functions */
+const char *find_attr(const char **attrs, const char *name)
+{
+       for (int i = 0; attrs[i] && attrs[i+1]; i += 2)
+               if (match(attrs[i+0], name))
+                       return attrs[i+1];
+       return NULL;
+}
+
 static xmpp_server_t *find_server(const char *name, int create)
 {
        xmpp_server_t *cur = NULL, *last = NULL;
@@ -162,15 +175,34 @@ static void on_start(void *_srv, const char *tag, const char **attrs)
        }
        if (srv->state == XMPP_RECV_JID) {
                if (match(tag, "jid")) {
-                       debug("xmpp: jid -> ready");
-                       srv->state = XMPP_READY;
+                       debug("xmpp: jid -> presence");
+                       srv->state = XMPP_PRESENCE;
                }
        }
+
+       /* Info queries */
+       if (srv->state == XMPP_READY) {
+               if (match(tag, "item"))
+                       chat_notice(NULL, NULL, "item: [%s] %s",
+                                       find_attr(attrs, "jid"),
+                                       find_attr(attrs, "name"));
+               if (match(tag, "identity"))
+                       chat_notice(NULL, NULL, "identity: %s",
+                                       find_attr(attrs, "name"));
+               if (match(tag, "feature"))
+                       chat_notice(NULL, NULL, "feature: %s",
+                                       find_attr(attrs, "var"));
+       }
+
+       /* Error handling */
+       if (match(tag, "stream:error"))
+               srv->in_error = 1;
 }
 
 static void on_end(void *_srv, const char *tag)
 {
        xmpp_server_t *srv = _srv;
+       const char *data = srv->buf.data;
 
        /* Debug print */
        if (srv->buf.len) {
@@ -188,6 +220,16 @@ static void on_end(void *_srv, const char *tag)
                        chat_recv("#test", NULL, data);
                }
        }
+
+       /* Error handling */
+       if (match(tag, "stream:error"))
+               srv->in_error = 0;
+       if (srv->in_error) {
+               if (match(tag, "text")) {
+                       debug("xmpp: error: %s", data);
+                       chat_notice(NULL, NULL, "error: %s", data);
+               }
+       }
 }
 
 static void on_data(void *_srv, const char *data, int len)
@@ -264,6 +306,18 @@ output:
                        srv->state = XMPP_RECV_JID;
                }
        }
+       if (srv->state == XMPP_PRESENCE) {
+               for (xmpp_channel_t *chan = channels; chan; chan = chan->next) {
+                       if (!chan->join)
+                               continue;
+                       net_print(&srv->net,
+                               "<presence id='join' from='%s' to='%s@%s/%s'>"
+                               "<x xmlns='http://jabber.org/protocol/muc'/>"
+                               "</presence>",
+                               srv->jid, chan->channel, srv->muc, srv->nick);
+               }
+               srv->state = XMPP_READY;
+       }
        if (srv->state == XMPP_ENCRYPT) {
                /* Encrypt connection */
                net_encrypt(&srv->net);
@@ -348,6 +402,10 @@ void xmpp_config(const char *group, const char *name, const char *key, const cha
                                srv->host = get_string(value);
                        else if (match(key, "port"))
                                srv->port = get_number(value);
+                       else if (match(key, "muc"))
+                               srv->muc = get_string(value);
+                       else if (match(key, "nick"))
+                               srv->nick = get_string(value);
                        else if (match(key, "jid"))
                                srv->jid = get_string(value);
                        else if (match(key, "user"))
@@ -371,6 +429,8 @@ void xmpp_config(const char *group, const char *name, const char *key, const cha
 
 void xmpp_send(const char *channel, const char *msg)
 {
+       const char *arg;
+
        xmpp_channel_t *chan = find_channel(channel, 0);
        if (!chan)
                return;
@@ -378,9 +438,51 @@ void xmpp_send(const char *channel, const char *msg)
        if (!srv || !srv->protocol)
                return;
 
-       net_print(&srv->net,
-               "<message to='%s'><body>%s</body></message>",
-               "andy@pileus.org", msg);
+       /* Handle commands */
+       if (msg[0] == '/') {
+               if (prefix(msg, "/items", &arg)) {
+                       net_print(&srv->net,
+                               "<iq id='items' type='get' from='%s' to='%s'>"
+                               "<query xmlns='http://jabber.org/protocol/disco#items' />"
+                               "</iq>",
+                               srv->jid, arg ?: srv->host);
+               }
+               else if (prefix(msg, "/info", &arg)) {
+                       net_print(&srv->net,
+                               "<iq id='info' type='get' from='%s' to='%s'>"
+                               "<query xmlns='http://jabber.org/protocol/disco#info' />"
+                               "</iq>",
+                               srv->jid, arg ?: srv->host);
+               }
+               else if (prefix(msg, "/list", &arg)) {
+                       net_print(&srv->net,
+                               "<iq id='list' type='get' from='%s' to='%s'>"
+                               "<query xmlns='http://jabber.org/protocol/disco#items' />"
+                               "</iq>",
+                               srv->jid, arg ?: srv->muc);
+               }
+               else if (prefix(msg, "/join", &arg)) {
+                       if (!arg) {
+                               chat_notice(NULL, NULL, "usage: /join <channel>");
+                               return;
+                       }
+                       net_print(&srv->net,
+                               "<presence id='join' from='%s' to='%s@%s/%s'>"
+                               "<x xmlns='http://jabber.org/protocol/muc'/>"
+                               "</presence>",
+                               srv->jid, arg, srv->muc, srv->nick);
+               }
+               else {
+                       debug("unknown: [%s]", msg);
+                       chat_notice(NULL, NULL,
+                               "unknown command %s", msg);
+               }
+       } else {
+               debug("message: [%s]", msg);
+               net_print(&srv->net,
+                       "<message to='%s'><body>%s</body></message>",
+                       "andy@pileus.org", msg);
+       }
 }
 
 void xmpp_exit(void)