]> Pileus Git - ~andy/lamechat/commitdiff
Fixup commands.
authorAndy Spencer <andy753421@gmail.com>
Thu, 19 Oct 2017 07:08:40 +0000 (07:08 +0000)
committerAndy Spencer <andy753421@gmail.com>
Thu, 19 Oct 2017 09:16:14 +0000 (09:16 +0000)
chat.c
chat.h
irc.c
irc.h [deleted file]
view.c
xmpp.c

diff --git a/chat.c b/chat.c
index d59abdad57f965e08642f76c7720538b9cd6cb8f..e099453c0f5e3d65b4d68decebc79f725bc0d7d6 100644 (file)
--- a/chat.c
+++ b/chat.c
@@ -210,25 +210,14 @@ void chat_recv(channel_t *channel, const char *from, const char *text)
 
 void chat_send(channel_t *channel, const char *text)
 {
-       append(&msg_buf, NULL, sizeof(message_t));
-       messages = (message_t*)msg_buf.data;
-
-       message_t *msg = &messages[history];
-       msg->channel = channel;
-       msg->when = time(NULL);
-       msg->text = strcopy(text);
-       history++;
-
        switch (channel->server->protocol) {
                case IRC:
-                       irc_send(msg);
+                       irc_send(channel, text);
                        break;
                case XMPP:
-                       xmpp_send(msg);
+                       xmpp_send(channel, text);
                        break;
        }
-
-       view_draw();
 }
 
 void chat_exit(void)
diff --git a/chat.h b/chat.h
index 2a6f671e99c001cddcbd5ec3d9dabfc376e8d032..5492bff432f042729b1cc5c0bd951e5e68167254 100644 (file)
--- a/chat.h
+++ b/chat.h
@@ -36,6 +36,7 @@ typedef struct channel_t {
        server_t   *server;
        char       *name;
        FILE       *log;
+       int         seen;
        channel_t  *next;
 } channel_t;
 
@@ -56,8 +57,8 @@ extern int        history;
 void chat_init(void);
 void chat_config(const char *group, const char *name,
                  const char *key, const char *value);
-void chat_recv(channel_t *channel, const char *from, const char *msg);
-void chat_send(channel_t *channel, const char *msg);
+void chat_recv(channel_t *channel, const char *from, const char *text);
+void chat_send(channel_t *channel, const char *text);
 void chat_exit(void);
 
 server_t  *add_server(const char *name, protocol_t protocol);
@@ -72,7 +73,7 @@ extern channel_t *irc_channel(void);
 extern void irc_config(server_t *server, channel_t *channel,
                        const char *group, const char *name,
                        const char *key, const char *value);
-extern void irc_send(message_t *msg);
+extern void irc_send(channel_t *channel, const char *text);
 extern void irc_exit(void);
 
 extern void xmpp_init(void);
@@ -81,5 +82,5 @@ extern channel_t *xmpp_channel(void);
 extern void xmpp_config(server_t *server, channel_t *channel,
                         const char *group, const char *name,
                         const char *key, const char *value);
-extern void xmpp_send(message_t *msg);
+extern void xmpp_send(channel_t *channel, const char *text);
 extern void xmpp_exit(void);
diff --git a/irc.c b/irc.c
index e41fa7388b9d025eddca4e2f1715cc3dfe2523be..b9038961130102f2c130842623dabbee52f8a142 100644 (file)
--- a/irc.c
+++ b/irc.c
@@ -90,7 +90,7 @@ typedef struct {
 } irc_command_t;
 
 /* Local functions */
