/* Main header for OperStats

   OperStats - Copyright (c) 2000-2003 Darcy Grexton
   Contact: skold@habber.net, skold @ HabberNet

   See doc/LICENSE for licensing details.
 */

#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 operstats_exit /* Only allow OperStats 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		*/

/* User Modes */
#define UMODE_o		0x00000001	/* Opered		*/

/* Channel Modes */
#define CMODE_s		0x00000001	/* Secret Channel	*/

/* Size definitions for StatServ */
#define KB (1024.0)
#define MB (1024.0 * 1024.0)
#define GB (1024.0 * 1024.0 * 1024.0)
#define TB (1024.0 * 1024.0 * 1024.0 * 1024.0)

#define SIZENAME(x) ((x>TB) ? "TB" : (x>GB) ? "GB" : (x>MB) ? "MB" : (x>KB) ? "KB" : "bytes")
#define SIZEREAL(x) ((x>TB) ? (float)(x/TB) : (x>GB) ? (float)(x/GB) : (x>MB) ? (float)(x/MB) : (x>KB) ? (float)(x/KB) : (float)x)

/* 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 SSHASH(server) shash(server) % HASHSIZE	/* ServStats	*/
#define CLHASH(host) shash(host) % HASHSIZE	/* Clones	*/

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

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

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

/* 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	*/
    uint8 isonline;		/* Is the GlobalNoticer online? */
    uint8 wantnick;		/* Are we waiting for our nick?	*/
    uint8 collided;		/* How many collides?		*/
    time_t lastcoll;		/* Time of last collide		*/
} gn;

/* SpamServ's information */
struct sp
{
    char nickpre[NICKLEN];	/* SpamServ's nick prefix	*/
    char nick[NICKLEN];		/* SpamServ's nickname		*/
    char user[USERLEN];		/* SpamServ's username		*/
    char host[HOSTLEN];		/* SpamServ's hostname		*/
    char real[REALLEN];		/* SpamServ's realname		*/
    uint8 isonline;		/* Is SpamServ online?		*/
    time_t lastnick;		/* Time of last nick change	*/
} sp;

typedef struct user_ User;
typedef struct channel_ Channel;
typedef struct server_ Server;
typedef struct sra_ SRA;
typedef struct tld_ TLD;
typedef struct zone_ Zone;
typedef struct msg_ MSG;
typedef struct servstat_ ServStat;
typedef struct akill_ AutoKill;
typedef struct clone_ Clone;
typedef struct trigger_ Trigger;
typedef struct exception_ Exception;
typedef struct uline_ ULine;

/* User structure: One per user */
struct user_ {
    User *next, *prev;
    char nick[NICKLEN];		/* NickName			*/
    char *user;			/* UserName			*/
    char *host;			/* HostName			*/
    char *real;			/* RealName			*/
    char *server;		/* Server			*/
    time_t lastmsg;		/* Time of last message		*/
    uint8 isaway;		/* Are they away?		*/
    uint8 msgs;			/* Number of messages		*/
    uint8 offences;		/* How many floods		*/
    uint32 mode;		/* UserModes			*/
    uint32 flags;		/* User Flags			*/
    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 *topic;		/* Channel's Topic		*/
    uint32 mode;		/* Channel Modes		*/
    uint16 usercnt;		/* Nummber of users on channel	*/
    struct c_userlist {		/* Users on channel		*/
	struct c_userlist *next, *prev;
	User *user;		/* User's NickName		*/
    } *users;
};

/* Server structure: One per server */
struct server_ {
    Server *next, *prev;
    char name[HOSTLEN];		/* Server's name		*/
    char *uplink;		/* Server's uplink		*/
    time_t connect;		/* When it connected		*/
    struct timeval lastping;	/* When it was last pinged	*/
    struct timeval lastpong;	/* When it replied to a ping	*/
    uint8 hops;			/* How many hops away from us?	*/
};

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

/* Clone Triggers */
struct trigger_ {
    Trigger *next, *prev;
    char host[HOSTLEN];
    uint8 limit;
};

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

/* Top-Level-Domain list */
struct tld_ {
    TLD *next, *prev;
    char *name;			/* The actual TLD		*/
    char *desc;			/* Text description of TLD	*/
    uint32 cnt;			/* Number of clients from TLD	*/
    uint32 hits;		/* Daily hits to this TLD	*/
};

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

/* LogonMSGs */
struct msg_ {
    MSG *next, *prev;
    char *text;			/* Body of the LogonMSG		*/
    char *setter;		/* Who set the LogonMSG		*/
    time_t set;			/* When it was set		*/
};

/* Server statistics info */
struct servstat_ {
    ServStat *next, *prev;
    char *name;			/* Server's name		*/
    char *version;		/* Server's version reply	*/
    char *flags;		/* Flags from version reply	*/
    char *lastquit;		/* Server's last quit message	*/
    time_t statssince;		/* How far back the stats go	*/
    time_t lastsplit;		/* When it last split		*/
    time_t lastreport;		/* When we said it was lagged	*/
    time_t maxtime;		/* When we saw the max clients	*/
    time_t splittime;		/* When did it split?		*/
    time_t uptimetime;		/* When we last queried uptime	*/
    uint8 is_uline;		/* Is this server U:Lined?	*/
    uint8 is_split;		/* Is it split right now?	*/
    uint8 penalize;		/* Was it the source of a split?*/
    uint16 splits;		/* How many times has it split?	*/
    uint16 opers;		/* Current oper count		*/
    uint32 maxclients;		/* Maximum clients seen		*/
    uint32 clients;		/* Current client count		*/
    uint32 lastdowntime;	/* How long it was split last	*/
    uint32 uptime;		/* Last uptime response		*/
    uint32 maxuptime;		/* Highest recorded uptime	*/
    struct timeval lag;		/* Current lag			*/
    struct timeval peaklag;	/* Peak lag			*/
};

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

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

/* U:Lined servers */
struct uline_ {
    ULine *next, *prev;
    char *name;			/* Name of the server		*/
};

/* 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_SRA   2		/* SRA access needed		*/

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