src/irc_chan.c
author Tero Marttila <terom@fixme.fi>
Thu, 12 Mar 2009 18:35:05 +0200
changeset 38 0c2e0cb46c3a
parent 37 4fe4a3c4496e
child 39 a4891d71aca9
permissions -rw-r--r--
implement irc_chan_callbacks, and add on_msg
#include "irc_chan.h"
#include "irc_nm.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->state.joining = false;
        chan->state.joined = true;

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

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

    // invoke callback (prefix, message)
    IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, line->prefix, line->args[1]);
}

/**
 * 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->state.joining && !chan->state.joined);

    // 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->state.joining = true;

    return SUCCESS;
}