implement irc_chan_callbacks, and add on_msg
authorTero Marttila <terom@fixme.fi>
Thu, 12 Mar 2009 18:35:05 +0200
changeset 38 0c2e0cb46c3a
parent 37 4fe4a3c4496e
child 39 a4891d71aca9
implement irc_chan_callbacks, and add on_msg
src/irc_chan.c
src/irc_chan.h
src/irc_log.c
src/irc_net.c
--- a/src/irc_chan.c	Thu Mar 12 18:11:44 2009 +0200
+++ b/src/irc_chan.c	Thu Mar 12 18:35:05 2009 +0200
@@ -24,17 +24,30 @@
         chan->state.joined = true;
 
         log_info("joined channel: %s", chan->info.channel);
+        
+        // invoke callback
+        IRC_CHAN_INVOKE_CALLBACK(chan, on_self_join);
+    }
+}
 
-        // TODO: callbacks
-    }
+/**
+ * :nm PRIVMSG <channel> <message>
+ */
+static void irc_chan_on_PRIVMSG (const struct irc_line *line, void *arg)
+{
+    struct irc_chan *chan = arg;
+
+    // invoke callback (prefix, message)
+    IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, line->prefix, line->args[1]);
 }
 
 /**
  * Core command handlers
  */
 struct irc_cmd_handler _cmd_handlers[] = {
-    {   "JOIN",     &irc_chan_on_JOIN   },
-    {   NULL,       NULL                }
+    {   "JOIN",     &irc_chan_on_JOIN       },
+    {   "PRIVMSG",  &irc_chan_on_PRIVMSG    },
+    {   NULL,       NULL                    }
 };
 
 err_t irc_chan_create (struct irc_chan **chan_ptr, struct irc_net *net, const struct irc_chan_info *info, struct error_info *err)
@@ -51,6 +64,7 @@
 
     // init
     irc_cmd_init(&chan->handlers);
+    CHAIN_INIT(&chan->callbacks);
     
     // add handlers
     if ((ERROR_CODE(err) = irc_cmd_add(&chan->handlers, _cmd_handlers, chan)))
@@ -73,10 +87,18 @@
     // free command handlers
     irc_cmd_free(&chan->handlers);
 
+    // free callbacks
+    chain_free(&chan->callbacks);
+
     // free chan itself
     free(chan);
 }
 
