add irc_chan module
authorTero Marttila <terom@fixme.fi>
Tue, 10 Mar 2009 01:11:12 +0200
changeset 26 aec062af155d
parent 25 56367df4ce5b
child 27 e6639132bead
add irc_chan module
Makefile
src/irc_chan.c
src/irc_chan.h
src/irc_log.c
src/irc_log.h
src/irc_net.c
src/irc_net.h
src/nexus.c
--- a/Makefile	Mon Mar 09 16:30:59 2009 +0200
+++ b/Makefile	Tue Mar 10 01:11:12 2009 +0200
@@ -38,7 +38,7 @@
 SOCK_OBJS = obj/sock.o obj/sock_tcp.o
 SOCK_GNUTLS_OBJS = obj/sock_gnutls.o
 LINEPROTO_OBJS = obj/line_proto.o
-IRC_OBJS = obj/irc_line.o obj/irc_conn.o obj/irc_net.o
+IRC_OBJS = obj/irc_line.o obj/irc_conn.o obj/irc_net.o obj/irc_chan.o
 IRC_LOG_OBJS = obj/irc_log.o
 
 # XXX: not yet there
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irc_chan.c	Tue Mar 10 01:11:12 2009 +0200
@@ -0,0 +1,48 @@
+#include "irc_chan.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+const char* irc_chan_name (struct irc_chan *chan)
+{
+    return chan->info.channel;
+}
+
+err_t irc_chan_create (struct irc_chan **chan_ptr, struct irc_net *net, const struct irc_chan_info *info, struct error_info *err)
+{
+    struct irc_chan *chan;
+
+    // allocate
+    if ((chan = calloc(1, sizeof(*chan))) == NULL)
+        return SET_ERROR(err, ERR_CALLOC);
+
+    // store
+    chan->net = net;
+    chan->info = *info;
+    chan->state = IRC_CHAN_INIT;
+
+    // ok
+    *chan_ptr = chan;
+
+    return SUCCESS;
+}
+
+err_t irc_chan_join (struct irc_chan *chan)
+{
+    err_t err;
+
+    // XXX: error instead?
+    assert(chan->state == IRC_CHAN_INIT);
+
+    // send JOIN message on the appropriate connection
+    if ((err = irc_conn_JOIN(chan->net->conn, chan->info.channel)))
+        // XXX: state?
+        return err;
+
+    // ok, joining
+    chan->state = IRC_CHAN_JOINING;
+
+    // done
+    return SUCCESS;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irc_chan.h	Tue Mar 10 01:11:12 2009 +0200
@@ -0,0 +1,82 @@
+#ifndef IRC_CHAN_H
+#define IRC_CHAN_H
+
+/**
+ * @file
+ *
+ * Support for IRC channels, including tracking their state and actions on them.
+ */
+struct irc_chan_info;
+struct irc_chan;
+
+#include "irc_net.h"
+#include "error.h"
+#include <sys/queue.h>
+
+/**
+ * IRC channel info, as required to create an irc_chan
+ */
+struct irc_chan_info {
+    /** Channel name, with the [#&!] prefix */
+    const char *channel;
+
+};
+
+/**
+ * General IRC channel states
+ */
+enum irc_chan_state {
+    /** Initialized, but idle */
+    IRC_CHAN_INIT,
+
+    /** JOIN request sent */
+    IRC_CHAN_JOINING,
+
+    /** Currently joined to the channel */
+    IRC_CHAN_JOINED,
+};
+
+/**
+ * IRC channel state
+ */
+struct irc_chan {
+    /** The irc_net.channels list */
+    TAILQ_ENTRY(irc_chan) node;
+
+    /* The network we're on */
+    struct irc_net *net;
+
+    /** Our identifying info */
+    struct irc_chan_info info;
+    
+    /** Current state */
+    enum irc_chan_state state;
+};
+
+/**
+ * Return the channel's name
+ */
+const char* irc_chan_name (struct irc_chan *chan);
+
+/**
+ * Build/initialize a new irc_chan struct. This does not have any external side-effects.
+ *
+ * The channel will be in the IRC_CHAN_INIT state after this.
+ *
+ * @param chan_ptr the new irc_chan is returned via this pointer
+ * @param net the irc_net this channel is on
+ * @param info the channel's identifying information
+ * @param err error codes are returned via this
+ */
+err_t irc_chan_create (struct irc_chan **chan_ptr, struct irc_net *net, const struct irc_chan_info *info, struct error_info *err);
+
+/**
+ * Send the initial JOIN message.
+ *
+ * The channel must be in the IRC_CHAN_INIT state, and will transition to the IRC_CHAN_JOINING state.
+ *
+ * @param chan the channel to JOIN
+ */
+err_t irc_chan_join (struct irc_chan *chan);
+
+#endif
--- a/src/irc_log.c	Mon Mar 09 16:30:59 2009 +0200
+++ b/src/irc_log.c	Tue Mar 10 01:11:12 2009 +0200
@@ -18,6 +18,9 @@
 {
     struct irc_log_ctx *ctx = arg;
 
+    (void) conn;
+    (void) ctx;
+
     // log it! :P
     log_debug("%s: %s: %s", line->prefix, line->args[0], line->args[1]);
 }
@@ -27,29 +30,26 @@
     {   NULL,       NULL            }
 };
 
