src/irc_chan.h
author Tero Marttila <terom@fixme.fi>
Thu, 26 Mar 2009 22:54:25 +0200
changeset 74 11ec458d1cbf
parent 72 43084f103c2a
child 78 941bb8379d3d
permissions -rw-r--r--
add irc_chan_on_PART, irc_net_put_user and test_irc_chan_user_part
#ifndef IRC_CHAN_H
#define IRC_CHAN_H

/**
 * @file
 *
 * Support for IRC channels, including tracking their state and actions on them.
 */
struct irc_chan_info;
struct irc_chan;

#include "irc_net.h"
#include "irc_user.h"
#include "irc_cmd.h"
#include "irc_proto.h"
#include "error.h"
#include <sys/queue.h>

/**
 * IRC channel info, as required to create an irc_chan
 */
struct irc_chan_info {
    /** Channel name, with the [#&!] prefix */
    const char *channel;

};

/**
 * Semantic IRC channel callbacks.
 *
 * Where callbacks have irc_nm arguments, these are MAY be given as NULL if the prefix could not be parsed.
 */
struct irc_chan_callbacks {
    /** Joined the channel */
    void (*on_self_join) (struct irc_chan *chan, void *arg);

    /** We parted the channel */
    void (*on_self_part) (struct irc_chan *chan, void *arg);

    /** Someone joined the channel */
    void (*on_join) (struct irc_chan *chan, const struct irc_nm *source, void *arg);

    /** Someone parted the channel. The irc_chan_user is still present */
    void (*on_part) (struct irc_chan *chan, const struct irc_nm *source, const char *msg, void *arg);

    /** Someone sent a message to the channel */
    void (*on_msg) (struct irc_chan *chan, const struct irc_nm *source, const char *msg, void *arg);
};

/**
 * Invoke the given callback with the given args
 */
#define IRC_CHAN_INVOKE_CALLBACK(chan, _cb_name_, ...)          \
    do {                                                        \
        struct chain_head *head;                                \
                                                                \
        CHAIN_FOREACH(&(chan)->callbacks, head) {               \
            const struct irc_chan_callbacks *callbacks = head->chain;       \
                                                                \
            if (callbacks->_cb_name_)                           \
                callbacks->_cb_name_((chan), ## __VA_ARGS__, head->arg);    \
        }                                                       \
    } while (0);

/**
 * Per-channel-user state
 */
struct irc_chan_user {
    /** The per-network user info */
    struct irc_user *user;

    /** The irc_chan list */
    LIST_ENTRY(irc_chan_user) chan_users;
};

/**
 * IRC channel state
 */
struct irc_chan {
    /** The irc_net.channels list */
    TAILQ_ENTRY(irc_chan) node;

    /* The network we're on */
    struct irc_net *net;

    /** Our identifying info */
    struct irc_chan_info info;
    
    /** 
     * @group State flags 
     * @{ 
     */

    /** JOIN request sent, waiting for reply */
    bool joining;

    /** Currently joined to channel */
    bool joined;

    /** We PART'd the channel */
    bool parted;

    // @}
    
    /** List of users on channel */
    LIST_HEAD(irc_chan_users_list, irc_chan_user) users;
    
    /** General command handlers */
    irc_cmd_handlers_t handlers;

    /** High-level user callbacks */
    struct chain_list callbacks;
};

/**
 * Return the channel's name
 */
const char* irc_chan_name (struct irc_chan *chan);

/**
 * Build/initialize a new irc_chan struct. This does not have any external side-effects.
 *
 * The channel will be in the IRC_CHAN_INIT state after this.
 *
 * @param chan_ptr the new irc_chan is returned via this pointer
 * @param net the irc_net this channel is on
 * @param info the channel's identifying information
 * @param err error codes are returned via this
 */
err_t irc_chan_create (struct irc_chan **chan_ptr, struct irc_net *net, const struct irc_chan_info *info, struct error_info *err);

/**
 * Destroy irc_chan state, without doing anything to the network
 */
void irc_chan_destroy (struct irc_chan *chan);

/**
 * Add high-level irc_chan callbacks
 */
err_t irc_chan_add_callbacks (struct irc_chan *chan, const struct irc_chan_callbacks *callbacks, void *arg);

/**
 * Remove high-level irc_chan callbacks.
 */
void irc_chan_remove_callbacks (struct irc_chan *chan, const struct irc_chan_callbacks *callbacks, void *arg);

/**
 * Look up an irc_chan_user struct by nickname for this channel, returning NULL if no such chan_user exists.
 *
 * @param chan the channel context
 * @param nickname the user's current nickname
 * @param return the irc_chan_user state, or NULL if nickname not found
 */
struct irc_chan_user* irc_chan_get_user (struct irc_chan *chan, const char *nickname);

/**
 * Send the initial JOIN message.
 *
 * The channel must be in the IRC_CHAN_INIT state, and will transition to the IRC_CHAN_JOINING state.
 *
 * @param chan the channel to JOIN
 */
err_t irc_chan_join (struct irc_chan *chan);


#endif