src/irc_chan.c
author Tero Marttila <terom@fixme.fi>
Thu, 12 Mar 2009 22:50:08 +0200
changeset 45 71e65564afd2
parent 39 a4891d71aca9
child 67 aa94bf2b5f9b
permissions -rw-r--r--
remove irc_chan.state, modify irc_chan_callbacks.on_msg to take a irc_nm, improve error handling a bit further (up to irc_net now)
#include "irc_chan.h"
#include "irc_proto.h"
#include "log.h"

#include <stdlib.h>
#include <assert.h>

const char* irc_chan_name (struct irc_chan *chan)
{
    return chan->info.channel;
}

/**
 * :nm JOIN <channel>
 */ 
static void irc_chan_on_JOIN (const struct irc_line *line, void *arg)
{
    struct irc_chan *chan = arg;

    // us?
    if (irc_prefix_cmp_nick(line->prefix, chan->net->conn->nickname) == 0) {
        // twiddle state
        chan->joining = false;
        chan->joined = true;

        log_info("joined channel: %s", chan->info.channel);
        
        // invoke callback
        IRC_CHAN_INVOKE_CALLBACK(chan, on_self_join);

    } else {
        // XXX: who cares
        
    }
}

/**
 * :nm PRIVMSG <channel> <message>
 */
static void irc_chan_on_PRIVMSG (const struct irc_line *line, void *arg)
{
    struct irc_chan *chan = arg;
    char prefix_buf[IRC_PREFIX_MAX];
    struct irc_nm *nm;
    err_t err;

    const char *msg = line->args[1];

    // parse nickmask
    if ((err = irc_nm_parse(nm, prefix_buf, line->prefix))) {
        log_warn("invalid prefix: %s", line->prefix);
        
        // invoke callback with NULL prefix
        IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, NULL, msg);

    } else {
        // invoke callback (prefix, message)
        IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, nm, msg);
    }
}

/**
 * Core command handlers
 */
struct irc_cmd_handler _cmd_handlers[] = {
    {   "JOIN",     &irc_chan_on_JOIN       },
    {   "PRIVMSG",  &irc_chan_on_PRIVMSG    },
    {   NULL,       NULL                    }
};

err_t irc_chan_create (struct irc_chan **chan_ptr, struct irc_net *net, const struct irc_chan_info *info, struct error_info *err)
{
    struct irc_chan *chan;

    // allocate
    if ((chan = calloc(1, sizeof(*chan))) == NULL)
        return SET_ERROR(err, ERR_CALLOC);

    // store
    chan->net = net;
    chan->info = *info;

    // init
    irc_cmd_init(&chan->handlers);
    CHAIN_INIT(&chan->callbacks);
    
    // add handlers
    if ((ERROR_CODE(err) = irc_cmd_add(&chan->handlers, _cmd_handlers, chan)))
        goto error;

    // ok
    *chan_ptr = chan;

    return SUCCESS;

error:
    // cleanup
    irc_chan_destroy(chan);

    return ERROR_CODE(err);
}

void irc_chan_destroy (struct irc_chan *chan)
{
    // free command handlers
    irc_cmd_free(&chan->handlers);

    // free callbacks
    chain_free(&chan->callbacks);

    // free chan itself
    free(chan);
}

err_t irc_chan_add_callbacks (struct irc_chan *chan, const struct irc_chan_callbacks *callbacks, void *arg)
{
    return chain_add(&chan->callbacks, callbacks, arg);
}

err_t irc_chan_join (struct irc_chan *chan)
{
    err_t err;

    // XXX: error instead?
    assert(!chan->joining && !chan->joined);
    assert(chan->net->conn);

    // send JOIN message on the appropriate connection
    if ((err = irc_conn_JOIN(chan->net->conn, chan->info.channel)))
        // XXX: error state?
        return err;

    // ok
    chan->joining = true;

    return SUCCESS;
}