/* Main header for Cygnus

   Cygnus IRC Services - Copyright (c) 2001-2002 Darcy Grexton
   Contact: skold@habber.net, skold @ HabberNet

   See doc/LICENSE for licensing details.
 */

#define _GNU_SOURCE

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <ctype.h>
#include "config.h"
#include "sysconf.h"
#include "response.h"

#ifndef WIN32
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <grp.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/socket.h>
#else
#include <winsock2.h>
#include <direct.h>
#include <windows.h>
#include <process.h>
#include <tchar.h>
#include "../win32.h"
#endif /* WIN32 */

#ifdef WIN32
#pragma warning (disable: 4018)

/* It's all different in Windows, redefine the odd thing */
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define printf printf_replacement
#define bcopy memmove
#define bzero(x, y) memset(x, 0, y)
#define random rand
#define close closesocket
#define write(p1, p2, p3) send(p1, p2, p3, 0)
#define read(p1, p2, p3) recv(p1, p2, p3, 0)
#define SIGUSR1 30
#define SIGHUP 1
#define log in_log
#define exit cygnus_exit /* Only allow Cygnus to call our -pseudo- exit */
typedef BOOL Boolean_T;

#else

/* True or False? This is used for toggles mainly. */
typedef enum {ERROR = -1,FALSE, TRUE} Boolean_T;

#endif /* WIN32 */

#ifndef WIN32
/* strcasecmp is better than stricmp. Doing this is better
   (read: easier) than renaming every call to stricmp and
   training myself to use strcasecmp instead.
 */
#define stricmp strcasecmp
#endif

/* Flags */
#define RUN_LIVE	0x00000001	/* Don't fork		*/
#define RUN_SHUTDOWN	0x00000002	/* Shut down		*/
#define RUN_RESTART	0x00000004	/* Shut down, restart	*/
#define RUN_STARTING	0x00000008	/* Starting up		*/
#define RUN_SAVEDBS	0x00000010	/* Save the DBs		*/

/* User Flags */
#define UF_SRA		0x00000001	/* Is an SRA		*/
#define UF_ENFORCED	0x00000002	/* Enforced, waiting	*/

/* NickName Flags */
#define NF_ENFORCE	0x00000001	/* NickName Enforcement	*/
#define NF_SECURE	0x00000002	/* NickName Security	*/
#define NF_HIDEMAIL	0x00000004	/* Hide E-Mail		*/
#define NF_SHOWMAIL	0x00000008	/* Show E-Mail		*/
#define NF_NEVEROP	0x00000010	/* Never Op (ChanServ)	*/
#define NF_NOOP		0x00000020	/* Can't add to CS Lists*/
#define NF_NOSUCCESSOR	0x00000040	/* Can't be successor	*/
#define NF_PRIVATE	0x00000080	/* Privacy Settings	*/
#define NF_NOTICE	0x00000100	/* Use NOTICE		*/
#define NF_PRIVMSG	0x00000200	/* Use PRIVMSG		*/
#define NF_NOMEMO	0x00000400	/* No Memos		*/
#define NF_RECEIPTS	0x00000800	/* Memo Receipts	*/
#define NF_MEMOMAIL	0x00001000	/* MemoMail		*/
#define NF_FROZEN	0x00002000	/* NickName is frozen	*/
#define NF_HELD		0x00004000	/* NickName is held	*/
#define NF_MARKED	0x00008000	/* NickName is marked	*/

/* Special NickName Flags */
#define NF_LINKED	0x10000000	/* Linked NickName	*/
#define NF_CSOP		0x20000000	/* Services Operator	*/
#define NF_NEWS		0x40000000	/* Hasn't read the NEWS	*/
#define NF_WAITAUTH	0x80000000	/* Waiting for Auth	*/

/* NickName Status Flags */
#define NS_RECOGNIZED	0x00000001	/* User is recognized	*/
#define NS_ENFORCED	0x00000002	/* Is an enforcer	*/

/* ChanServ Flags */
#define CF_VERBOSE	0x00000001	/* Verbose reporting	*/
#define CF_VOPALL	0x00000002	/* Auto +v on join	*/
#define CF_SECURE	0x00000004	/* Channel Security	*/
#define CF_RESTRICTED	0x00000008	/* Restricted Channel	*/
#define CF_FROZEN	0x00000010	/* Channel is frozen	*/
#define CF_HELD		0x00000020	/* Channel is held	*/
#define CF_MARKED	0x00000040	/* Channel is marked	*/
#define CF_LIMITED	0x00000080	/* Maintain +l		*/

