--- a/src/nexus.c Mon Mar 16 00:11:15 2009 +0200
+++ b/src/nexus.c Mon Mar 16 00:55:07 2009 +0200
@@ -1,5 +1,4 @@
#include "nexus.h"
-#include "irc_log.h"
#include "signals.h"
#include "log.h"
@@ -8,41 +7,177 @@
#include <stdio.h>
#include <getopt.h>
#include <signal.h>
+#include <string.h>
#define DEFAULT_HOST "irc.fixme.fi"
#define DEFAULT_PORT "6667"
#define DEFAULT_PORT_SSL "6697"
+/**
+ * Command-line option codes
+ */
enum option_code {
- _OPT_LOG_BEGIN = 0x00ff,
+ OPT_HELP = 'h',
+ OPT_NETWORK = 'n',
+ OPT_CHANNEL = 'c',
+ OPT_MODULE = 'm',
+ OPT_CONFIG = 'C',
+
+ /** Options without short names */
+ _OPT_EXT_BEGIN = 0x00ff,
- OPT_LOG_DATABASE,
- OPT_LOG_CHANNEL,
};
+/**
+ * Command-line option definitions
+ */
static struct option options[] = {
- {"help", 0, NULL, 'h' },
- {"hostname", 1, NULL, 'H' },
- {"port", 1, NULL, 'P' },
- {"ssl", 0, NULL, 'S' },
- {"log-database", 1, NULL, OPT_LOG_DATABASE },
- {"log-channel", 1, NULL, OPT_LOG_CHANNEL },
- {0, 0, 0, 0 },
+ {"help", 0, NULL, OPT_HELP },
+ {"network", 1, NULL, OPT_NETWORK },
+ {"channel", 1, NULL, OPT_CHANNEL },
+ {"module", 1, NULL, OPT_MODULE },
+ {"config", 1, NULL, OPT_CONFIG },
+ {0, 0, 0, 0 },
};
-void usage (const char *exe)
+/**
+ * Display --help output on stdout
+ */
+static void usage (const char *exe)
{
printf("Usage: %s [OPTIONS]\n", exe);
printf("\n");
printf(" --help / -h display this message\n");
- printf(" --hostname / -H HOST set hostname to connect to\n");
- printf(" --port / -P PORT set service port to connect to\n");
- printf(" --ssl / -S use SSL\n");
- printf(" --log-database database connection string for logging\n");
- printf(" --log-channel channel to log\n");
+ printf(" --network / -n add an IRC network using '<name>:<hostname>[:<port>[:ssl]]' format\n");
+ printf(" --channel / -c add an IRC channel using '<network>:<channel>' format\n");
+ printf(" --module / -m add a module using '<name>:<path>' format\n");
+ printf(" --config / -C add a module configuration option using '<mod_name>:<name>[:<value>]' format\n");
}
-void on_sigint (evutil_socket_t sig, short what, void *arg)
+/**
+ * Parse and apply a --network option
+ */
+static err_t apply_network (struct nexus *nexus, char *opt, struct error_info *err)
+{
+ struct irc_net_info info = {
+ .network = NULL,
+ .hostname = NULL,
+ .service = DEFAULT_PORT,
+ .use_ssl = false,
+ .register_info = {
+ .nickname = "SpBotDev",
+ .username = "spbot-dev",
+ .realname = "SpBot (development version)"
+ }
+ };
+
+ // parse the required fields
+ if ((info.network = strsep(&opt, ":")) == NULL)
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing <name> field for --network");
+
+ if ((info.hostname = strsep(&opt, ":")) == NULL)
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing <hostname> field for --network");
+
+ // parse the optional fields
+ if (opt)
+ info.service = strsep(&opt, ":");
+
+ // parse any remaining flags
+ while (opt) {
+ char *flag = strsep(&opt, ":");
+
+ if (strcmp(flag, "ssl"))
+ info.use_ssl = true;
+
+ else
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "unrecognized flag for --network");
+ }
+
+ // create the net
+ if (irc_client_add_net(nexus->client, NULL, &info, err))
+ return ERROR_CODE(err);
+
+ // ok
+ return SET_ERROR(err, SUCCESS);
+}
+
+/**
+ * Parse and apply a --channel option
+ */
+static err_t apply_channel (struct nexus *nexus, char *opt, struct error_info *err)
+{
+ const char *network = NULL;
+ struct irc_net *net;
+ struct irc_chan_info info = {
+ .channel = NULL,
+ };
+
+ // parse the required fields
+ if ((network = strsep(&opt, ":")) == NULL)
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing <network> field for --channel");
+
+ if ((info.channel = strsep(&opt, ":")) == NULL)
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing <channel> field for --channel");
+
+ // trailing garbage?
+ if (opt)
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "trailing values for --channel");
+
+ // look up the net
+ if ((net = irc_client_get_net(nexus->client, network)) == NULL)
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "unknown network for --channel");
+
+ // add the channel
+ if (irc_net_add_chan(net, NULL, &info, err))
+ return ERROR_CODE(err);
+
+ // ok
+ return SUCCESS;
+}
+
+/**
+ * Parse arguments and apply them to the given nexus
+ */
+static err_t parse_args (struct nexus *nexus, int argc, char **argv, struct error_info *err)
+{
+ int opt, option_index;
+
+ // parse options
+ while ((opt = getopt_long(argc, argv, "hn:c:m:C:", options, &option_index)) != -1) {
+ switch (opt) {
+ case OPT_HELP:
+ usage(argv[0]);
+
+ // XXX: return instead
+ exit(EXIT_SUCCESS);
+
+ case OPT_NETWORK:
+ if (apply_network(nexus, optarg, err))
+ return ERROR_CODE(err);
+
+ break;
+
+ case OPT_CHANNEL:
+ if (apply_channel(nexus, optarg, err))
+ return ERROR_CODE(err);
+
+ break;
+
+ case OPT_MODULE:
+ case OPT_CONFIG:
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "option unimplemented");
+
+ case '?':
+ usage(argv[0]);
+ return SET_ERROR(err, ERR_CMD_OPT);
+ }
+ }
+
+ // ok
+ return SUCCESS;
+}
+
+static void on_sigint (evutil_socket_t sig, short what, void *arg)
{
struct nexus *ctx = arg;
@@ -71,135 +206,47 @@
int main (int argc, char **argv)
{
- int opt, option_index;
struct signals *signals;
- struct nexus ctx;
- struct irc_net *net;
struct error_info err;
- struct irc_net_info net_info = {
- .network = "default",
- .hostname = DEFAULT_HOST,
- .service = DEFAULT_PORT,
- .use_ssl = false,
- .register_info = {
- .nickname = "SpBotDev",
- .username = "spbot-dev",
- .realname = "SpBot (development version)",
- }
- };
-
- // XXX: hardcode irc_log config
- char *log_db_info = NULL;
- struct irc_chan_info log_chan_info = {
- .channel = NULL,
- };
-
- bool port_default = true;
-
- // parse options
- while ((opt = getopt_long(argc, argv, "hH:P:S", options, &option_index)) != -1) {
- switch (opt) {
- case 'h':
- usage(argv[0]);
- return EXIT_SUCCESS;
+ struct nexus _nexus, *nexus = &_nexus;
- case 'H':
- net_info.hostname = optarg;
- break;
-
- case 'P':
- net_info.service = optarg;
- port_default = false;
- break;
-
- case 'S':
- net_info.use_ssl = true;
-
- if (port_default)
- net_info.service = DEFAULT_PORT_SSL;
-
- break;
-
- case OPT_LOG_DATABASE:
- log_db_info = optarg;
- break;
-
- case OPT_LOG_CHANNEL:
- log_chan_info.channel = optarg;
- break;
-
- case '?':
- usage(argv[0]);
- return EXIT_FAILURE;
- }
- }
+ // zero nexus
+ memset(nexus, 0, sizeof(*nexus));
// initialize libevent
- if ((ctx.ev_base = event_base_new()) == NULL)
+ if ((nexus->ev_base = event_base_new()) == NULL)
FATAL("event_base_new");
// initialize signal handlers
- if ((ERROR_CODE(&err) = signals_create(&signals, ctx.ev_base)))
+ if ((ERROR_CODE(&err) = signals_create(&signals, nexus->ev_base)))
FATAL("signals_create");
- // 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))
- FATAL_ERROR(&err, "irc_client_create");
-
- // the IRC network
- if (irc_client_add_net(ctx.client, &net, &net_info))
- FATAL_ERR(ERROR_CODE(&err), "irc_client_add_net");
-
// add our signal handlers
if (
(ERROR_CODE(&err) = signals_add(signals, SIGPIPE, &signals_ignore, signals))
- || (ERROR_CODE(&err) = signals_add(signals, SIGINT, &on_sigint, &ctx))
+ || (ERROR_CODE(&err) = signals_add(signals, SIGINT, &on_sigint, nexus))
)
FATAL_ERROR(&err, "signals_add");
-
- // logging?
- 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/libirc_log.so"
- };
-
- // load the module
- if (module_load(ctx.modules, &mod_irc_log, &mod_irc_log_info, &err))
- FATAL_ERROR(&err, "module_load");
+
+ // initialize sock module
+ if (sock_init(nexus->ev_base, &err))
+ FATAL_ERROR(&err, "sock_init");
- // get the channel
- 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");
+ // modules
+ if ((ERROR_CODE(&err) = modules_create(&nexus->modules, nexus)))
+ FATAL_ERROR(&err, "modules_create");
+
+ // the IRC client
+ if (irc_client_create(&nexus->client, &err))
+ FATAL_ERROR(&err, "irc_client_create");
- // 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);
- }
-
+ // parse args
+ if (parse_args(nexus, argc, argv, &err))
+ FATAL_ERROR(&err, "parse_args");
+
// run event loop
- if (event_base_dispatch(ctx.ev_base))
+ if (event_base_dispatch(nexus->ev_base))
FATAL("event_base_dispatch");
// ok, no cleanup