-static void srv_notice(irc_server_t *srv, const char *from, const char *fmt, ...)
+static void srv_notice(irc_server_t *srv, const char *fmt, ...)
 {
        static char buf[1024];
 
@@ -99,10 +99,10 @@ static void srv_notice(irc_server_t *srv, const char *from, const char *fmt, ...
        vsnprintf(buf, sizeof(buf), fmt, ap);
        va_end(ap);
 
-       chat_recv(&srv->system.channel, from, buf);
+       chat_recv(&srv->system.channel, NULL, buf);
 }
 
-static void chan_notice(irc_channel_t *chan, const char *from, const char *fmt, ...)
+static void chan_notice(irc_channel_t *chan, const char *fmt, ...)
 {
        static char buf[1024];
 
@@ -111,7 +111,7 @@ static void chan_notice(irc_channel_t *chan, const char *from, const char *fmt,
        vsnprintf(buf, sizeof(buf), fmt, ap);
        va_end(ap);
 
-       chat_recv(&chan->channel, from, buf);
+       chat_recv(&chan->channel, NULL, buf);
 }
 
 static irc_channel_t *find_dest(irc_server_t *srv, const char *dest, int create)
@@ -135,7 +135,7 @@ static irc_channel_t *find_dest(irc_server_t *srv, const char *dest, int create)
 
 static void join_channel(irc_server_t *srv, irc_channel_t *chan)
 {
-       chan_notice(chan, NULL, "Joining Channel: %s", chan->channel.name);
+       chan_notice(chan, "Joining Channel: %s", chan->channel.name);
        net_print(&srv->net, "JOIN %s\n",  chan->dest);
        net_print(&srv->net, "TOPIC %s\n", chan->dest);
        net_print(&srv->net, "WHO %s\n",   chan->dest);
@@ -143,7 +143,7 @@ static void join_channel(irc_server_t *srv, irc_channel_t *chan)
 
 static void part_channel(irc_server_t *srv, irc_channel_t *chan)
 {
-       chan_notice(chan, NULL, "Leaving Channel: %s", chan->channel.name);
+       chan_notice(chan, "Leaving Channel: %s", chan->channel.name);
        net_print(&srv->net, "PART %s\n",  chan->dest);
 }
 
@@ -274,7 +274,7 @@ static void irc_run(irc_server_t *srv, const char *line)
                srv->net.err  = on_err;
                srv->net.data = srv;
 
-               srv_notice(srv, NULL, "Joining Server: %s", srv->server.name);
+               srv_notice(srv, "Joining Server: %s", srv->server.name);
                net_open(&srv->net, srv->host, srv->port);
 
                if (srv->tls)
@@ -290,11 +290,11 @@ static void irc_run(irc_server_t *srv, const char *line)
        }
        if (srv->state == IRC_RECV_TLS) {
                if (match(cmd, "CAP") && match(arg, "ACK")) {
-                       srv_notice(srv, from, "Start TLS proceeding");
+                       srv_notice(srv, "Start TLS proceeding");
                        srv->state = IRC_SEND_STARTTLS;
                }
                if (match(cmd, "CAP") && match(arg, "NAK")) {
-                       srv_notice(srv, from, "Start TLS unsupported");
+                       srv_notice(srv, "Start TLS unsupported");
                        srv->state = IRC_SEND_END;
                }
        }
@@ -320,11 +320,11 @@ static void irc_run(irc_server_t *srv, const char *line)
        }
        if (srv->state == IRC_RECV_SASL) {
                if (match(cmd, "CAP") && match(arg, "ACK")) {
-                       srv_notice(srv, from, "SASL auth proceeding");
+                       srv_notice(srv, "SASL auth proceeding");
                        srv->state = IRC_SEND_PLAIN;
                }
                if (match(cmd, "CAP") && match(arg, "NAK")) {
-                       srv_notice(srv, from, "SASL auth unsupported");
+                       srv_notice(srv, "SASL auth unsupported");
                        srv->state = IRC_SEND_END;
                }
        }
@@ -344,14 +344,14 @@ static void irc_run(irc_server_t *srv, const char *line)
        }
        if (srv->state == IRC_RECV_STATUS) {
                if (match(cmd, "903")) {
-                       srv_notice(srv, from, "SASL auth succeeded");
+                       srv_notice(srv, "SASL auth succeeded");
                        srv->state = IRC_SEND_END;
                }
                if (match(cmd, "904") ||
                    match(cmd, "905") ||
                    match(cmd, "906") ||
                    match(cmd, "907")) {
-                       srv_notice(srv, from, "SASL auth failed");
+                       srv_notice(srv, "SASL auth failed");
                        srv->state = IRC_DEAD;
                }
        }
