#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