/* Special Channel Flags */
#define CF_WAITAUTH	0x10000000	/* Waiting for Auth	*/
#define CF_WAITING	0x20000000	/* Waiting for Verify	*/

/* Memo Status Flags */
#define MF_UNREAD	0x00000001	/* Memo is Unread	*/
#define MF_EMAILED	0x00000002	/* Memo was E-Mailed	*/

/* User Modes */
#define UMODE_o		0x00000001	/* Opered		*/
#define UMODE_r		0x00000002	/* Identified		*/
#define UMODE_A		0x00000004	/* Server Admin		*/
#define UMODE_a		0x00000008	/* Services Admin	*/
#define UMODE_N		0x00000008	/* Network Admin	*/
#define UMODE_T		0x00000010	/* Technical Admin	*/

/* Channel Modes */
#define CMODE_t		0x00000001	/* Only ops change topic*/
#define CMODE_n		0x00000002	/* No external messages	*/
#define CMODE_s		0x00000004	/* Secret Channel	*/
#define CMODE_m		0x00000008	/* Moderated		*/
#define CMODE_l		0x00000010	/* Limited users	*/	
#define CMODE_i		0x00000020	/* Invite only		*/
#define CMODE_p		0x00000040	/* Private		*/
#define CMODE_k		0x00000080	/* Keyed		*/
#define CMODE_o		0x00000100	/* Op			*/
#define CMODE_v		0x00000200	/* Voice		*/
#define CMODE_R		0x00000400	/* Registered users only*/
#define CMODE_r		0x00000800	/* Registered channel	*/
#define CMODE_c		0x00001000	/* No colors allowed	*/
#define CMODE_O		0x00002000	/* Oper Only channel	*/
#define CMODE_Q		0x00004000	/* No non-U:Lined kicks	*/
#define CMODE_S		0x00008000	/* Strip color codes	*/
#define CMODE_K		0x00010000	/* No knocking		*/
#define CMODE_V		0x00020000	/* No inviting		*/
#define CMODE_f		0x00040000	/* Flood trigger	*/
#define CMODE_H		0x00080000	/* No hidden users	*/
#define CMODE_G		0x00100000	/* Strip bad words	*/
#define CMODE_C		0x00200000	/* No CTCPs/Ctrl Codes	*/
#define CMODE_u		0x00400000	/* Auditorium		*/
#define CMODE_z		0x00800000	/* Secure users only	*/
#define CMODE_N		0x01000000	/* No nick changes	*/
#define CMODE_L		0x02000000	/* Linked Channel	*/
#define CMODE_A		0x04000000	/* Admin Only channel	*/
#define CMODE_h		0x08000000	/* Half-Op		*/
#define CMODE_a		0x10000000	/* Protected		*/
#define CMODE_q		0x20000000	/* Channel Founder	*/

/* NickServ Timer Stuff */
#define TO_COLLIDE	0		/* Collide this nick?	*/
#define TO_RELEASE	1		/* Release an enforcer?	*/
#define TO_MESS40	2		/* 20 seconds left	*/
#define TO_MESS20	3		/* 40 seconds left	*/

/* ChanServ Timer Stuff */
#define TO_UNINHABIT	0		/* Part the channel	*/

/* Mode stacking stuff */
#define MAXMODES	6		/* Maximum stacked modes*/
#define MAXPARAMSLEN	(510-NICKLEN-CHANNELLEN-34-(7+MAXMODES))

/* Channel access list levels */
#define VOP		1		/* Voice Op		*/
#define HOP		2		/* Half Op		*/
#define AOP		3		/* Auto Op		*/
#define SOP		4		/* Super Op		*/
#define FOUNDER		5		/* Channel founder	*/

/* Hashes for various items */
#define CHASH(chan) shash(chan) % HASHSIZE	/* Channels	*/
#define NHASH(nick) shash(nick) % HASHSIZE	/* Users	*/
#define SVHASH(server) shash(server) % HASHSIZE	/* Servers	*/
#define MHASH(email) shash(email) % HASHSIZE	/* Mail		*/
#define CLHASH(host) shash(host) % HASHSIZE	/* Clones	*/
#define CSHASH(chan) shash(chan) % HASHSIZE	/* ChanInfo	*/
#define NSHASH(nick) shash(nick) % HASHSIZE	/* NickInfo	*/

