src/irc_conn.c
changeset 37 4fe4a3c4496e
parent 33 e5139b339b18
child 39 a4891d71aca9
--- a/src/irc_conn.c	Thu Mar 12 18:08:27 2009 +0200
+++ b/src/irc_conn.c	Thu Mar 12 18:11:44 2009 +0200
@@ -1,47 +1,109 @@
 #include "irc_conn.h"
 #include "irc_cmd.h"
+#include "irc_nm.h"
 #include "log.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-/*
- * "Welcome to the Internet Relay Network <nick>!<user>@<host>"
+/**
+ * @group Forward-declerations
+ * @{
  */
-static void on_RPL_WELCOME (struct irc_conn *conn, const struct irc_line *line, void *arg)
+
+/**
+ * Handle an event-based error on this IRC connection.
+ */
+static void irc_conn_handle_error (struct irc_conn *conn, struct error_info *err);
+
+/**
+ * Update irc_conn.nickname
+ */
+static err_t irc_conn_set_nickname (struct irc_conn *conn, const char *nickname)
 {
-    (void) line;
-    (void) arg;
+    struct error_info err;
+
+    // strdup
+    if ((conn->nickname = strdup(nickname)) == NULL) {
+        SET_ERROR(&err, ERR_STRDUP);
+
+        // notify
+        irc_conn_handle_error(conn, &err);
+
+        return ERROR_CODE(&err);
+    }
+
+    // ok
+    return SUCCESS;
+}
+
+// @}
+
+/**
+ * 001 <nick> :Welcome to the Internet Relay Network <nick>!<user>@<host>
+ */
+static void on_RPL_WELCOME (const struct irc_line *line, void *arg)
+{
+    struct irc_conn *conn = arg;
 
     // update state
     conn->registering = false;
     conn->registered = true;
+    
+    // set our real nickname from the message target
+    if (irc_conn_set_nickname(conn, line->args[0]))
+        return;
 
     // trigger callback
     if (conn->callbacks.on_registered)
         conn->callbacks.on_registered(conn, conn->cb_arg);
 }
 
-/*
+/**
  * PING <server1> [ <server2> ]
  *
  * Send a 'PONG <server1>` reply right away.
  */ 
-static void on_PING (struct irc_conn *conn, const struct irc_line *line, void *arg)
+static void on_PING (const struct irc_line *line, void *arg)
 {
-    (void) arg;
+    struct irc_conn *conn = arg;
 
     // just reply
     irc_conn_PONG(conn, line->args[0]);
 }
 
-/*
+/**
+ * NICK <nickname>
+ *
+ * If the prefix is us, then update our nickname
+ */
+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))
+        return;
+
+    // update our nickname
+    irc_conn_set_nickname(conn, nickname);
+}
+
+/**
  * Our command handlers
  */
-struct irc_cmd_handler _cmd_handlers[] = {
-    { IRC_RPL_WELCOME,  on_RPL_WELCOME      },
-    { "PING",           on_PING             },
-    { NULL,             NULL,               },
+static struct irc_cmd_handler _cmd_handlers[] = {
+    {   IRC_RPL_WELCOME,    &on_RPL_WELCOME     },
+    {   "PING",             &on_PING            },
+    {   "NICK",             &on_NICK            },
+    {   NULL,               NULL,               },
 };
 
 /**
@@ -51,8 +113,6 @@
 {
     struct irc_conn *conn = arg;
     struct irc_line line;
-    struct irc_cmd_chain *chain;
-    struct irc_cmd_handler *handler;
     int err;
     
     // log
@@ -63,21 +123,9 @@
         log_warn("invalid line: %s: %s\n", line_buf, error_name(err));
         return;
     }
-    
-    // run each handler chain
-    STAILQ_FOREACH(chain, &conn->handlers, node) {
-        // look up appropriate handler
-        for (handler = chain->handlers; handler->command; handler++) {
-            // the command is alpha-only, so normal case-insensitive cmp is fine
-            if (strcasecmp(handler->command, line.command) == 0) {
-                // invoke the func
-                handler->func(conn, &line, chain->arg);
 
-                // ...only one per chain
-                break;
-            }
-        }
-    }
+    // invoke command handlers
+    irc_cmd_invoke(&conn->handlers, &line);
 }
 
 /**
@@ -89,8 +137,9 @@
 
     // log
     log_err_info(err, "line_proto error");
-
-    // XXX: notify user
+    
+    // 'handle'
+    irc_conn_handle_error(conn, err);
 }
 
 static struct line_proto_callbacks _lp_callbacks = {
@@ -98,6 +147,11 @@
     .on_error       = &irc_conn_on_error,
 };
 
+static void irc_conn_handle_error (struct irc_conn *conn, struct error_info *err)
+{
+    // XXX: notify user callback
+}
+
 err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_callbacks *callbacks, 
         void *cb_arg, struct error_info *err)
 {
@@ -112,10 +166,10 @@
     conn->cb_arg = cb_arg;
 
     // initialize command handlers
-    STAILQ_INIT(&conn->handlers);
+    irc_cmd_init(&conn->handlers);
     
     // add the core handlers 
-    if ((ERROR_CODE(err) = irc_conn_register_handler_chain(conn, _cmd_handlers, NULL)))
+    if ((ERROR_CODE(err) = irc_conn_add_cmd_handlers(conn, _cmd_handlers, conn)))
         goto error;
 
     // create the line_proto, with our on_line handler
@@ -136,44 +190,21 @@
 
 void irc_conn_destroy (struct irc_conn *conn)
 {
-    struct irc_cmd_chain *next = STAILQ_FIRST(&conn->handlers);
-
     // release the line_proto
     if (conn->lp)
         line_proto_release(conn->lp);
-
-    // clean up any handler chains
-    while (next) {
-        struct irc_cmd_chain *node = next;
-
-        // update next
-        next = STAILQ_NEXT(node, node);
-
-        // free
-        free(node);
-    }
+    
+    // free the command handlers
+    irc_cmd_free(&conn->handlers);
 
     // free the irc_conn itself
     free(conn);
 }
 
-err_t irc_conn_register_handler_chain (struct irc_conn *conn, struct irc_cmd_handler *handlers, void *arg)
+err_t irc_conn_add_cmd_handlers (struct irc_conn *conn, struct irc_cmd_handler *handlers, void *arg)
 {
-    struct irc_cmd_chain *item;
-
-    // allocate the chain item
-    if ((item = calloc(1, sizeof(*item))) == NULL)
-        return ERR_CALLOC;
-
-    // store
-    item->handlers = handlers;
-    item->arg = arg;
-
-    // append
-    STAILQ_INSERT_TAIL(&conn->handlers, item, node);
-
-    // ok
-    return SUCCESS;
+    // use the irc_cmd stuff
+    return irc_cmd_add(&conn->handlers, handlers, arg);
 }
 
 err_t irc_conn_register (struct irc_conn *conn, const struct irc_conn_register_info *info)