#include "nexus.h"
#include "irc_log.h"
#include "signals.h"
#include "log.h"
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <getopt.h>
#include <signal.h>
#define DEFAULT_HOST "irc.fixme.fi"
#define DEFAULT_PORT "6667"
#define DEFAULT_PORT_SSL "6697"
enum option_code {
_OPT_LOG_BEGIN = 0x00ff,
OPT_LOG_DATABASE,
OPT_LOG_CHANNEL,
};
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 },
};
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");
}
void on_sigint (evutil_socket_t sig, short what, void *arg)
{
struct nexus *ctx = arg;
(void) sig;
(void) what;
if (ctx->client && !ctx->client->quitting) {
log_info("Quitting...");
// quit it
irc_client_quit(ctx->client, "Goodbye, cruel world ;(");
} else {
log_error("Aborting");
// die
if (ctx->client) {
irc_client_destroy(ctx->client);
ctx->client = NULL;
}
// exit
event_base_loopexit(ctx->ev_base, NULL);
}
}
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;
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;
}
}
// initialize libevent
if ((ctx.ev_base = event_base_new()) == NULL)
FATAL("event_base_new");
// initialize signal handlers
if ((ERROR_CODE(&err) = signals_create(&signals, ctx.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))
)
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");
// 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");
// 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
if (event_base_dispatch(ctx.ev_base))
FATAL("event_base_dispatch");
// ok, no cleanup
return 0;
}