/* Structure for our stuff */
struct me
{
    char uplink[HOSTLEN];	/* Address we connect to	*/
    int port;			/* Port we do it on		*/
    char pass[PASSWDLEN];	/* Password we use for the link	*/
    char ruplink[HOSTLEN];	/* Real name of our uplink	*/
    char bindhost[HOSTLEN];	/* Address to bind to		*/
    int bindport;		/* Port to bind to		*/
    int token;			/* True if our uplink has tokens*/
    char name[HOSTLEN];		/* Our server name		*/
    char desc[REALLEN];		/* Our description		*/
    time_t since;		/* When we started		*/
    time_t reset;		/* When we last reset		*/
} me;

/* RootServ's information */
struct rs
{
    char nick[NICKLEN];		/* Nick we want to have		*/
    char user[USERLEN];		/* RootServ's username		*/
    char host[HOSTLEN];		/* RootServ's hostname		*/
    char mode[12];		/* RootServ's modes		*/
    char real[REALLEN];		/* RootServ's realname		*/
    int isonline;		/* Is RootServ online?		*/
    int wantnick;		/* Are we waiting for our nick?	*/
    int collided;		/* How many collides?		*/
    int version;		/* Version of RootServ's DB	*/
    time_t lastcoll;		/* Time of last collide		*/
} rs;

/* NickServ's information */
struct ns
{
    char nick[NICKLEN];		/* Nick we want to have		*/
    char user[USERLEN];		/* NickServ's username		*/
    char host[HOSTLEN];		/* NickServ's hostname		*/
    char mode[12];		/* NickServ's modes		*/
    char real[REALLEN];		/* NickServ's realname		*/
    int isonline;		/* Is NickServ online?		*/
    int wantnick;		/* Are we waiting for our nick?	*/
    int collided;		/* How many collides?		*/
    int version;		/* Version of NickServ's DB	*/
    time_t lastcoll;		/* Time of last collide		*/
} ns;

/* ChanServ's information */
struct cs
{
    char nick[NICKLEN];		/* Nick we want to have		*/
    char user[USERLEN];		/* ChanServ's username		*/
    char host[HOSTLEN];		/* ChanServ's hostname		*/
    char mode[12];		/* ChanServ's modes		*/
    char real[REALLEN];		/* ChanServ's realname		*/
    int isonline;		/* Is ChanServ online?		*/
    int wantnick;		/* Are we waiting for our nick?	*/
    int collided;		/* How many collides?		*/
    int version;		/* Version of ChanServ's DB	*/
    time_t lastcoll;		/* Time of last collide		*/
} cs;

/* MemoServ's information */
struct ms
{
    char nick[NICKLEN];		/* Nick we want to have		*/
    char user[USERLEN];		/* MemoServ's username		*/
    char host[HOSTLEN];		/* MemoServ's hostname		*/
    char mode[12];		/* MemoServ's modes		*/
    char real[REALLEN];		/* MemoServ's realname		*/
    int isonline;		/* Is MemoServ online?		*/
    int wantnick;		/* Are we waiting for our nick?	*/
    int collided;		/* How many collides?		*/
    time_t lastcoll;		/* Time of last collide		*/
} ms;

/* GlobalNoticer's information */
struct gn
{
    char nick[NICKLEN];		/* Nick we want to have		*/
    char user[USERLEN];		/* GlobalNoticer's username	*/
    char host[HOSTLEN];		/* GlobalNoticer's hostname	*/
    char mode[12];		/* GlobalNoticer's modes	*/
    char real[REALLEN];		/* GlobalNoticer's realname	*/
    int isonline;		/* Is the GlobalNoticer online? */
    int wantnick;		/* Are we waiting for our nick?	*/
    int collided;		/* How many collides?		*/
    time_t lastcoll;		/* Time of last collide		*/
} gn;

typedef struct user_ User;
typedef struct channel_ Channel;
typedef struct server_ Server;
typedef struct sra_ SRA;
typedef struct zone_ Zone;
typedef struct akill_ AutoKill;
typedef struct verify_ Verify;
typedef struct mail_ Mail;
typedef struct timeout_ Timeout;
typedef struct nickinfo_ NickInfo;
typedef struct chaninfo_ ChanInfo;
typedef struct memo_ Memo;
typedef struct clone_ Clone;
typedef struct trigger_ Trigger;
typedef struct exception_ Exception;

