src/nexus.c
author Tero Marttila <terom@fixme.fi>
Mon, 16 Mar 2009 00:09:53 +0200
branchbuild-cmake
changeset 61 4ba21936518a
parent 56 942370000450
child 63 d399a1d915a3
permissions -rw-r--r--
temporarily disable evsql stuff
#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;
}