@@ -393,15 +393,15 @@ static void irc_run(irc_server_t *srv, const char *line)
                }
                if (match(cmd, "TOPIC")) {
                        chan = find_dest(srv, arg, 1);
-                       chan_notice(chan, NULL, "Topic changed to %s", msg);
+                       chan_notice(chan, "Topic changed to %s", msg);
                }
                if (match(cmd, "331") || match(cmd, "322")) {
                        chan = find_dest(srv, arg, 1);
-                       chan_notice(chan, NULL, "Topic: %s", msg);
+                       chan_notice(chan, "Topic: %s", msg);
                }
                if (match(cmd, "353") && prefix(arg, "@", &arg)) {
                        chan = find_dest(srv, arg, 1);
-                       chan_notice(chan, NULL, "Members: %s", msg);
+                       chan_notice(chan, "Members: %s", msg);
                }
                if (match(cmd, "PRIVMSG") && dst[0] == '#') {
                        chan = find_dest(srv, dst, 1);
@@ -419,7 +419,7 @@ static void irc_run(irc_server_t *srv, const char *line)
            match(cmd, "372")    ||
            match(cmd, "375")    ||
            match(cmd, "376"))
-               srv_notice(srv, from, "%s", msg);
+               srv_notice(srv, "%s", msg);
 }
 
 /* IRC functions */
@@ -493,40 +493,46 @@ void irc_config(server_t *server, channel_t *channel,
        }
 }
 
