src/irc_chan.h
author Tero Marttila <terom@fixme.fi>
Wed, 27 May 2009 23:57:48 +0300
branchnew-lib-errors
changeset 217 7728d6ec3abf
parent 171 b54f393c3df0
permissions -rw-r--r--
nexus.c compiles
#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;

};

/**
 * Per-channel-user state. This is used to store the list of irc_user's on an irc_chan.
 *
 * The nickname is accessible via user->nickname.
 */
struct irc_chan_user {
    /** The per-network user info */
    struct irc_user *user;

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

/**
 * High-level IRC channel callbacks for convenience.
 *
 * These are based on the normal irc_chan::handlers interface, and you can use both freely.
 *
 * The on_self_* handlers are for actions that affect our own status on the channel, the rest are only for actions
 * done by other users.
 *
 * 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);

    /** We were kicked from the channel */
    void (*on_self_kicked) (struct irc_chan *chan, const struct irc_nm *source, const char *msg, void *arg);

    /** We sent a message to the channel using irc_chan_PRIVMSG */
    void (*on_self_msg) (struct irc_chan *chan, const char *msg, void *arg);

    /** We sent a notice to the channel using irc_chan_NOTICE */
    void (*on_self_notice) (struct irc_chan *chan, const char *msg, 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 was kicked from the channel. The irc_chan_user is still present */
    void (*on_kick)  (struct irc_chan *chan, const struct irc_nm *source, struct irc_chan_user *target, const char *msg, void *arg);

    /** Someone quit the channel. The irc_chan_user is still present */
    void (*on_quit) (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);
};

/**
 * Callback storage struct
 */
struct irc_chan_callback_item {
    CHAIN_ITEM_HEADER(irc_chan_callback_item);

    const struct irc_chan_callbacks *callbacks;

    void *arg;
};

/**
 * Persistent IRC channel state, part of irc_net.
 *
 * This stores the channel's info, status flags, users list, and handlers/callbacks.
 *
 * Create/get channels using the irc_net_add_chan()/irc_net_get_chan() interface, and then attach your own
 * callbacks/handlers using irc_chan_add_callbacks()/irc_chan::handlers and irc_cmd_add().
 *
 * Note that irc_net will propagate all relevant events for each channel.
 */
struct irc_chan {
    /** The network we're part of */
    struct irc_net *net;

    /** Our identifying info */
    struct irc_chan_info info;
    
    /** 
     * @defgroup irc_chan_state State flags 
     * @{ 
     */
    /** JOIN request sent, waiting for reply */
    bool joining;

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

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

    /** We were KICK'd from the channel */
    bool kicked;

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

    /** High-level user callbacks */
    CHAIN_HEAD_TYPE(irc_chan_callback_list, irc_chan_callback_item) callbacks;

    /** The irc_net::channels list */
    TAILQ_ENTRY(irc_chan) net_channels;
};

/**
 * 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.
 *
 * The contents of \a info will be copied.
 *
 * @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, error_t *err);

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

/**
 * Add a set of high-level irc_chan callbacks. Not all callbacks need to be implemented.
 */
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.
 *
 * Be careful not to hold on to this, as the irc_chan_user struct may be released if the user leaves the channel.
 *
 * @param chan the channel context
 * @param nickname the user's current nickname
 * @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.
 *
 * @param chan the channel to JOIN
 */
err_t irc_chan_join (struct irc_chan *chan);

/**
 * Send a normal PRIVMSG to the channel. If we're being pedantic, one should use NOTICE instead for messages sent in
 * reply to PRIVMSG's, but the real world is different.
 *
 * This also invokes any self_msg callbacks.
 *
 * @param chan the IRC channel
 * @param message the message to send
 */
err_t irc_chan_PRIVMSG (struct irc_chan *chan, const char *message);

/**
 * Send a NOTICE message to the channel.
 *
 * This also invokes any self_notice callbacks.
 *
 * @param chan the IRC channel
 * @param message the message to send
 */
err_t irc_chan_NOTICE (struct irc_chan *chan, const char *message);

#endif