merge modules -> default, this is a bit early as it breaks functionality, but who cares, need to replace the build system now :)
--- a/Makefile Fri Mar 13 16:10:48 2009 +0200
+++ b/Makefile Sun Mar 15 23:24:21 2009 +0200
@@ -34,28 +34,31 @@
# modules
module_objs = $(patsubst src/%.c,obj/%.o,$(wildcard src/$(1)/*.c))
-CORE_OBJS = obj/error.o obj/log.o obj/chain.o obj/signals.o
+CORE_OBJS = obj/error.o obj/log.o
SOCK_OBJS = obj/sock.o obj/sock_tcp.o
SOCK_TEST_OBJS = obj/sock_test.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 obj/irc_chan.o obj/irc_cmd.o obj/irc_proto.o obj/irc_client.o
+IRC_OBJS = obj/irc_line.o obj/irc_conn.o obj/irc_net.o obj/irc_chan.o obj/chain.o obj/irc_cmd.o obj/irc_proto.o obj/irc_client.o
+NEXUS_OBJS = obj/signals.o obj/module.o
IRC_LOG_OBJS = obj/irc_log.o
# XXX: not yet there
#CORE_OBJS = obj/lib/log.o obj/lib/signals.o
# first target
-all: ${BIN_PATHS}
+all: ${BIN_PATHS} modules/irc_log.so
# binaries
-bin/nexus: ${CORE_OBJS} ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS} ${LINEPROTO_OBJS} ${IRC_OBJS} ${IRC_LOG_OBJS}
+bin/nexus: ${CORE_OBJS} ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS} ${LINEPROTO_OBJS} ${IRC_OBJS} ${IRC_LOG_OBJS} ${NEXUS_OBJS}
bin/test: ${CORE_OBJS} ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS} ${SOCK_TEST_OBJS} ${LINEPROTO_OBJS} ${IRC_OBJS}
+modules/irc_log.so: ${CORE_OBJS}
+
# computed
-CFLAGS = ${MODE_CFLAGS} ${FIXED_CFLAGS} ${LIBEVENT_CFLAGS} ${GNUTLS_CFLAGS} ${EVSQL_CFLAGS}
-LDFLAGS = ${LIBEVENT_LDFLAGS} ${GNUTLS_LDFLAGS} ${EVSQL_LDFLAGS}
+CFLAGS = ${MODE_CFLAGS} ${FIXED_CFLAGS} ${LIBEVENT_CFLAGS} ${GNUTLS_CFLAGS} ${EVSQL_CFLAGS} -fpic
+LDFLAGS = ${LIBEVENT_LDFLAGS} ${GNUTLS_LDFLAGS} ${EVSQL_LDFLAGS} -Wl,--export-dynamic
# XXX: is this valid?
CPPFLAGS = ${CFLAGS}
@@ -94,6 +97,9 @@
bin/% : obj/%.o
$(CC) $(LDFLAGS) $+ $(LOADLIBES) $(LDLIBS) -o $@
+modules/%.so : obj/%.o
+ $(CC) -shared -Wl,-soname,$(notdir $@) -o $@ $+ -lc
+
# documentation
DOXYGEN_PATH = /usr/bin/doxygen
DOXYGEN_CONF_PATH = doc/doxygen.conf
--- a/src/error.c Fri Mar 13 16:10:48 2009 +0200
+++ b/src/error.c Sun Mar 15 23:24:21 2009 +0200
@@ -4,6 +4,7 @@
// for the error_desc tables
#include "sock.h"
#include "sock_gnutls.h"
+#include "module.h"
#include <string.h>
#include <stdio.h>
@@ -46,6 +47,12 @@
{ ERR_INVALID_NM, "Invalid nickmask", ERR_EXTRA_NONE },
{ ERR_INVALID_NICK_LENGTH, "Nickname is too long", ERR_EXTRA_NONE },
{ _ERR_INVALID, NULL, 0 }
+}, _module_error_desc[] = {
+ { ERR_MODULE_OPEN, "module dlopen() failed", ERR_EXTRA_STR },
+ { ERR_MODULE_NAME, "invalid module name", ERR_EXTRA_NONE },
+ { ERR_MODULE_INIT_FUNC, "invalid module init func", ERR_EXTRA_STR },
+ { ERR_MODULE_CONF, "module_conf", ERR_EXTRA_STR },
+ { _ERR_INVALID, NULL, 0 }
};
/**
@@ -56,6 +63,7 @@
_sock_error_desc,
_sock_gnutls_error_desc,
_irc_proto_error_desc,
+ _module_error_desc,
NULL
};
@@ -125,6 +133,11 @@
snprintf(msg, ERROR_MSG_MAXLEN, "%s: %s", desc->name, gnutls_strerror(err->extra));
break;
+ case ERR_EXTRA_STR:
+ // static error message string
+ snprintf(msg, ERROR_MSG_MAXLEN, "%s: %s", desc->name, err->extra_str);
+ break;
+
default:
// ???
snprintf(msg, ERROR_MSG_MAXLEN, "%s: %#.8x", desc->name, err->extra);
--- a/src/error.h Fri Mar 13 16:10:48 2009 +0200
+++ b/src/error.h Sun Mar 15 23:24:21 2009 +0200
@@ -29,6 +29,9 @@
/** GnuTLS, using gnutls_strerror() */
ERR_EXTRA_GNUTLS,
+
+ /** Static error message string */
+ ERR_EXTRA_STR,
};
/**
@@ -47,10 +50,10 @@
ERR_GETADDRINFO,
ERR_GETADDRINFO_EMPTY,
- /** @see enum sock_error_code*/
+ /** @see sock_error_code*/
_ERR_SOCK = 0x000300,
- /** @see enum sock_gnutls_error_code */
+ /** @see sock_gnutls_error_code */
_ERR_GNUTLS = 0x000400,
/** Libevent errors */
@@ -77,6 +80,9 @@
/** irc_net errors */
_ERR_IRC_NET = 0x000900,
ERR_IRC_NET_QUIT_STATE,
+
+ /** @see module_error_code */
+ _ERR_MODULE = 0x000a00,
};
/**
@@ -99,9 +105,14 @@
struct error_info {
/** The base error code */
err_t code;
+
+ union {
+ /** Additional detail info, usually some third-party error code, as defined by the code's ERR_EXTRA_* */
+ int extra;
- /** Additional detail info, usually some third-party error code, as defined by the code's ERR_EXTRA_* */
- int extra;
+ /** Additional info, stored as a pointer to a static string (note how dangerous this is) */
+ const char *extra_str;
+ };
};
/**
@@ -150,6 +161,13 @@
#define _SET_ERROR_ERRNO(err_info_ptr, err_code) _SET_ERROR_EXTRA(err_info_ptr, err_code, errno);
#define SET_ERROR_ERRNO(err_info_ptr, err_code) SET_ERROR_EXTRA(err_info_ptr, err_code, errno);
+/**
+ * Set error_info.code to err_code, and .extra_str to str. The given string pointer should remain valid while the error
+ * is being handled down-stack.
+ */
+#define _SET_ERROR_STR(err_info_ptr, err_code, err_str) (err_info_ptr)->code = (err_code); (err_info_ptr)->extra_str = (err_str)
+#define SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); } while(0)
+
/** Set error_info from another error_info. Evaluates to the new error_info */
#define SET_ERROR_INFO(err_info_ptr, from_ptr) (*err_info_ptr = *from_ptr)
@@ -158,9 +176,11 @@
#define RETURN_SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); return (err_code); } while (0)
#define RETURN_SET_ERROR_ERRNO(err_info_ptr, err_code) do { _SET_ERROR_ERRNO(err_info_ptr, err_code); return (err_code); } while (0)
#define RETURN_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); return (from_ptr->code); } while (0)
+#define RETURN_SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); return (err_code); } while (0)
/** Same as above, but also do a 'goto error' */
#define JUMP_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); goto error; } while (0)
#define JUMP_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); goto error; } while (0)
+#define JUMP_SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); goto error; } while (0)
#endif
--- a/src/irc_client.c Fri Mar 13 16:10:48 2009 +0200
+++ b/src/irc_client.c Sun Mar 15 23:24:21 2009 +0200
@@ -70,6 +70,18 @@
return NULL;
}
+struct irc_chan* irc_client_get_chan (struct irc_client *client, const char *network, const char *channel)
+{
+ struct irc_net *net;
+
+ // lookup network
+ if ((net = irc_client_get_net(client, network)) == NULL)
+ return NULL;
+
+ // and then return channel lookup
+ return irc_net_get_chan(net, channel);
+}
+
err_t irc_client_quit (struct irc_client *client, const char *message)
{
struct irc_net *net;
--- a/src/irc_client.h Fri Mar 13 16:10:48 2009 +0200
+++ b/src/irc_client.h Sun Mar 15 23:24:21 2009 +0200
@@ -44,6 +44,11 @@
struct irc_net* irc_client_get_net (struct irc_client *client, const char *network);
/**
+ * Get an irc_chan by network/channel name
+ */
+struct irc_chan* irc_client_get_chan (struct irc_client *client, const char *network, const char *channel);
+
+/**
* Quit cleanly from all our IRC networks.
*
* XXX: currently no way to indicate once we've quit all of them
--- a/src/irc_log.c Fri Mar 13 16:10:48 2009 +0200
+++ b/src/irc_log.c Sun Mar 15 23:24:21 2009 +0200
@@ -1,18 +1,27 @@
-#include "irc_log.h"
+#include "module.h"
+#include "irc_chan.h"
+#include "error.h"
#include "log.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include <event2/event.h>
// XXX: fix this err_t crap
#define LIB_ERR_H
#include <evsql.h>
/**
- * The core irc_log state
+ * The irc_log module state
*/
-static struct irc_log_ctx {
+struct irc_log_ctx {
+ /** The nexus this module is loaded for */
+ struct nexus *nexus;
+
/** The database connection */
struct evsql *db;
-} _ctx;
+};
static void on_chan_msg (struct irc_chan *chan, const struct irc_nm *source, const char *message, void *arg)
{
@@ -28,33 +37,67 @@
.on_msg = on_chan_msg,
};
-err_t irc_log_init (struct event_base *ev_base, const struct irc_log_info *info)
+static err_t irc_log_init (struct nexus *nexus, void **ctx_ptr, struct error_info *err)
{
- struct irc_log_ctx *ctx = &_ctx;
- err_t err;
-
- // open the database connection
- if (info->db_info) {
- log_info("connect to database: %s", info->db_info);
+ struct irc_log_ctx *ctx;
+
+ // allocate
+ if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+ return SET_ERROR(err, ERR_CALLOC);
- if ((ctx->db = evsql_new_pq(ev_base, info->db_info, NULL, NULL)) == NULL)
+ // initialize
+ memset(ctx, 0, sizeof(*ctx));
+
+ // store
+ ctx->nexus = nexus;
+
+ // ok
+ *ctx_ptr = ctx;
+
+ return SET_ERROR(err, SUCCESS);
+}
+
+static err_t irc_log_conf (void *mod_ctx, const char *name, char *value, struct error_info *err)
+{
+ struct irc_log_ctx *ctx = mod_ctx;
+
+ if (strcmp(name, "db_info") == 0) {
+ log_info("connect to database: %s", value);
+
+ if ((ctx->db = evsql_new_pq(ctx->nexus->ev_base, value, NULL, NULL)) == NULL)
return ERR_EVSQL_NEW_PQ;
+
+ } else if (strcmp(name, "channel") == 0) {
+ const char *network = strsep(&value, "/");
+ const char *channel = value;
+
+ struct irc_chan *chan;
+
+ // kill missing tokens
+ if (!network || !channel)
+ RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "invalid '<network>/<channel>' value");
+
+ // get the channel?
+ if ((chan = irc_client_get_chan(ctx->nexus->client, network, channel)) == NULL)
+ RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "unknown channel name");
+
+ // add channel callbacks
+ if ((ERROR_CODE(err) = irc_chan_add_callbacks(chan, &_chan_callbacks, ctx)))
+ return ERROR_CODE(err);
+
+ } else {
+ return -1;
+
}
-
- if (info->channel) {
- log_info("log channel: %s", irc_chan_name(info->channel));
- }
-
- // add channel callbacks
- if ((err = irc_chan_add_callbacks(info->channel, &_chan_callbacks, ctx)))
- goto error;
// ok
return SUCCESS;
-
-error:
- // XXX: cleanup
-
- return err;
}
+/**
+ * The module function table
+ */
+struct module_funcs irc_log_funcs = {
+ .init = &irc_log_init,
+ .conf = &irc_log_conf,
+};
--- a/src/irc_log.h Fri Mar 13 16:10:48 2009 +0200
+++ b/src/irc_log.h Sun Mar 15 23:24:21 2009 +0200
@@ -1,31 +1,1 @@
-#ifndef IRC_LOG_H
-#define IRC_LOG_H
-
-/**
- * @file
- *
- * Logging IRC events to an SQL database
- */
-#include "error.h"
-#include "irc_chan.h"
-#include <event2/event.h>
-/**
- * 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 struct irc_log_info *info);
-
-#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/module.c Sun Mar 15 23:24:21 2009 +0200
@@ -0,0 +1,100 @@
+#include "module.h"
+#include "log.h"
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <assert.h>
+
+err_t modules_create (struct modules **modules_ptr, struct nexus *nexus)
+{
+ struct modules *modules;
+
+ // alloc
+ if ((modules = calloc(1, sizeof(*modules))) == NULL)
+ return ERR_CALLOC;
+
+ // init
+ TAILQ_INIT(&modules->list);
+
+ // store
+ modules->nexus = nexus;
+
+ // ok
+ *modules_ptr = modules;
+
+ return SUCCESS;
+}
+
+/**
+ * Load the symbol named "<module>_<suffix>".
+ */
+static err_t module_symbol (struct module *module, void **sym, const char *suffix)
+{
+ char sym_name[MODULE_SYMBOL_MAX];
+
+ // validate the length of the suffix
+ assert(strlen(module->info.name) <= MODULE_NAME_MAX);
+ assert(strlen(suffix) <= MODULE_SUFFIX_MAX);
+
+ // format
+ sprintf(sym_name, "%s_%s", module->info.name, suffix);
+
+ // load
+ if ((*sym = dlsym(module->handle, sym_name)) == NULL)
+ return ERR_MODULE_SYM;
+
+ // ok
+ return SUCCESS;
+}
+
+err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *info, struct error_info *err)
+{
+ struct module *module;
+
+ // validate the module name
+ if (strlen(info->name) > MODULE_NAME_MAX)
+ return SET_ERROR(err, ERR_MODULE_NAME);
+
+ // alloc
+ if ((module = calloc(1, sizeof(*module))) == NULL)
+ return SET_ERROR(err, ERR_CALLOC);
+
+ // store
+ module->info = *info;
+
+ // clear dlerrors
+ (void) dlerror();
+
+ // load it
+ if ((module->handle = dlopen(info->path, RTLD_NOW)) == NULL)
+ JUMP_SET_ERROR_STR(err, ERR_MODULE_OPEN, dlerror());
+
+ // load the funcs symbol
+ if ((ERROR_CODE(err) = module_symbol(module, (void **) &module->funcs, "funcs")))
+ JUMP_SET_ERROR_STR(err, ERROR_CODE(err), dlerror());
+
+ // call the init func
+ if ((module->funcs->init(modules->nexus, &module->ctx, err)))
+ goto error;
+
+ // add to modules list
+ TAILQ_INSERT_TAIL(&modules->list, module, modules_list);
+
+ // ok
+ *module_ptr = module;
+
+ return SUCCESS;
+
+error:
+ // XXX: cleanup
+ free(module);
+
+ return ERROR_CODE(err);
+}
+
+err_t module_conf (struct module *module, const char *name, char *value, struct error_info *err)
+{
+ // call the conf func
+ return module->funcs->conf(module->ctx, name, value, err);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/module.h Sun Mar 15 23:24:21 2009 +0200
@@ -0,0 +1,141 @@
+#ifndef MODULE_H
+#define MODULE_H
+
+/**
+ * @file
+ *
+ * Dynamically loadable modules for use with nexus.
+ *
+ * The modules are loaded using dlopen(), and hence should be standard dynamic libraries. Module initialization happens
+ * using a module_init_func_t named "<name>_init", which should return some kind of context pointer, which can later be
+ * used to perform other operations on the module.
+ */
+#include "nexus.h"
+#include "error.h"
+
+#include <sys/queue.h>
+
+/**
+ * Information required to load/identify a module.
+ */
+struct module_info {
+ /** Human-readable name */
+ const char *name;
+
+ /** Filesystem path to the .so */
+ const char *path;
+};
+
+/**
+ * A module's behaviour is defined as a set of function pointers, which is dynamically resolved from the module DSO,
+ * using the <mod_name>_funcs symbol.
+ */
+struct module_funcs {
+ /**
+ * Initialize the module, returning an opaque context pointer that is stored in the module state, and supplied for
+ * subsequent calls. The supplied nexus arg can be used to access the global state.
+ *
+ * @param nexus a pointer to the nexus struct containing the global state
+ * @param ctx_ptr the context pointer should be returned via this
+ * @param err returned error info
+ */
+ err_t (*init) (struct nexus *nexus, void **ctx_ptr, struct error_info *err);
+
+ /**
+ * Set a configuration option with the given name and value, given by the user. Configuration settings are not
+ * regarded as unique-per-name, but rather, several invocations of 'conf' with the same name and different values
+ * could set up a multitude of things.
+ *
+ * XXX: make value a non-modifyable string
+ *
+ * @param ctx the module's context pointer as returned by init
+ * @param name the name of the configuration setting
+ * @param value the value of the configuration setting
+ * @param err returned error info
+ */
+ err_t (*conf) (void *ctx, const char *name, char *value, struct error_info *err);
+};
+
+/**
+ * A loaded module.
+ */
+struct module {
+ /** The identifying info for the module */
+ struct module_info info;
+
+ /** The dlopen handle */
+ void *handle;
+
+ /** The resolved function table */
+ struct module_funcs *funcs;
+
+ /** The module context object */
+ void *ctx;
+
+ /** Our entry in the list of modules */
+ TAILQ_ENTRY(module) modules_list;
+};
+
+/**
+ * A set of loaded modules, and functionality to load more
+ */
+struct modules {
+ /** The nexus in use */
+ struct nexus *nexus;
+
+ /** List of loaded modules */
+ TAILQ_HEAD(module_ctx_modules, module) list;
+};
+
+/**
+ * Possible error codes
+ */
+enum module_error_code {
+ _ERR_MODULE_BEGIN = _ERR_MODULE,
+
+ ERR_MODULE_OPEN, ///< dlopen() failed
+ ERR_MODULE_NAME, ///< invalid module_info.name
+ ERR_MODULE_SYM, ///< invalid symbol
+ ERR_MODULE_INIT_FUNC, ///< invalid module_init_func_t
+ ERR_MODULE_CONF, ///< value error in configuration data
+};
+
+
+/**
+ * Maximum length of a module name
+ */
+#define MODULE_NAME_MAX 24
+
+/**
+ * Maximum length of module symbol suffix
+ */
+#define MODULE_SUFFIX_MAX 16
+
+/**
+ * Maximum length of symbol name name, including terminating NUL
+ */
+#define MODULE_SYMBOL_MAX (MODULE_NAME_MAX + 1 + MODULE_SUFFIX_MAX + 1)
+
+/**
+ * Create a new modules state
+ */
+err_t modules_create (struct modules **modules_ptr, struct nexus *nexus);
+
+/**
+ * Load a new module
+ */
+err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *info, struct error_info *err);
+
+/**
+ * Set a module configuration option
+ */
+err_t module_conf (struct module *module, const char *name, char *value, struct error_info *err);
+
+/**
+ * Unload a module
+ *
+ * XXX: not implemented
+ */
+err_t module_unload (struct module *module);
+
+#endif
--- a/src/nexus.c Fri Mar 13 16:10:48 2009 +0200
+++ b/src/nexus.c Sun Mar 15 23:24:21 2009 +0200
@@ -44,7 +44,7 @@
void on_sigint (evutil_socket_t sig, short what, void *arg)
{
- struct nexus_ctx *ctx = arg;
+ struct nexus *ctx = arg;
(void) sig;
(void) what;
@@ -73,12 +73,12 @@
{
int opt, option_index;
struct signals *signals;
- struct nexus_ctx ctx;
+ struct nexus ctx;
struct irc_net *net;
struct error_info err;
struct irc_net_info net_info = {
- .network = NULL,
+ .network = "default",
.hostname = DEFAULT_HOST,
.service = DEFAULT_PORT,
.use_ssl = false,
@@ -89,15 +89,12 @@
}
};
+ // XXX: hardcode irc_log config
+ char *log_db_info = 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;
// parse options
@@ -125,7 +122,7 @@
break;
case OPT_LOG_DATABASE:
- log_info.db_info = optarg;
+ log_db_info = optarg;
break;
case OPT_LOG_CHANNEL:
@@ -149,6 +146,10 @@
// initialize sock module
if (sock_init(ctx.ev_base, &err))
FATAL_ERROR(&err, "sock_init");
+
+ // modules
+ if ((ERROR_CODE(&err) = modules_create(&ctx.modules, &ctx)))
+ FATAL_ERROR(&err, "modules_create");
// the IRC client
if (irc_client_create(&ctx.client, &err))
@@ -166,14 +167,35 @@
FATAL_ERROR(&err, "signals_add");
// logging?
- if (log_info.db_info || log_chan_info.channel) {
+ if (log_db_info || log_chan_info.channel) {
+ struct module *mod_irc_log;
+
+ struct module_info mod_irc_log_info = {
+ .name = "irc_log",
+ .path = "modules/irc_log.so"
+ };
+
+ // load the module
+ if (module_load(ctx.modules, &mod_irc_log, &mod_irc_log_info, &err))
+ FATAL_ERROR(&err, "module_load");
+
// 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(ctx.ev_base, &log_info)))
- FATAL_ERROR(&err, "irc_log_init");
+ if (log_chan_info.channel) {
+ char conf_channel[] = "default/#test";
+
+ // create the channel
+ if ((irc_net_add_chan(net, &log_chan_info)) == NULL)
+ FATAL("irc_net_add_chan");
+
+ // configure it
+ // XXX: hardcoded
+ if (module_conf(mod_irc_log, "channel", conf_channel, &err))
+ FATAL_ERROR(&err, "module_conf(irc_log, '%s', '%s)", "channel", conf_channel);
+ }
+
+ // configure the databse info
+ if (log_db_info && module_conf(mod_irc_log, "db_info", log_db_info, &err))
+ FATAL_ERROR(&err, "module_conf(irc_log, 'db_info', '%s')", log_db_info);
}
// run event loop
--- a/src/nexus.h Fri Mar 13 16:10:48 2009 +0200
+++ b/src/nexus.h Sun Mar 15 23:24:21 2009 +0200
@@ -4,16 +4,23 @@
/**
* A nexus is the central brain of the application; the place where the main() method is implemented
*/
+
+struct nexus;
+
#include <event2/event.h>
+#include "module.h"
#include "irc_client.h"
/**
* Context for async nexus operation
*/
-struct nexus_ctx {
+struct nexus {
/** The libevent base */
struct event_base *ev_base;
+ /** Our loaded modules */
+ struct modules *modules;
+
/** The IRC client state */
struct irc_client *client;
};