/* User structure: One per user */
struct user_ {
    User *next, *prev;
    char nick[NICKLEN];		/* NickName			*/
    char *user;			/* UserName			*/
    char *host;			/* HostName			*/
    char *fakehost;		/* Fake (masked) hostname	*/
    char *real;			/* RealName			*/
    char *server;		/* Server			*/
    char *lastnick;		/* Last nickname user id'd for	*/
    char **idchans;		/* Channels user id'd for	*/
    int32 idchancnt;		/* Number of channels id'd for	*/
    int32 flags;		/* User Flags			*/
    int32 mode;			/* UserModes			*/
    int32 sstamp;		/* Services Stamp		*/
    int32 passfail;		/* # of failed IDENTIFY's	*/
    int32 msgs;			/* Number of messages		*/
    int32 offences;		/* How many floods		*/
    time_t lastmsg;		/* Time of last message		*/
    time_t timestamp;		/* TimeStamp			*/
    time_t lastnreg;		/* Time of last nick REGISTER	*/
    time_t lastcreg;		/* Time of last chan REGISTER	*/
    time_t lastmemo;		/* Time of last memo send	*/
    time_t lastnotify;		/* Last new memo notification	*/
    struct u_chanlist {		/* Channels user is on		*/
	struct u_chanlist *next, *prev;
	Channel *chan;		/* Channel Name			*/
    } *chans;
};

/* Channel structure: One per channel */
struct channel_ {
    Channel *next, *prev;
    char name[CHANNELLEN];	/* Channel Name			*/
    char *key;			/* Channel's +k key		*/
    char *link;			/* Channel this one is linked to*/
    char *flood;		/* Channel flood trigger	*/
    char **bans;		/* Bans on the channel		*/
    char topic[TOPICLEN];	/* Channel's Topic		*/
    char topicsetter[NICKLEN];	/* Who set the topic		*/
    time_t topictime;		/* When the topic was set	*/
    time_t lastlimit;		/* When did we last set a limit?*/
    int32 mode;			/* Channel Modes		*/
    int32 limit;		/* Channel's +l limit		*/
    int32 bancnt;		/* Number of bans on channel	*/
    int usercnt;		/* Number of users on channel	*/
    struct c_userlist {		/* Users on channel		*/
	struct c_userlist *next, *prev;
	User *user;		/* User's NickName		*/
	int32 mode;		/* Mode on channel		*/
    } *users;
};

/* Server structure: One per server */
struct server_ {
    Server *next, *prev;
    char name[HOSTLEN];		/* Server's name		*/
    char *uplink;		/* Server's uplink		*/
};

/* SRAs */
struct sra_ {
    SRA *next, *prev;
    char *nick;			/* SRA's nickname		*/
    char *pass;			/* SRA's password		*/
};

/* TimeZone list */
struct zone_ {
    Zone *next, *prev;
    int zindex;			/* Index number of this TimeZone*/
    char *name;			/* TimeZone Name (ie, PST)	*/
    char *noffset;		/* Named offset (ie, -0800)	*/
    char *desc;			/* Full Description		*/
    int offset;			/* GMT Offset in seconds	*/
};

/* Clone Triggers */
struct trigger_ {
    Trigger *next, *prev;
    char host[HOSTLEN];		/* Host for the Trigger		*/
    int limit;			/* Amount this host can have	*/
};

/* Clone Exceptions */
struct exception_ {
    Exception *next, *prev;
    char host[HOSTLEN];		/* Host for the Exception	*/
};

/* AKill structure */
struct akill_ {
    char *mask;			/* Mask that's AKilled		*/
    char *reason;		/* Reason for the AKill		*/
    char *setter;		/* Who set the AKill		*/
    int realname;		/* Is it a realname AKill?	*/
    time_t set;			/* When the AKill was set	*/
    time_t expires;		/* When the AKill expires	*/
};

struct timeout_ {
    Timeout *next, *prev;
    time_t settime;		/* When it was set		*/
    uint32 timeout;		/* When it triggers		*/
    int repeat;			/* Does this timeout repeat?	*/
    void (*code)(Timeout *);	/* This structure is passed on	*/
    void *data;			/* Can be anything		*/
};

