change irc_line.prefix into a
authorTero Marttila <terom@fixme.fi>
Thu, 26 Mar 2009 23:15:55 +0200
changeset 75 ff6272398d2e
parent 74 11ec458d1cbf
child 76 b3672e3d9665
change irc_line.prefix into a
src/irc_chan.c
src/irc_conn.c
src/irc_line.c
src/irc_line.h
src/irc_log.c
src/irc_proto.c
src/irc_proto.h
src/test.c
--- a/src/irc_chan.c	Thu Mar 26 22:54:25 2009 +0200
+++ b/src/irc_chan.c	Thu Mar 26 23:15:55 2009 +0200
@@ -71,7 +71,7 @@
     err_t err;
 
     // us?
-    if (irc_prefix_cmp_nick(line->prefix, chan->net->conn->nickname) == 0) {
+    if (irc_cmp_nick(line->source->nickname, chan->net->conn->nickname) == 0) {
         // twiddle state
         chan->joining = false;
         chan->joined = true;
@@ -80,19 +80,12 @@
         IRC_CHAN_INVOKE_CALLBACK(chan, on_self_join);
 
     } else {
-        char prefix_buf[IRC_PREFIX_MAX];
-        struct irc_nm nm;
-        
-        // parse the nickname
-        if ((err = irc_nm_parse(&nm, prefix_buf, line->prefix)))
-            return log_warn("invalid prefix: %s", line->prefix);
-        
         // add them
-        if ((err = irc_chan_add_user(chan, nm.nickname)))
-            return log_warn("irc_chan_add_user(%s, %s): %s", irc_chan_name(chan), nm.nickname, error_name(err));
+        if ((err = irc_chan_add_user(chan, line->source->nickname)))
+            return log_warn("irc_chan_add_user(%s, %s): %s", irc_chan_name(chan), line->source->nickname, error_name(err));
 
         // invoke callback (source)
-        IRC_CHAN_INVOKE_CALLBACK(chan, on_join, &nm);
+        IRC_CHAN_INVOKE_CALLBACK(chan, on_join, line->source);
     }
 }
 
@@ -104,12 +97,11 @@
 static void irc_chan_on_PART (const struct irc_line *line, void *arg)
 {
     struct irc_chan *chan = arg;
-    err_t err;
 
     const char *msg = line->args[1];
 
     // us?
-    if (irc_prefix_cmp_nick(line->prefix, chan->net->conn->nickname) == 0) {
+    if (irc_cmp_nick(line->source->nickname, chan->net->conn->nickname) == 0) {
         // twiddle state
         chan->joined = false;
         chan->parted = true;
@@ -119,20 +111,14 @@
 
     } else {
         // someone else
-        char prefix_buf[IRC_PREFIX_MAX];
-        struct irc_nm nm;
         struct irc_chan_user *chan_user;
         
-        // parse the nickname
-        if ((err = irc_nm_parse(&nm, prefix_buf, line->prefix)))
-            return log_warn("invalid prefix: %s", line->prefix);
-        
         // invoke callback (source, msg)
-        IRC_CHAN_INVOKE_CALLBACK(chan, on_part, &nm, msg);
+        IRC_CHAN_INVOKE_CALLBACK(chan, on_part, line->source, msg);
 
         // look up the irc_chan_user
-        if ((chan_user = irc_chan_get_user(chan, nm.nickname)) == NULL)
-            return log_warn("PART'd user not on channel: %s, %s", irc_chan_name(chan), nm.nickname);
+        if ((chan_user = irc_chan_get_user(chan, line->source->nickname)) == NULL)
+            return log_warn("PART'd user not on channel: %s, %s", irc_chan_name(chan), line->source->nickname);
 
         // remove them
         irc_chan_remove_user(chan, chan_user);
@@ -145,23 +131,11 @@
 static void irc_chan_on_PRIVMSG (const struct irc_line *line, void *arg)
 {
     struct irc_chan *chan = arg;
-    char prefix_buf[IRC_PREFIX_MAX];
-    struct irc_nm nm;
-    err_t err;
 
     const char *msg = line->args[1];
 
-    // parse nickmask
-    if ((err = irc_nm_parse(&nm, prefix_buf, line->prefix))) {
-        log_warn("invalid prefix: %s", line->prefix);
-        
-        // invoke callback with NULL source
-        IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, NULL, msg);
-
-    } else {
-        // invoke callback (source, message)
-        IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, &nm, msg);
-    }
+    // invoke callback (source, message)
+    IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, line->source, msg);
 }
 
 /**
--- a/src/irc_conn.c	Thu Mar 26 22:54:25 2009 +0200
+++ b/src/irc_conn.c	Thu Mar 26 23:15:55 2009 +0200
@@ -81,20 +81,13 @@
 static void on_NICK (const struct irc_line *line, void *arg)
 {
     struct irc_conn *conn = arg;
-    char nickname[IRC_NICK_MAX];
-
-    // parse nickname, ignoring errors
-    if (irc_prefix_parse_nick(line->prefix, nickname)) {
-        log_warn("invalid prefix: %s", line->prefix);
-        return;
-    }
 
     // ignore if it's not us
-    if (irc_cmp_nick(nickname, conn->nickname))
+    if (!line->source || irc_cmp_nick(line->source->nickname, conn->nickname))
         return;
 
     // update our nickname
-    irc_conn_set_nickname(conn, nickname);
+    irc_conn_set_nickname(conn, line->args[0]);
 }
 
 /**
@@ -114,13 +107,14 @@
 {
     struct irc_conn *conn = arg;
     struct irc_line line;
+    struct irc_nm nm;
     int err;
     
     // log
     log_debug("%s", line_buf);
 
     // parse
-    if ((err = irc_line_parse(&line, line_buf))) {
+    if ((err = irc_line_parse(&line, &nm, line_buf))) {
         log_warn("invalid line: %s: %s\n", line_buf, error_name(err));
         return;
     }
--- a/src/irc_line.c	Thu Mar 26 22:54:25 2009 +0200
+++ b/src/irc_line.c	Thu Mar 26 23:15:55 2009 +0200
@@ -1,17 +1,28 @@
-
 #include "irc_line.h"
+#include "log.h"
 
 #include <string.h>
 #include <assert.h>
 
-err_t irc_line_parse (struct irc_line *line, char *data)
+err_t irc_line_parse (struct irc_line *line, struct irc_nm *nm, char *data)
 {
     int i;
+    err_t err;
 
     // prefix?
     if (data && *data == ':') {
         // consume as token
-        line->prefix = strsep(&data, " ") + 1;
+        char *prefix = strsep(&data, " ") + 1;
+        
+        // parse as a nickmask
+        if ((err = irc_nm_parse_buf(nm, prefix))) {
+            line->source = NULL;
+            log_warn("invalid prefix: '%s': %s", prefix, error_name(err));
+
+        } else {
+            // valid, store
+            line->source = nm;
+        }
     }
 
     // command
@@ -87,7 +98,7 @@
     err_t err;
 
     // XXX: no need for prefix on client
-    assert(line->prefix == NULL);
+    assert(line->source == NULL);
     
     // command
     if ((err = output_token(buf, &off, line->command, TOK_NOSPACE)))
--- a/src/irc_line.h	Thu Mar 26 22:54:25 2009 +0200
+++ b/src/irc_line.h	Thu Mar 26 23:15:55 2009 +0200
@@ -6,6 +6,7 @@
  *
  * The low-level IRC protocol unit is a line, with prefix, command and arguments
  */