-err_t irc_log_init (struct event_base *ev_base, const char *db_info, struct irc_conn *irc, const char *channel)
+err_t irc_log_init (struct event_base *ev_base, const struct irc_log_info *info)
 {
     struct irc_log_ctx *ctx = &_ctx;
     err_t err;
 
     // open the database connection
-    if (db_info) {
-        log_info("connect to database: %s", db_info);
+    if (info->db_info) {
+        log_info("connect to database: %s", info->db_info);
 
-        if ((ctx->db = evsql_new_pq(ev_base, db_info, NULL, NULL)) == NULL)
+        if ((ctx->db = evsql_new_pq(ev_base, info->db_info, NULL, NULL)) == NULL)
            return ERR_EVSQL_NEW_PQ;
     }
     
-    if (channel) {
-        log_info("join channel: %s", channel);
-
-        // join the channel
-        if ((err = irc_conn_JOIN(irc, channel)))
-            return err;
+    if (info->channel) {
+        log_info("log channel: %s", irc_chan_name(info->channel));
     }
 
     // register for events
-    if ((err = irc_conn_register_handler_chain(irc, _cmd_handlers, ctx)))
+    // XXX: need irc_chan API
+    if ((err = irc_conn_register_handler_chain(info->channel->net->conn, _cmd_handlers, ctx)))
         return err;
 
     // ok
--- a/src/irc_log.h	Mon Mar 09 16:30:59 2009 +0200
+++ b/src/irc_log.h	Tue Mar 10 01:11:12 2009 +0200
@@ -6,16 +6,26 @@
  *
  * Logging IRC events to an SQL database
  */
-
 #include "error.h"
-#include "irc_conn.h"
+#include "irc_chan.h"
 #include <event2/event.h>
 
 /**
- * Initialize the global irc_log state
+ * Configuration state for irc_log
+ */
+struct irc_log_info {
+    /** Database connection string */
+    const char *db_info;
+
+    /** The channel to log */
+    struct irc_chan *channel;
+};
+
+/**
+ * Initialize the global irc_log module to use the given configuration
  *
  * XXX: db_info is still unused if not specified
  */
-err_t irc_log_init (struct event_base *ev_base, const char *db_info, struct irc_conn *irc, const char *channel);
+err_t irc_log_init (struct event_base *ev_base, const struct irc_log_info *info);
 
 #endif
--- a/src/irc_net.c	Mon Mar 09 16:30:59 2009 +0200
+++ b/src/irc_net.c	Tue Mar 10 01:11:12 2009 +0200
@@ -2,6 +2,7 @@
 #include "log.h"
 
 #include <stdlib.h>
+#include <string.h>
 
 err_t irc_net_create (struct irc_net **net_ptr, const struct irc_net_info *info, struct error_info *err)
 {
@@ -12,6 +13,9 @@
     if ((net = calloc(1, sizeof(*net))) == NULL)
         return SET_ERROR(err, ERR_CALLOC);
 
+    // initialize
+    TAILQ_INIT(&net->channels);
+
     // XXX: over-simplified blocking connect
     if (info->use_ssl) {
         log_info("connecting to [%s]:%s using SSL", info->hostname, info->service);
@@ -44,3 +48,41 @@
     return ERROR_CODE(err);
 }
 
+struct irc_chan* irc_net_add_chan (struct irc_net *net, const struct irc_chan_info *info)
+{
+    struct irc_chan *chan;
+    struct error_info err;
+
+    // create the new irc_chan struct
+    if (irc_chan_create(&chan, net, info, &err))
+        // XXX: we lose error info
+        return NULL;
+    
+    // add to network list
+    TAILQ_INSERT_TAIL(&net->channels, chan, node);
+
+    // then join
+    if ((ERROR_CODE(&err) = irc_chan_join(chan)))
+        // XXX
+        return NULL;
+
+    // ok, return
+    return chan;
+}
+
+struct irc_chan* irc_net_get_chan (struct irc_net *net, const char *channel)
+{
+    struct irc_chan *chan = NULL;
+
+    // look for it...
+    TAILQ_FOREACH(chan, &net->channels, node) {
+        if (strcasecmp(chan->info.channel, channel) == 0)
+            // found it
+            return chan;
+    }
+
+    // no such channel
+    return NULL;
+
+}
+
--- a/src/irc_net.h	Mon Mar 09 16:30:59 2009 +0200
+++ b/src/irc_net.h	Tue Mar 10 01:11:12 2009 +0200
@@ -9,6 +9,8 @@
  */
 #include "error.h"
 #include "irc_conn.h"
+#include "irc_chan.h"
+#include <sys/queue.h>
 
 /**
  * Configuration info for an IRC network
@@ -37,14 +39,32 @@
     /* The current connection */
     struct irc_conn *conn;
 
-
+    /** The list of IRC channel states */
+    TAILQ_HEAD(irc_net_chan_list, irc_chan) channels;
 };
 
 /**
  * Create a new IRC network state, using the given network info to connect/register.
  *
  * Errors are returned via *err, also returning the error code.
+ *
+ * @param net the new irc_net struct is returned via this pointer
+ * @param info network informated, used to connect and register
+ * @param err used to return extended error information
  */
 err_t irc_net_create (struct irc_net **net, const struct irc_net_info *info, struct error_info *err);
 
+/**
+ * Create a new irc_chan, add it to our channel list, and send the JOIN request.
+ */
+struct irc_chan* irc_net_add_chan (struct irc_net *net, const struct irc_chan_info *info);
+
+/**
+ * Look up an existing irc_chan by name, returning NULL if not found.
+ *
+ * @param net the network state
+ * @param channel the channel name
+ */
+struct irc_chan* irc_net_get_chan (struct irc_net *net, const char *channel);
+
 #endif
--- a/src/nexus.c	Mon Mar 09 16:30:59 2009 +0200
+++ b/src/nexus.c	Tue Mar 10 01:11:12 2009 +0200
@@ -62,7 +62,15 @@
             .realname               = "SpBot (development version)",
         }
     };
-    const char *log_database = NULL, *log_channel = NULL;
+
+    struct irc_chan_info log_chan_info = {
+        .channel                    = NULL, 
+    };
+
+    struct irc_log_info log_info = {
+        .db_info                    = NULL,
+        .channel                    = NULL,
+    };
 
     bool port_default = true;
     
@@ -91,11 +99,11 @@
                 break;
             
             case OPT_LOG_DATABASE:
-                log_database = optarg;
+                log_info.db_info = optarg;
                 break;
 
             case OPT_LOG_CHANNEL:
-                log_channel = optarg;
+                log_chan_info.channel = optarg;
                 break;
 
             case '?':
@@ -117,8 +125,13 @@
         FATAL_ERROR(&err, "irc_net_create");
     
     // logging?
-    if (log_database || log_channel) {
-        if ((ERROR_CODE(&err) = irc_log_init(ev_base, log_database, net->conn, log_channel)))
+    if (log_info.db_info || log_chan_info.channel) {
+        // get the channel
+        if (log_chan_info.channel && (log_info.channel = irc_net_add_chan(net, &log_chan_info)) == NULL)
+            FATAL("irc_net_add_chan");
+        
+        // init the irc_log module
+        if ((ERROR_CODE(&err) = irc_log_init(ev_base, &log_info)))
             FATAL_ERROR(&err, "irc_log_init");
     }