/* Clone structure */
struct clone_ {
    Clone *next, *prev;
    char host[HOSTLEN];		/* Host for this record		*/
    int cnt;			/* Number of connections	*/
    int kills;			/* Number of kills		*/
    time_t lastkill;		/* When we last killed this host*/
};

/* Verification structure */
struct verify_ {
    char *name;			/* Object waiting to be verified*/
    time_t since;		/* How long it's been waiting	*/
};

/* List of addresses we've E-Mailed */
struct mail_ {
    Mail *next, *prev;
    char *email;		/* The address.			*/
    int times;			/* How many times we've emailed	*/
    time_t since;		/* First time we E-Mailed it	*/
};

/* Channel Access List:
      0: Not in use
      1: VOP
      2: HOP (Unreal only)
      3: AOP
      4: SOP
      5: Founder
 */
typedef struct {
    int32 level;		/* Level of this entry		*/
    char *mask;			/* Mask of entry		*/
} ChanAccess;

/* Channel AKick List */
typedef struct {
    char *mask;			/* Mask of entry		*/
    char *reason;		/* Reason for the AKick		*/
    char setter[NICKLEN];	/* Who set the AKick		*/
    time_t time;		/* When it was set		*/
    int32 level;		/* Level of this entry		*/
} AKick;

/* Memo structure */
struct memo_ {
    int32 number;		/* Memo Number			*/
    int32 flags;		/* Memos flags			*/
    time_t time;		/* When it was sent		*/
    char sender[NICKLEN];	/* Who sent it			*/
    char *text;			/* Actual memo			*/
};

/* Memo Info */
typedef struct {
    int memocnt;		/* Number of memos they have	*/
    int memolimit;		/* Max memos they can have	*/
    Memo *memos;		/* Memo data			*/
} MemoInfo;

/* NickName Information structure */
struct nickinfo_ {
    NickInfo *next, *prev;
    char nick[NICKLEN];		/* Registered NickName		*/
    char pass[PASSWDLEN];	/* Password for NickName	*/
    char *host;			/* Nick this one is linked to	*/
    char *usermask;		/* Last user@host mask		*/
    char *real;			/* Last RealName		*/
    char **access;		/* NickName's Access List	*/
    char **links;		/* List of linked nicks		*/
    char **chans;		/* List of channels owned	*/
    char **successor;		/* List of successor channels	*/
    char *email;		/* E-Mail address		*/
    char *url;			/* URL				*/
    char *name;			/* Real Name			*/
    char *sex;			/* Sex				*/
    char *location;		/* Location			*/
    char *forward;		/* NickName to forward memos to	*/
    char *freezereason;		/* Optional reason for Freeze	*/
    char *temp;			/* For use with temp emails	*/
    unsigned long key;		/* NickServ Key			*/
    int32 age;			/* Age				*/
    int32 uin;			/* ICQ UIN			*/
    int32 flags;		/* NickName Flags		*/
    int32 status;		/* NickName Status Flags	*/
    int32 sstamp;		/* Services' Stamp		*/
    int32 zone;			/* TimeZone this user prefers	*/
    int32 accesscnt;		/* Number of Access entries	*/
    int32 linkcnt;		/* Number of Linked Nicks	*/
    int32 chancnt;		/* Number of Channels owned	*/
    int32 successorcnt;		/* Number of Successor channels	*/
    time_t timestamp;		/* TimeStamp			*/
    time_t registered;		/* Time of Registration		*/
    time_t lastseen;		/* Last logoff after ID		*/
    time_t temptime;		/* For use with temp emails	*/
    MemoInfo memos;		/* NickName's Memos		*/
};