+#include "irc_proto.h"
 #include "error.h"
 
 /**
@@ -28,8 +29,8 @@
  * Low-level IRC protocol unit
  */
 struct irc_line {
-    /** The message source, either a server name or a nickmask */
-    const char *prefix;
+    /** The message source as a nickmask, for those messages that have a valid prefix. May be NULL otherwise */
+    const struct irc_nm *source;
 
     /** The command, either a numeric or a primary command */
     const char *command;
@@ -42,9 +43,11 @@
  * Parse an IRC message to fill in an irc_line. This mutates the value of data (to insert NULs between tokens), and
  * stores pointers into this data into the irc_line.
  *
+ * If the prefix is a valid nickmask, it will be stored in the given given irc_nm, and irc_line.nm set to this.
+ *
  * The irc_line will have the first N args values set to valid values, and all the rest set to NULL.
  */
-err_t irc_line_parse (struct irc_line *line, char *data);
+err_t irc_line_parse (struct irc_line *line, struct irc_nm *nm, char *data);
 
 /**
  * Formats an irc_line as a protocol line into the given buffer (which should hold at least IRC_LINE_MAX bytes).
--- a/src/irc_log.c	Thu Mar 26 22:54:25 2009 +0200
+++ b/src/irc_log.c	Thu Mar 26 23:15:55 2009 +0200
@@ -162,24 +162,6 @@
 }
 
 /**
- * Parse the prefix into a nickmask and pass on to irc_log_event
- */
-static err_t irc_log_event_prefix (struct irc_log_ctx *ctx, struct irc_log_chan *chan_ctx, const char *prefix,
-        const char *type, const char *target, const char *message)
-{
-    char prefix_buf[IRC_PREFIX_MAX];
-    struct irc_nm nm;
-    err_t err;
-
-    // parse nickmask
-    if ((err = irc_nm_parse(&nm, prefix_buf, prefix)))
-        return err;
-
-    // log
-    return irc_log_event(ctx, chan_ctx, &nm, type, target, message);
-}
-
-/**
  * Log a simple channel event of the form:
  *
  * :nm <type> <channel> [<msg>]
@@ -190,7 +172,7 @@
     
     const char *msg = line->args[1];
 
-    irc_log_event_prefix(chan_ctx->ctx, chan_ctx, line->prefix, line->command, NULL, msg);
+    irc_log_event(chan_ctx->ctx, chan_ctx, line->source, line->command, NULL, msg);
 }
 
 /**
@@ -221,7 +203,7 @@
     }
     
     // log
-    irc_log_event_prefix(chan_ctx->ctx, chan_ctx, line->prefix, line->command, NULL, message);
+    irc_log_event(chan_ctx->ctx, chan_ctx, line->source, line->command, NULL, message);
 }
 
 /**
@@ -236,7 +218,7 @@
     const char *target = line->args[1];    
     const char *msg = line->args[2];
 
-    irc_log_event_prefix(chan_ctx->ctx, chan_ctx, line->prefix, line->command, target, msg);
+    irc_log_event(chan_ctx->ctx, chan_ctx, line->source, line->command, target, msg);
 }
 
 /**
--- a/src/irc_proto.c	Thu Mar 26 22:54:25 2009 +0200
+++ b/src/irc_proto.c	Thu Mar 26 23:15:55 2009 +0200
@@ -2,6 +2,27 @@
 
 #include <string.h>
 
+err_t irc_nm_parse_buf (struct irc_nm *nm, char *prefix)
+{
+    // XXX: handle server name prefixes
+
+    // mangle tokens
+    nm->nickname = strsep(&prefix, "!");
+    nm->username = strsep(&prefix, "@");
+
+    // did we find the ! and @ tokens?
+    if (!prefix)
+        // probably a server name instead
+        return ERR_INVALID_NM;
+    
+    // the hostname is then the rest of the prefix
+    nm->hostname = prefix;
+
+    // ok
+    return SUCCESS;
+
+}
+
 err_t irc_nm_parse (struct irc_nm *nm, char *buf, const char *prefix)
 {
     // too long?
@@ -10,21 +31,9 @@
 
     // copy to mutable buffer
     strcpy(buf, prefix);
-
-    // mangle tokens
-    nm->nickname = strsep(&buf, "!");
-    nm->username = strsep(&buf, "@");
-
-    // did we find the ! and @ tokens?
-    if (!buf)
-        // probably a server name instead
-        return ERR_INVALID_NM;
     
-    // the hostname is then the rest of the prefix
-    nm->hostname = buf;
-
-    // ok
-    return SUCCESS;
+    // parse from buf
+    return irc_nm_parse_buf(nm, buf);
 }
 
 /**
--- a/src/irc_proto.h	Thu Mar 26 22:54:25 2009 +0200
+++ b/src/irc_proto.h	Thu Mar 26 23:15:55 2009 +0200
@@ -32,7 +32,8 @@
 #define IRC_CHANFLAGS "@+"
 
 /**
- * Parsed nickmask
+ * Parsed nickmask. For normal user prefixes, all fields will be non-NULL. For server prefixes, nickname and username
+ * will be NULL, and hostname will be the server name.
  */
 struct irc_nm {
     /** Nickname, not normalized */
@@ -46,10 +47,14 @@
 };
 
 /**
- * Parse a full nickmask from a prefix. This fails if the prefix is a server name.
- *
- * Since we cannot modify the prefix string, the user must provide a buffer of at least IRC_PREFIX_MAX bytes to store
- * the procesed prefix. The returned nm's fields will point into this buffer.
+ * Parse a full nickmask from a prefix, mutating the value of the given buffer, and returning pointers into the buffer
+ * inside \a nm.
+ */
+err_t irc_nm_parse_buf (struct irc_nm *nm, char *prefix);
+
+/**
+ * Same as irc_nm_parse_buf(), but copies the prefix into the given mutable buffer of at least IRC_PREFIX_MAX bytes and
+ * returns pointers into that instead.
  */
 err_t irc_nm_parse (struct irc_nm *nm, char *buf, const char *prefix);
 
--- a/src/test.c	Thu Mar 26 22:54:25 2009 +0200
+++ b/src/test.c	Thu Mar 26 23:15:55 2009 +0200
@@ -123,6 +123,12 @@
     return dump_strn(str, -1);
 }
 