-void irc_send(message_t *msg)
+void irc_send(channel_t *channel, const char *text)
 {
-       irc_channel_t *chan = (irc_channel_t*)msg->channel;
-       irc_server_t  *srv  = (irc_server_t*)msg->channel->server;
-       const char *txt = msg->text;
+       irc_channel_t *chan = (irc_channel_t*)channel;
+       irc_server_t  *srv  = (irc_server_t*)channel->server;
        const char *arg;
 
-       if (txt[0] == '/') {
-               if (prefix(txt, "/join", &arg)) {
+       if (text[0] == '/') {
+               if (prefix(text, "/join", &arg)) {
                        if (arg)
                                chan = find_dest(srv, arg, 1);
                        if (chan)
                                join_channel(srv, chan);
                }
-               else if (prefix(txt, "/part", &arg)) {
+               else if (prefix(text, "/part", &arg)) {
                        if (arg)
                                chan = find_dest(srv, arg, 0);
                        if (chan)
                                part_channel(srv, chan);
                }
+               else if (prefix(text, "/query", &arg)) {
+                       if (!arg) {
+                               chan_notice(chan, "usage: /query <user>");
+                               return;
+                       }
+                       chan = find_dest(srv, arg, 0);
+                       chan_notice(chan, "User: %s", arg);
+               }
                else {
-                       debug("unknown: [%s]", txt);
-                       chan_notice(chan, "unknown command %s", txt);
+                       chan_notice(chan, "Unknown command %s", text);
                }
        } else {
                if (chan == &srv->system) {
-                       strset(&msg->text, "Cannot send to server");
+                       chan_notice(chan, "Cannot send to server");
                }
                else if (!chan->dest) {
-                       strset(&msg->text, "No destination for message");
+                       chan_notice(chan, "No destination for message");
                }
                else {
-                       net_print(&srv->net, "PRIVMSG %s :%s\n", chan->dest, msg->text);
-                       msg->from = strcopy(srv->nick);
+                       net_print(&srv->net, "PRIVMSG %s :%s\n", chan->dest, text);
+                       chat_recv(channel, srv->nick, text);
                }
        }
 }
diff --git a/irc.h b/irc.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/view.c b/view.c
index 5ce670335d4e5268253d134f0baef3ea67173ff0..3372c1ddf5038d153e3e4bdc995858bd474ccb55 100644 (file)
--- a/view.c
+++ b/view.c
@@ -140,24 +140,27 @@ static void cycle_channel(void)
        if (!focus)
                return;
 
-       int found = 0;
-       channel_t *channel = NULL;
-       for (int i = 0; i < history; i++) {
+       /* Clear seen flags */
+       for (int i = 0; i < history; i++)
+               messages[i].channel->seen = 0;
+
+       /* Find current channel */
+       channel_t *first = NULL, *cur = NULL, *next = NULL;
+       for (int i = 0; i < history && !next; i++) {
                message_t *msg = &messages[i];
-               int match = msg->channel == focus->channel;
+               if (msg->channel->seen)
+                       continue;
+               msg->channel->seen = 1;
                if (!in_window(msg, focus))
                        continue;
-               if (match)
-                       found = 1;
-               if (!channel && !match)
-                       channel = msg->channel;
-               if (found && !match) {
-                       channel = msg->channel;
-                       break;
-               }
-       }
-       if (channel)
-               focus->channel = channel;
+               if (cur)
+                       next = msg->channel;
+               if (msg->channel == focus->channel)
+                       cur = msg->channel;
+               if (!first)
+                       first = msg->channel;
+       }
+       focus->channel = next ?: first;
 }
 
 static void update_windows(void)
diff --git a/xmpp.c b/xmpp.c
index 22504b2d34238b7cfa4f417c00c35ec0f3dd3a32..3bcb846500209b2ecc53a7f44ada0d2f0631b135 100644 (file)
--- a/xmpp.c
+++ b/xmpp.c
@@ -48,41 +48,46 @@ typedef enum {
        XMPP_RECV_JID,
        XMPP_SEND_PRESENCE,
        XMPP_READY,
+       XMPP_IN_IQ,
+       XMPP_IN_MESSAGE,
+       XMPP_IN_PRESENCE,
 } xmpp_state_t;
 
 typedef struct {
-       channel_t      channel;
-       char           dest[JID_LEN];
+       channel_t       channel;
+       char            dest[JID_LEN];
 
-       const char    *room;
-       int            join;
+       const char     *room;
+       int             join;
 } xmpp_channel_t;
 
 typedef struct {
-       server_t       server;
-       xmpp_channel_t system;
-
-       int            connect;
-       const char    *host;
-       int            port;
-       const char    *muc;
-       const char    *nick;
-       const char    *jid;
-       const char    *user;
-       const char    *pass;
-
-       net_t          net;
-       XML_Parser     expat;
-       xmpp_state_t   state;
-       buf_t          buf;
-       int            indent;
-
-       int            in_error;
-
-       char           msg_from[JID_LEN];
-       char           msg_usr[JID_LEN];
-       char           msg_srv[JID_LEN];
-       char           msg_res[JID_LEN];
+       server_t        server;
+       xmpp_channel_t  system;
+
+       int             connect;
+       const char     *host;
+       int             port;
+       const char     *muc;
+       const char     *nick;
+       const char     *jid;
+       const char     *user;
+       const char     *pass;
+
+       net_t           net;
+       XML_Parser      expat;
+       xmpp_state_t    state;
+       buf_t           buf;
+       int             indent;
+
+       int             in_error;
+
+       char            msg_jid[JID_LEN];
+       char            msg_usr[JID_LEN];
+       char            msg_srv[JID_LEN];
+       char            msg_res[JID_LEN];
+       char           *msg_from;
+       xmpp_channel_t *msg_chan;
 } xmpp_server_t;
 
 /* Helper functions */
@@ -136,8 +141,8 @@ static void split_jid(const char *jid, char *usr, char *srv, char *res)
                }
        }
 
