# HG changeset patch # User Tero Marttila # Date 1237157707 -7200 # Node ID d399a1d915a3bd35dca8f3b9df14e06bef80ee4e # Parent e0dabc496f6411c6849787bf0ccc35f9860fc858 start reworking option-parsing, but --module/--config is still unimplemented diff -r e0dabc496f64 -r d399a1d915a3 src/error.c --- a/src/error.c Mon Mar 16 00:11:15 2009 +0200 +++ b/src/error.c Mon Mar 16 00:55:07 2009 +0200 @@ -17,6 +17,7 @@ { ERR_EVENT_NEW, "event_new", ERR_EXTRA_NONE }, { ERR_EVENT_ADD, "event_add", ERR_EXTRA_NONE }, { ERR_EVSQL_NEW_PQ, "evsql_new_pq", ERR_EXTRA_NONE }, + { ERR_CMD_OPT, "argv", ERR_EXTRA_STR }, { _ERR_INVALID, NULL, 0 } }, _sock_error_desc[] = { diff -r e0dabc496f64 -r d399a1d915a3 src/error.h --- a/src/error.h Mon Mar 16 00:11:15 2009 +0200 +++ b/src/error.h Mon Mar 16 00:55:07 2009 +0200 @@ -83,6 +83,10 @@ /** @see module_error_code */ _ERR_MODULE = 0x000a00, + + /** General errors */ + _ERR_GENERAL = 0xffff00, + ERR_CMD_OPT, }; /** diff -r e0dabc496f64 -r d399a1d915a3 src/irc_client.c --- a/src/irc_client.c Mon Mar 16 00:11:15 2009 +0200 +++ b/src/irc_client.c Mon Mar 16 00:55:07 2009 +0200 @@ -37,22 +37,22 @@ free(client); } -err_t irc_client_add_net (struct irc_client *client, struct irc_net **net_ptr, struct irc_net_info *net_info) +err_t irc_client_add_net (struct irc_client *client, struct irc_net **net_ptr, struct irc_net_info *net_info, struct error_info *err) { struct irc_net *net; - struct error_info err; // create the new irc_chan struct - if (irc_net_create(&net, net_info, &err)) - return ERROR_CODE(&err); + if (irc_net_create(&net, net_info, err)) + return ERROR_CODE(err); // add to network list TAILQ_INSERT_TAIL(&client->networks, net, client_networks); // ok - *net_ptr = net; + if (net_ptr) + *net_ptr = net; - return SUCCESS; + return SET_ERROR(err, SUCCESS); } struct irc_net* irc_client_get_net (struct irc_client *client, const char *network) diff -r e0dabc496f64 -r d399a1d915a3 src/irc_client.h --- a/src/irc_client.h Mon Mar 16 00:11:15 2009 +0200 +++ b/src/irc_client.h Mon Mar 16 00:55:07 2009 +0200 @@ -35,8 +35,12 @@ /** * Add a new IRC network + * + * @param client the irc_client state + * @param net_ptr used to return the new irc_net if not NULL + * @param net_info info required to identify and connect to the network */ -err_t irc_client_add_net (struct irc_client *client, struct irc_net **net_ptr, struct irc_net_info *net_info); +err_t irc_client_add_net (struct irc_client *client, struct irc_net **net_ptr, struct irc_net_info *net_info, struct error_info *err); /** * Get a pre-existing IRC network by name diff -r e0dabc496f64 -r d399a1d915a3 src/irc_net.c --- a/src/irc_net.c Mon Mar 16 00:11:15 2009 +0200 +++ b/src/irc_net.c Mon Mar 16 00:55:07 2009 +0200 @@ -220,15 +220,13 @@ free(net); } -struct irc_chan* irc_net_add_chan (struct irc_net *net, const struct irc_chan_info *info) +err_t irc_net_add_chan (struct irc_net *net, struct irc_chan **chan_ptr, const struct irc_chan_info *info, struct error_info *err) { 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; + if (irc_chan_create(&chan, net, info, err)) + return ERROR_CODE(err); // add to network list TAILQ_INSERT_TAIL(&net->channels, chan, node); @@ -236,13 +234,15 @@ // currently connected? if (net->conn && net->conn->registered) { // then join - if ((ERROR_CODE(&err) = irc_chan_join(chan))) - // XXX - return NULL; + if ((ERROR_CODE(err) = irc_chan_join(chan))) + return ERROR_CODE(err); } - // ok, return - return chan; + // ok + if (chan_ptr) + *chan_ptr = chan; + + return SUCCESS; } struct irc_chan* irc_net_get_chan (struct irc_net *net, const char *channel) diff -r e0dabc496f64 -r d399a1d915a3 src/irc_net.h --- a/src/irc_net.h Mon Mar 16 00:11:15 2009 +0200 +++ b/src/irc_net.h Mon Mar 16 00:55:07 2009 +0200 @@ -74,7 +74,7 @@ * * If we are connected and registered, JOIN the channel right away, otherwise, join it once we register. */ -struct irc_chan* irc_net_add_chan (struct irc_net *net, const struct irc_chan_info *info); +err_t irc_net_add_chan (struct irc_net *net, struct irc_chan **chan_ptr, const struct irc_chan_info *info, struct error_info *err); /** * Look up an existing irc_chan by name, returning NULL if not found. diff -r e0dabc496f64 -r d399a1d915a3 src/nexus.c --- 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 #include #include +#include #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 ':[:[:ssl]]' format\n"); + printf(" --channel / -c add an IRC channel using ':' format\n"); + printf(" --module / -m add a module using ':' format\n"); + printf(" --config / -C add a module configuration option using ':[:]' 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 field for --network"); + + if ((info.hostname = strsep(&opt, ":")) == NULL) + RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing 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 field for --channel"); + + if ((info.channel = strsep(&opt, ":")) == NULL) + RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing 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