src/irc_conn.c
changeset 23 542c73d07d3c
parent 22 c339c020fd33
child 24 08a26d0b9afd
--- a/src/irc_conn.c	Sun Mar 01 02:02:48 2009 +0200
+++ b/src/irc_conn.c	Sun Mar 08 17:17:37 2009 +0200
@@ -9,7 +9,7 @@
 /*
  * "Welcome to the Internet Relay Network <nick>!<user>@<host>"
  */
-static void on_RPL_WELCOME (struct irc_conn *conn, const struct irc_line *line)
+static void on_RPL_WELCOME (struct irc_conn *conn, const struct irc_line *line, void *arg)
 {
     // update state
     conn->registered = true;
@@ -22,7 +22,7 @@
  *
  * Send a 'PONG <server1>` reply right away.
  */ 
-static void on_PING (struct irc_conn *conn, const struct irc_line *line)
+static void on_PING (struct irc_conn *conn, const struct irc_line *line, void *arg)
 {
     // just reply
     irc_conn_PONG(conn, line->args[0]);
@@ -31,23 +31,20 @@
 /*
  * Our command handlers
  */
-struct irc_cmd_handler {
-    /* The command name */
-    const char *command;
-
-    /* The handler function */
-    void (*func) (struct irc_conn *conn, const struct irc_line *line);
-
-} _cmd_handlers[] = {
+struct irc_cmd_handler _cmd_handlers[] = {
     { IRC_RPL_WELCOME,  on_RPL_WELCOME      },
     { "PING",           on_PING             },
     { NULL,             NULL,               },
 };
 
+/*
+ * Incoming line handler
+ */
 void irc_conn_on_line (char *line_buf, void *arg) 
 {
     struct irc_conn *conn = arg;
     struct irc_line line;
+    struct irc_cmd_chain *chain;
     struct irc_cmd_handler *handler;
     int err;
     
@@ -56,18 +53,22 @@
 
     // parse
     if ((err = irc_line_parse(&line, line_buf))) {
-        printf("!!! Invalid line: %s: %s\n", line_buf, error_name(err));
-        
+        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);
 
-    // look up appropriate handler
-    for (handler = _cmd_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);
-            break;
+                // ...only one per chain
+                break;
+            }
         }
     }
 }
@@ -80,6 +81,13 @@
     if ((conn = calloc(1, sizeof(struct irc_conn))) == NULL)
         return SET_ERROR(err, ERR_CALLOC);
 
+    // initialize command handlers
+    STAILQ_INIT(&conn->handlers);
+    
+    // add the core handlers 
+    if ((ERROR_CODE(err) = irc_conn_register_handler_chain(conn, _cmd_handlers, NULL)))
+        return ERROR_CODE(err);
+
     // create the line_proto, with our on_line handler
     if (line_proto_create(&conn->lp, sock, IRC_LINE_MAX * 1.5, &irc_conn_on_line, conn, err))
         return ERROR_CODE(err);
@@ -97,6 +105,25 @@
     return SUCCESS;
 }
 
+err_t irc_conn_register_handler_chain (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;
+}
+
 err_t irc_conn_send (struct irc_conn *conn, const struct irc_line *line)
 {
     char line_buf[IRC_LINE_MAX + 2];
@@ -148,3 +175,13 @@
     return irc_conn_send(conn, &line);
 }
 
+err_t irc_conn_JOIN (struct irc_conn *conn, const char *channel)
+{
+    // JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0"
+    struct irc_line line = {
+        NULL, "JOIN", { channel, NULL }
+    };
+
+    return irc_conn_send(conn, &line);
+}
+