-       debug("JID: '%s' usr=[%s] srv=[%s] res=[%s]",
-                       jid, usr, srv, res);
+       //debug("JID: '%s' usr=[%s] srv=[%s] res=[%s]",
+       //              jid, usr, srv, res);
 }
 
 static xmpp_channel_t *find_dest(xmpp_server_t *srv,
@@ -153,6 +158,10 @@ static xmpp_channel_t *find_dest(xmpp_server_t *srv,
                 jid_srv[0] ? jid_srv  :
                 is_muc     ? srv->muc : srv->host);
 
+       /* Server channels */
+       if (match(jid, srv->host))
+               return &srv->system;
+
        /* Find existing channels */
        for (channel_t *cur = channels; cur; cur = cur->next) {
                if (cur->server != &srv->server)
@@ -224,6 +233,8 @@ static void xmpp_run(xmpp_server_t *srv,
                const char *start, const char **attrs,
                const char *end, const char *data)
 {
+       xmpp_channel_t *chan = NULL;
+
        /* Debug print */
        if (data)
                debug("%*s \"%s\"", srv->indent*4, "", data);
@@ -392,47 +403,129 @@ static void xmpp_run(xmpp_server_t *srv,
                srv->state = XMPP_READY;
        }
 
-       /* Info queries */
+       /* Start message */
        if (srv->state == XMPP_READY) {
-               if (match(start, "item"))
+               srv->state = match(start, "iq")       ? XMPP_IN_IQ       :
+                            match(start, "message")  ? XMPP_IN_MESSAGE  :
+                            match(start, "presence") ? XMPP_IN_PRESENCE :
+                                                       XMPP_READY;
+               if (srv->state != XMPP_READY) {
+                       strncpy(srv->msg_jid, find_attr(attrs, "from"), JID_LEN);
+                       split_jid(srv->msg_jid, srv->msg_usr,
+                                 srv->msg_srv, srv->msg_res);
+
+                       if (match(srv->msg_srv, srv->muc)) {
+                               srv->msg_from = srv->msg_res[0] ? srv->msg_res : NULL;
+                               srv->msg_chan = find_dest(srv, srv->msg_jid, 1);
+                       } else {
+                               srv->msg_from = srv->msg_usr[0] ? srv->msg_usr : NULL;
+                               srv->msg_chan = find_dest(srv, srv->msg_jid, 0);
+                       }
+
+                       debug("xmpp: %s -- jid=[%s] from=[%s] chan=[%s]",
+                               start,
+                               srv->msg_jid, srv->msg_from,
+                               srv->msg_chan->channel.name);
+               }
+       }
+       if (srv->state == XMPP_IN_IQ ||
+           srv->state == XMPP_IN_MESSAGE ||
+           srv->state == XMPP_IN_PRESENCE) {
+               if (srv->msg_chan && srv->msg_chan != &srv->system)
+                       chan = srv->msg_chan;
+       }
+
+       /* Info/Queries */
+       if (srv->state == XMPP_IN_IQ) {
+               if (match(start, "item") && chan) {
+                       static char res[JID_LEN];
+                       split_jid(find_attr(attrs, "jid"),
+                                 NULL, NULL, res);
+                       chan_notice(chan, "user: %s", res);
+               }
+               if (match(start, "item") && !chan) {
                        srv_notice(srv, "item: [%s] %s",
                                        find_attr(attrs, "jid"),
                                        find_attr(attrs, "name"));
-               if (match(start, "identity"))
+               }
+               if (match(start, "identity")) {
                        srv_notice(srv, "identity: %s",
                                        find_attr(attrs, "name"));
-               if (match(start, "feature"))
+               }
+               if (match(start, "feature")) {
                        srv_notice(srv, "feature: %s",
                                        find_attr(attrs, "var"));
+               }
+               if (match(start, "field")) {
+                       debug("xmpp: %s -- type=[%s] label=[%s]", end,
+                               find_attr(attrs, "type"),
+                               find_attr(attrs, "label"));
+                       if (!find_attr(attrs, "label"))
+                               return;
+                       chan_notice(chan, "%-36s -- %s (%s)",
+                               find_attr(attrs, "var"),
+                               find_attr(attrs, "label"),
+                               find_attr(attrs, "type"));
+               }
+               if (match(end, "title")) {
+                       debug("xmpp: title -- jid=[%s]",
+                               end, srv->msg_jid);
+                       chan_notice(chan, "Title: %s", data);
+               }
+               if (match(end, "instructions")) {
+                       debug("xmpp: instructions -- jid=[%s]",
+                               end, srv->msg_jid);
+                       chan_notice(chan, "%s", data);
+               }
        }
 
-       /* Receive messages */
-       if (srv->state == XMPP_READY) {
-               if (match(start, "message")) {
-                       strncpy(srv->msg_from, find_attr(attrs,"from"),
-                               JID_LEN);
-                       split_jid(srv->msg_from, srv->msg_usr,
-                                 srv->msg_srv, srv->msg_res);
+       /* Messages */
+       if (srv->state == XMPP_IN_MESSAGE) {
+               if (match(end, "body") && data) {
+                       debug("xmpp: body (%s) -- chan=[%s] jid=[%s] from=[%s]",
+                               srv->msg_from == srv->msg_usr ? "user" : "chat" ,
+                               srv->msg_chan->channel.name,
+                               srv->msg_jid, srv->msg_from);
+                       chat_recv(&chan->channel, srv->msg_from, data);
                }
-               if (match(end, "message")) {
-                       srv->msg_from[0] = '\0';
-                       srv->msg_usr[0]  = '\0';
-                       srv->msg_srv[0]  = '\0';
-                       srv->msg_res[0]  = '\0';
+       }
+
+       /* Presence */
+       if (srv->state == XMPP_IN_PRESENCE) {
+               static char alias[JID_LEN];
+               const char *jid;
+               if (match(start, "item")) {
+                       if ((jid = find_attr(attrs, "jid")))
+                               strncpy(alias, jid, JID_LEN);
                }
-               if (match(end, "body") && data) {
-                       xmpp_channel_t *chan;
-                       debug("xmpp: jid -> ready");
-                       if (match(srv->msg_srv, srv->muc)) {
-                               chan = find_dest(srv, srv->msg_from, 1);
-                               chat_recv(&chan->channel, srv->msg_res, data);
-                       } else {
-                               chan = find_dest(srv, srv->msg_from, 0);
-                               chat_recv(&chan->channel, srv->msg_usr, data);
-                       }
+               if (match(end, "presence") && chan) {
+                       if (alias[0])
+                               chan_notice(chan, "%s (%s) entered room.",
+                                               srv->msg_from, alias);
+                       else
+                               chan_notice(chan, "%s entered room.",
+                                               srv->msg_from);
+                       alias[0] = '\0';
                }
        }
 
+       /* End messages */
+       if (srv->state == XMPP_IN_IQ ||
+           srv->state == XMPP_IN_MESSAGE ||
+           srv->state == XMPP_IN_PRESENCE) {
+               if (match(end, "iq") ||
+                   match(end, "message") ||
+                   match(end, "presence")) {
+                       srv->state = XMPP_READY;
+
+                       srv->msg_jid[0] = '\0';
+                       srv->msg_usr[0] = '\0';
+                       srv->msg_srv[0] = '\0';
+                       srv->msg_res[0] = '\0';
+                       srv->msg_from   = NULL;
+                       srv->msg_chan   = NULL;
+               }
+       }
        /* Error handling */
        if (match(start, "stream:error"))
                srv->in_error = 1;
@@ -521,74 +614,97 @@ void xmpp_config(server_t *server, channel_t *channel,
        }
 }
 
-void xmpp_send(message_t *msg)
+void xmpp_send(channel_t *channel, const char *text)
 {
-       xmpp_channel_t *chan = (xmpp_channel_t*)msg->channel;
-       xmpp_server_t  *srv  = (xmpp_server_t*)msg->channel->server;
-       const char *txt = msg->text;
+       xmpp_channel_t *chan = (xmpp_channel_t*)channel;
+       xmpp_server_t  *srv  = (xmpp_server_t*)channel->server;
        const char *arg;
 
        /* Handle commands */
-       if (txt[0] == '/') {
-               if (prefix(txt, "/items", &arg)) {
+       if (text[0] == '/') {
+               if (prefix(text, "/items", &arg)) {
                        net_print(&srv->net,
                                "<iq id='items' type='get' from='%s' to='%s'>"
-                               "<query xmlns='http://jabber.org/protocol/disco#items' />"
+                               "<query xmlns='http://jabber.org/protocol/disco#items'/>"
                                "</iq>",
                                srv->jid, arg ?: srv->host);
                }
-               else if (prefix(txt, "/info", &arg)) {
+               else if (prefix(text, "/info", &arg)) {
                        net_print(&srv->net,
                                "<iq id='info' type='get' from='%s' to='%s'>"
-                               "<query xmlns='http://jabber.org/protocol/disco#info' />"
+                               "<query xmlns='http://jabber.org/protocol/disco#info'/>"
                                "</iq>",
                                srv->jid, arg ?: srv->host);
                }
-               else if (prefix(txt, "/list", &arg)) {
+               else if (prefix(text, "/names", &arg)) {
+                       if (arg)
+                               chan = find_dest(srv, arg, 1);
+                       if (chan == &srv->system) {
+                               chan_notice(chan, "Cannot get names from server");
+                               return;
+                       }
                        net_print(&srv->net,
                                "<iq id='list' type='get' from='%s' to='%s'>"
-                               "<query xmlns='http://jabber.org/protocol/disco#items' />"
+                               "<query xmlns='http://jabber.org/protocol/disco#items'/>"
                                "</iq>",
-                               srv->jid, arg ?: srv->muc);
+                               srv->jid, chan->dest);
                }
-               else if (prefix(txt, "/join", &arg)) {
+               else if (prefix(text, "/join", &arg)) {
                        if (!arg) {
                                chan_notice(chan, "usage: /join <channel>");
                                return;
                        }
-                       chan = find_dest(srv, arg, 1);
                        net_print(&srv->net,
                                "<presence id='join' from='%s' to='%s/%s'>"
                                "<x xmlns='http://jabber.org/protocol/muc'/>"
                                "</presence>",
                                srv->jid, chan->dest, srv->nick);
+                       chan = find_dest(srv, arg, 1);
+                       chan_notice(chan, "Room: %s", arg);
+               }
+               else if (prefix(text, "/config", &arg)) {
+                       if (arg) {
+                               chan_notice(chan, "Unimplemented: /config <arg>");
+                               return;
+                       }
+                       net_print(&srv->net,
+                               "<iq id='config' type='get' from='%s' to='%s'>"
+                               "<query xmlns='http://jabber.org/protocol/muc#owner'/>"
+                               "</iq>",
+                               srv->jid, chan->dest);
                }
-               else if (prefix(txt, "/query", &arg)) {
+               else if (prefix(text, "/query", &arg)) {
                        if (!arg) {
                                chan_notice(chan, "usage: /query <user>");
                                return;
                        }
                        chan = find_dest(srv, arg, 0);
-                       chan_notice(chan, "query <user>");
+                       chan_notice(chan, "User: %s", arg);
                }
                else {
-                       debug("unknown: [%s]", txt);
-                       chan_notice(chan, "unknown command %s", txt);
+                       chan_notice(chan, "Unknown command %s", text);
                }
        } else {
-               debug("message: [%s]", txt);
-               if (chan->room) {
+               debug("message: [%s]", text);
+               if (chan == &srv->system) {
+                       chan_notice(chan, "Cannot send to server");
+               }
+               else if (!chan->dest) {
+                       chan_notice(chan, "No destination for message");
+               }
+               else if (chan->room) {
                        net_print(&srv->net,
                                "<message id='chat' from='%s' to='%s' type='groupchat'>"
                                "<body>%s</body>"
                                "</message>",
-                               srv->jid, chan->dest, txt);
+                               srv->jid, chan->dest, text);
                } else {
                        net_print(&srv->net,
                                "<message id='chat' from='%s' to='%s'>"
                                "<body>%s</body>"
                                "</message>",
-                               srv->jid, chan->dest, txt);
+                               srv->jid, chan->dest, text);
+                       chat_recv(channel, srv->nick, text);
                }
        }
 }