+void assert_null (const void *ptr)
+{
+    if (ptr)
+        FATAL("%p != NULL", ptr);
+}
+
 void assert_strcmp (const char *is, const char *should_be)
 {
     if (!is || strcmp(is, should_be))
@@ -423,7 +429,7 @@
 {
     struct _test_irc_conn_ctx *ctx = arg;
 
-    assert_strcmp(line->prefix, "foobar-prefix");
+    assert_null(line->source);
     assert_strcmp(line->command, "TEST");
     assert_strcmp(line->args[0], "arg0");
     assert_strnull(line->args[1]);
@@ -486,6 +492,7 @@
     assert_success(irc_conn_add_cmd_handlers(conn, _conn_handlers, &ctx));
 
     // test on_TEST handler
+    // XXX: come up with a better prefix
     log_info("test irc_conn.handlers");
     test_sock_push(sock, ":foobar-prefix TEST arg0\r\n");
     assert(ctx.on_TEST);
@@ -836,7 +843,9 @@
     {   "dump_str",             &test_dump_str              },
     {   "sock_test",            &test_sock_test             },
     {   "line_proto",           &test_line_proto            },
+    // XXX: irc_line_parse_invalid_prefix
     {   "irc_conn",             &test_irc_conn              },
+    // XXX: irc_conn_self_nick
     {   "irc_net",              &test_irc_net               },
     {   "irc_chan_add_offline", &test_irc_chan_add_offline  },
     {   "irc_chan_namreply",    &test_irc_chan_namreply     },