/* Channel Information structure */
struct chaninfo_ {
    ChanInfo *next, *prev;
    char name[CHANNELLEN];	/* Channel name			*/
    char founder[NICKLEN];	/* Channel founder		*/
    char pass[PASSWDLEN];	/* Channel password		*/
    char topic[TOPICLEN];	/* Channel topic		*/
    char topicsetter[NICKLEN];	/* Who set the topic		*/
    char *successor;		/* Channel successor		*/
    char *greet;		/* Channel Greet message	*/
    char *url;			/* Channel URL			*/
    char *mlock_key;		/* MLock key			*/
    char *mlock_flood;		/* MLock flood			*/
    char *mlock_link;		/* MLock link			*/
    ChanAccess *access;		/* Access list			*/
    AKick *akick;		/* AutoKick List		*/
    int32 accesscnt;		/* Number of entries in access	*/
    int32 akickcnt;		/* Number of AKicks		*/
    int32 mlock_on;		/* Modes locked on		*/
    int32 mlock_off;		/* Modes locked off		*/
    int32 mlock_limit;		/* MLock limit			*/
    int32 topiclock;		/* TopicLock setting		*/    
    int32 memolevel;		/* MemoLevel setting		*/
    int32 flags;		/* Channel Flags		*/
    time_t topictime;		/* When the topic was set	*/
    time_t registered;		/* Time of Registration		*/
    time_t lastused;		/* Time of last usage		*/
    unsigned long key;		/* ChanServ Key			*/
};

/* Commands we understand: See process.c */
typedef struct {
    const char *name;		/* Name of the command		*/
    void (*func) (char *source, int8 ac, char **av);
} Message;

extern Message messages[];
extern Message *find_message (const char *name);

/* Struct for help, command and subcommand hash tables */
typedef struct {
    char *accept;		/* Name of the command		*/
    short access;		/* Access needed to use command	*/
    void (*process) (User *u);
} Hash;

extern Hash *get_hash (const char *whoami, User *u, const char *cmd, Hash *hash_table); 
extern Hash *get_sub_hash (const char *whoami, User *u, const char *cmd, Hash *hash_table);
extern Hash *get_help_hash (const char *whoami, User *u, const char *cmd, Hash *hash_table);

/* Hash table access levels */
#define H_NONE  0		/* No access. Everyone can use	*/
#define H_IRCOP 1		/* IRCOp access needed		*/
#define H_CSOP	2		/* CSOp access needed		*/
#define H_SRA   3		/* SRA access needed		*/

/* Channel modes we support */
struct flag {
    char mode;			/* Text version of the mode	*/
    int32 flag;			/* Flag version of the mode	*/
    char prefix;		/* Channel user mode prefix	*/
};

/* Hash table for channel modes */
static const struct flag cmodes[] = {
    {'t',	CMODE_t,	0},
    {'n',	CMODE_n,	0},
    {'s',	CMODE_s,	0},
    {'m',	CMODE_m,	0},
    {'l',	CMODE_l,	0},
    {'i',	CMODE_i,	0},
    {'p',	CMODE_p,	0},
    {'k',	CMODE_k,	0},
    {'r',	CMODE_r,	0},
    {'R',	CMODE_R,	0},
    {'c',	CMODE_c,	0},
    {'O',	CMODE_O,	0},
    {'Q',	CMODE_Q,	0},
    {'S',	CMODE_S,	0},
    {'K',	CMODE_K,	0},
    {'V',	CMODE_V,	0},
    {'f',	CMODE_f,	0},
    {'H',	CMODE_H,	0},
    {'G',	CMODE_G,	0},
    {'C',	CMODE_C,	0},
    {'u',	CMODE_u,	0},
    {'z',	CMODE_z,	0},
    {'N',	CMODE_N,	0},
    {'L',	CMODE_L,	0},
    {'A',	CMODE_A,	0},
    {0,		0}
};

static const struct flag cumodes[] = {
    {'o',	CMODE_o,	'@'},
    {'v',	CMODE_v,	'+'},
    {'h',	CMODE_h,	'%'},
    {'a',	CMODE_a,	'~'},
    {'q',	CMODE_q,	'*'},
    {0,		0,		0}
};

/* Mode stacking structure */
struct modedata
{
    time_t used;		/* When it was first used?		*/
    int last_add;		/* When the last mode was added		*/
    char channel[CHANNELLEN];	/* The channel these modes apply to	*/
    char sender[NICKLEN];	/* The sender (Usually ChanServ)	*/
    int32 binmodes_on;		/* The modes being applied		*/
    int32 binmodes_off;		/* The modes being removed		*/
    char opmodes[MAXMODES*2+1];
    char params[BUFSIZE];	/* Parameters for the modes		*/
    int nparams;		/* Number of parameters			*/
    int paramslen;		/* Length of the parameters		*/
    int dotopic;		/* Should we set the topic, too?	*/
    Timeout *timeout;		/* When these modes will be applied	*/
} modedata[3];

/* This needs to be down here so the stuff in services.h it uses works */
#include "extern.h"