+err_t irc_chan_add_callbacks (struct irc_chan *chan, const struct irc_chan_callbacks *callbacks, void *arg)
+{
+    return chain_add(&chan->callbacks, callbacks, arg);
+}
+
 err_t irc_chan_join (struct irc_chan *chan)
 {
     err_t err;
--- a/src/irc_chan.h	Thu Mar 12 18:11:44 2009 +0200
+++ b/src/irc_chan.h	Thu Mar 12 18:35:05 2009 +0200
@@ -29,9 +29,27 @@
 struct irc_chan_callbacks {
     /** Joined the channel */
     void (*on_self_join) (struct irc_chan *chan, void *arg);
+
+    /** Someone sent a message to the channel */
+    void (*on_msg) (struct irc_chan *chan, const char *prefix, const char *msg, void *arg);
 };
 
 /**
+ * Invoke the given callback with the given args
+ */
+#define IRC_CHAN_INVOKE_CALLBACK(chan, _cb_name_, ...)          \
+    do {                                                        \
+        struct chain_head *head;                                \
+                                                                \
+        CHAIN_FOREACH(&(chan)->callbacks, head) {               \
+            const struct irc_chan_callbacks *callbacks = head->chain;       \
+                                                                \
+            if (callbacks->_cb_name_)                           \
+                callbacks->_cb_name_((chan), ## __VA_ARGS__, head->arg);    \
+        }                                                       \
+    } while (0);
+
+/**
  * IRC channel state
  */
 struct irc_chan {
@@ -56,6 +74,9 @@
 
     /** General command handlers */
     irc_cmd_handlers_t handlers;
+
+    /** High-level user callbacks */
+    struct chain_list callbacks;
 };
 
 /**
@@ -81,6 +102,11 @@
 void irc_chan_destroy (struct irc_chan *chan);
 
 /**
+ * Add high-level irc_chan callbacks
+ */
+err_t irc_chan_add_callbacks (struct irc_chan *chan, const struct irc_chan_callbacks *callbacks, void *arg);
+
+/**
  * Send the initial JOIN message.
  *
  * The channel must be in the IRC_CHAN_INIT state, and will transition to the IRC_CHAN_JOINING state.
--- a/src/irc_log.c	Thu Mar 12 18:11:44 2009 +0200
+++ b/src/irc_log.c	Thu Mar 12 18:35:05 2009 +0200
@@ -14,19 +14,18 @@
 
 } _ctx;
 
-static void on_PRIVMSG (const struct irc_line *line, void *arg)
+static void on_chan_msg (struct irc_chan *chan, const char *prefix, const char *message, void *arg)
 {
     struct irc_log_ctx *ctx = arg;
 
     (void) ctx;
 
     // log it! :P
-    log_debug("%s: %s: %s", line->prefix, line->args[0], line->args[1]);
+    log_debug("%s: %s: %s", prefix, irc_chan_name(chan), message);
 }
 
-static struct irc_cmd_handler _cmd_handlers[] = {
-    {   "PRIVMSG",  &on_PRIVMSG     },
-    {   NULL,       NULL            }
+static struct irc_chan_callbacks _chan_callbacks = {
+    .on_msg         = on_chan_msg,
 };
 
 err_t irc_log_init (struct event_base *ev_base, const struct irc_log_info *info)
@@ -46,12 +45,16 @@
         log_info("log channel: %s", irc_chan_name(info->channel));
     }
 
-    // register for events
-    // XXX: need irc_chan API for this
-    if ((err = irc_conn_add_cmd_handlers(info->channel->net->conn, _cmd_handlers, ctx)))
-        return err;
+    // add channel callbacks
+    if ((err = irc_chan_add_callbacks(info->channel, &_chan_callbacks, ctx)))
+        goto error;
 
     // ok
     return SUCCESS;
+
+error:
+    // XXX: cleanup
+    
+    return err;
 }
 
--- a/src/irc_net.c	Thu Mar 12 18:11:44 2009 +0200
+++ b/src/irc_net.c	Thu Mar 12 18:35:05 2009 +0200
@@ -28,16 +28,15 @@
 };
 
 /**
- * :nm JOIN <channel>
- */ 
-static void irc_net_on_JOIN (const struct irc_line *line, void *arg)
+ * Propagate the command to the appropriate irc_chan based on the given name
+ */
+static void irc_net_propagate_chan (struct irc_net *net, const struct irc_line *line, const char *channel)
 {
-    struct irc_net *net = arg;
     struct irc_chan *chan;
 
     // look up channel
-    if ((chan = irc_net_get_chan(net, line->args[0])) == NULL) {
-        log_warn("unkown channel: %s", line->args[0]);
+    if ((chan = irc_net_get_chan(net, channel)) == NULL) {
+        log_warn("unknown channel: %s", channel);
         return;
     }
 
@@ -46,10 +45,41 @@
 }
 
 /**
+ * Propagate line to irc_chan based on args[0]
+ */ 
+static void irc_net_on_chan0 (const struct irc_line *line, void *arg)
+{
+    struct irc_net *net = arg;
+    
+    irc_net_propagate_chan(net, line, line->args[0]);
+}
+
+/**
+ * :nm PRIVMSG <target> <message>
+ *
+ * Either propagate to channel if found, otherwise handle as a privmsg
+ */
+static void irc_net_on_PRIVMSG (const struct irc_line *line, void *arg)
+{
+    struct irc_net *net = arg;
+
+    // XXX: does two lookups
+    if (irc_net_get_chan(net, line->args[0])) {
+        // short-circuit to on_chan0
+        irc_net_on_chan0(line, arg);
+    
+    } else {
+        // XXX: callbacks for privmsgs
+        
+    }
+}
+
+/**
  * Our irc_cmd handler list
  */
 static struct irc_cmd_handler _cmd_handlers[] = {
-    {   "JOIN",     &irc_net_on_JOIN        },
+    {   "JOIN",     &irc_net_on_chan0       },
+    {   "PRIVMSG",  &irc_net_on_PRIVMSG     },
     {   NULL,       NULL                    }
 };