/* - Internet Relay Chat, include/client.h
 *   Copyright (C) 1990 Jarkko Oikarinen and
 *                      University of Oulu, Computing Center
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 1, or (at your option)
 *   any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 * $Id: client.h,v 1.3 2001/02/05 21:19:47 jpinto Exp $
 */
#ifndef INCLUDED_client_h
#define INCLUDED_client_h
#ifndef INCLUDED_config_h
#include "config.h"
#endif
#if !defined(CONFIG_H_LEVEL_6_1)
#error Incorrect config.h for this revision of ircd.
#endif
#ifndef INCLUDED_sys_types_h
#include <sys/types.h>       /* time_t */
#define INCLUDED_sys_types_h
#endif
#ifndef INCLUDED_netinet_in_h
#include <netinet/in.h>      /* in_addr */
#define INCLUDED_netinet_in_h
#endif
#if defined(HAVE_STDDEF_H)
# ifndef INCLUDED_stddef_h
#  include <stddef.h>        /* offsetof */
#  define INCLUDED_stddef_h
# endif
#endif
#ifndef INCLUDED_ircd_defs_h
# include "ircd_defs.h"
#endif
#ifndef INCLUDED_dbuf_h
#include "dbuf.h"
#endif

#define HOSTIPLEN       16      /* Length of dotted quad form of IP        */
                                /* - Dianora                               */
#define PASSWDLEN       20
#define IDLEN           12      /* this is the maximum length, not the actual
                                   generated length; DO NOT CHANGE! */
#define CLIENT_BUFSIZE 512      /* must be at least 512 bytes */

/*
 * pre declare structs
 */
struct SLink;
struct ConfItem;
struct Whowas;
struct fludbot;
struct Zdata;
struct Listener;
struct Client;

/*
 * Client structures
 */
struct User
{
  struct User*   next;          /* chain of anUser structures */
  struct SLink*  channel;       /* chain of channel pointer blocks */
  struct SLink*  invited;       /* chain of invite pointer blocks */
  struct SLink*  silence;       /* chain of silence pointer blocks  */
  char*          away;          /* pointer to away message */
  time_t         last;
  int            refcnt;        /* Number of times this block is referenced */
  char           joined;        /* number of channels joined */
//char           id[IDLEN + 1]; /* for future use *hint* */
  const char*    server;        /* pointer to scached server name */
  unsigned int	 news_mask;		/* user subscribed news bit mask */
  char*          vs;
  char*          vsd;
  char*          prefix;
  /*
  ** In a perfect world the 'server' name
  ** should not be needed, a pointer to the
  ** client describing the server is enough.
  ** Unfortunately, in reality, server may
  ** not yet be in links while USER is
  ** introduced... --msa
  */
  /* with auto-removal of dependent links, this may no longer be the
  ** case, but it's already fixed by the scache anyway  -orabidoo
  */
};

struct Server
{
  struct User*     user;        /* who activated this connection */
  const char*      up;          /* Pointer to scache name */
  char             by[NICKLEN + 1];
  struct ConfItem* nline;       /* N-line pointer for this server */
  struct Client*   servers;     /* Servers on this server */
  struct Client*   users;       /* Users on this server */
  char             version[HOSTLEN + 1]; /* server version */
};

struct Client
{
  struct Client*    next;
  struct Client*    prev;
  struct Client*    hnext;
  struct Client*    idhnext;

/* QS */

  struct Client*    lnext;      /* Used for Server->servers/users */
  struct Client*    lprev;      /* Used for Server->servers/users */

/* LINKLIST */
  /* N.B. next_local_client, and previous_local_client
   * duplicate the link list referenced to by struct Server -> users
   * someday, we'll rationalize this... -Dianora
   */

  struct Client*    next_local_client;      /* keep track of these */
  struct Client*    previous_local_client;

  struct Client*    next_server_client;
  struct Client*    next_oper_client;

  struct User*      user;       /* ...defined, if this is a User */
  struct Server*    serv;       /* ...defined, if this is a server */
  struct Client*    servptr;    /* Points to server this Client is on */
  struct Client*    from;       /* == self, if Local Client, *NEVER* NULL! */

  struct Whowas*    whowas;     /* Pointers to whowas structs */
  time_t            lasttime;   /* ...should be only LOCAL clients? --msa */
  time_t            firsttime;  /* time client was created */
  time_t            since;      /* last time we parsed something */
  time_t            tsinfo;     /* TS on the nick, SVINFO on server */
  time_t			nexttarget; /* Time until a change in targets is allowed */
  unsigned char 	targets[MAXTARGETS]; /* Hash values of current targets */
  unsigned int      umodes;     /* opers, normal users subset */
  unsigned int      flags;      /* client flags */
  unsigned int      flags2;     /* ugh. overflow */
  int               fd;         /* >= 0, for local clients */
  unsigned char     hopcount;   /* number of servers to this 0 = local */
  unsigned short    status;     /* Client type */
  unsigned char     nicksent;
  unsigned char     local_flag; /* if this is 1 this client is local */
  short    listprogress;        /* where were we when the /list blocked? */
  int      listprogress2;       /* where in the current bucket were we? */

  /*
   * client->name is the unique name for a client nick or host
   */
  char              name[HOSTLEN + 1]; 
  /* 
   * client->username is the username from ident or the USER message, 
   * If the client is idented the USER message is ignored, otherwise 
   * the username part of the USER message is put here prefixed with a 
   * tilde depending on the I:line, Once a client has registered, this
   * field should be considered read-only.
   */ 
  char              username[USERLEN + 1]; /* client's username */
  /*
   * client->realhost contains the resolved name or ip address
   * as a string for the user, it may be fiddled with for oper spoofing etc.
   * once it's changed the *real* address goes away. This should be
   * considered a read-only field after the client has registered.
   */
  char              realhost[HOSTLEN + 1];     /* client's hostname */
  /*
   * client->host contains a copy of client->realhost if client is coming
   * from a server not using hostname masking or the client hostname masked
   * at the client connection server.
   */
  char              host[HOSTLEN + 1];     /* client's hostname */  
  /*
   * client->info for unix clients will normally contain the info from the 
   * gcos field in /etc/passwd but anything can go here.
   */
  char              info[REALLEN + 1]; /* Free form additional client info */
#ifdef FLUD
  struct SLink*     fludees;
#endif
  /*
   * The following fields are allocated only for local clients
   * (directly connected to *this* server with a socket.
   * The first of them *MUST* be the "count"--it is the field
   * to which the allocation is tied to! *Never* refer to
   * these fields, if (from != self).
   */
  int               count;       /* Amount of data in buffer */
#ifdef FLUD
  time_t            fludblock;
  struct fludbot*   fluders;
#endif
#ifdef ANTI_SPAMBOT
  time_t            last_join_time;   /* when this client last 
                                         joined a channel */
  time_t            last_leave_time;  /* when this client last 
                                       * left a channel */
  unsigned char     join_leave_count; /* count of JOIN/LEAVE in less than 
                                         MIN_JOIN_LEAVE_TIME seconds */
  unsigned char     oper_warn_count_down; /* warn opers of this possible 
                                          spambot every time this gets to 0 */
#endif
#ifdef ANTI_DRONE_FLOOD
  time_t            first_received_message_time;
  unsigned char     received_number_of_privmsgs;
  unsigned char     drone_noticed;
#endif
  char  buffer[CLIENT_BUFSIZE]; /* Incoming message buffer */
#ifdef ZIP_LINKS
  struct Zdata*     zip;        /* zip data */
#endif
  short             lastsq;     /* # of 2k blocks when sendqueued called last*/
  struct DBuf       sendQ;      /* Outgoing message queue--if socket full */
  struct DBuf       recvQ;      /* Hold for data incoming yet to be parsed */
  /*
   * we want to use unsigned int here so the sizes have a better chance of
   * staying the same on 64 bit machines. The current trend is to use
   * I32LP64, (32 bit ints, 64 bit longs and pointers) and since ircd
   * will NEVER run on an operating system where ints are less than 32 bits, 
   * it's a relatively safe bet to use ints. Since right shift operations are
   * performed on these, it's not safe to allow them to become negative, 
   * which is possible for long running server connections. Unsigned values 
   * generally overflow gracefully. --Bleep
   */
  unsigned int      sendM;      /* Statistics: protocol messages send */
  unsigned int      sendK;      /* Statistics: total k-bytes send */
  unsigned int      receiveM;   /* Statistics: protocol messages received */
  unsigned int      receiveK;   /* Statistics: total k-bytes received */
  unsigned short    sendB;      /* counters to count upto 1-k lots of bytes */
  unsigned short    receiveB;   /* sent and received. */
  unsigned int      lastrecvM;  /* to check for activity --Mika */
  int               priority;
  struct Listener*  listener;   /* listener accepted from */
  struct SLink*     confs;      /* Configuration record associated */
  struct in_addr    ip;         /* keep real ip# too */
  unsigned short    port;       /* and the remote port# too :-) */
#ifndef USE_ADNS
  struct DNSReply*  dns_reply;  /* result returned from resolver query */  
#else
  struct DNSQuery*  dns_query;  /* result returned from resolver query */  
#endif
#ifdef ANTI_NICK_FLOOD
  time_t            last_nick_change;
  unsigned char     number_of_nick_changes;
  int               services_nick_change;
#endif
  time_t            last_services_use;
  unsigned char     number_of_services_use;
  time_t            last_knock; /* don't allow knock to flood */
  /*
   * client->sockhost contains the ip address gotten from the socket as a
   * string, this field should be considered read-only once the connection
   * has been made. (set in s_bsd.c only)
   */
  char              sockhost[HOSTIPLEN + 1]; /* This is the host name from the 
                                              socket ip address as string */
  /*
   * XXX - there is no reason to save this, it should be checked when it's
   * received and not stored, this is not used after registration
   */
  char              passwd[PASSWDLEN + 1];
  struct SLink*     watch; 		/* user's watch list */
  unsigned char     watches;            /* how many watches this user has set */     
  struct            ListOptions *lopt;  /* Saved /list options */
  int               caps;               /* capabilities bit-field */
  /* SSL support */
#ifdef HAVE_SSL
  int    use_ssl;
  int	 ssl_hshake_done;
  struct SSL*	  ssl;   /* SSL instance */
  struct X509*    client_cert;  /* SSL client's certificate */
#endif  
};

/*
 * status macros.
 */
#define STAT_CONNECTING 0x01   /* -4 */
#define STAT_HANDSHAKE  0x02   /* -3 */
#define STAT_ME         0x04   /* -2 */
#define STAT_UNKNOWN    0x08   /* -1 */
#define STAT_SERVER     0x10   /* 0  */
#define STAT_CLIENT     0x20   /* 1  */


#define IsRegisteredUser(x)     ((x)->status == STAT_CLIENT)
#define IsRegistered(x)         ((x)->status  > STAT_UNKNOWN)
#define IsConnecting(x)         ((x)->status == STAT_CONNECTING)
#define IsHandshake(x)          ((x)->status == STAT_HANDSHAKE)
#define IsMe(x)                 ((x)->status == STAT_ME)
#define IsUnknown(x)            ((x)->status == STAT_UNKNOWN)
#define IsServer(x)             ((x)->status == STAT_SERVER)
#define IsClient(x)             ((x)->status == STAT_CLIENT)

#define SetConnecting(x)        ((x)->status = STAT_CONNECTING)
#define SetHandshake(x)         ((x)->status = STAT_HANDSHAKE)
#define SetMe(x)                ((x)->status = STAT_ME)
#define SetUnknown(x)           ((x)->status = STAT_UNKNOWN)
#define SetServer(x)            ((x)->status = STAT_SERVER)
#define SetClient(x)            ((x)->status = STAT_CLIENT)

#define STAT_CLIENT_PARSE (STAT_UNKNOWN | STAT_CLIENT)
#define STAT_SERVER_PARSE (STAT_CONNECTING | STAT_HANDSHAKE | STAT_SERVER)

#define PARSE_AS_CLIENT(x)      ((x)->status & STAT_CLIENT_PARSE)
#define PARSE_AS_SERVER(x)      ((x)->status & STAT_SERVER_PARSE)

/*
 * ts stuff
 */
#define TS_CURRENT      6       /* current TS protocol version */
#define TS_MIN          3       /* minimum supported TS protocol version */
#define TS_DOESTS       0x20000000
#define DoesTS(x)       ((x)->tsinfo == TS_DOESTS)


/* housekeeping flags */

#define FLAGS_PINGSENT     0x0001 /* Unreplied ping sent */
#define FLAGS_DEADSOCKET   0x0002 /* Local socket is dead--Exiting soon */
#define FLAGS_KILLED       0x0004 /* Prevents "QUIT" from being sent for this*/
#define FLAGS_BLOCKED      0x0008 /* socket is in a blocked condition */
#define FLAGS_REJECT_HOLD  0x0010 /* client has been klined */
#define FLAGS_CLOSING      0x0020 /* set when closing to suppress errors */
#define FLAGS_CHKACCESS    0x0040 /* ok to check clients access if set */
#define FLAGS_GOTID        0x0080 /* successful ident lookup achieved */
#define FLAGS_NEEDID       0x0100 /* I-lines say must use ident return */
#define FLAGS_NONL         0x0200 /* No \n in buffer */
#define FLAGS_NORMALEX     0x0400 /* Client exited normally */
#define FLAGS_SENDQEX      0x0800 /* Sendq exceeded */
#define FLAGS_IPHASH       0x1000 /* iphashed this client */
#define FLAGS_SERVICE	   0x2000 /* Is Service server/client ? */
#define FLAGS_SSL	       0x4000 /* SSL handshake done ? */

/* umodes, settable flags */
#define FLAGS_WALLOP       	0x0001 /* send wallops to them */
#define FLAGS_INVISIBLE    	0x0002 /* makes user invisible */
#define UMODE_ZOMBIE       	0x0004 /* zombie, settable by command */

/* settable by services */
#define UMODE_IDENTIFIED   	0x0008 /* registered and identified nick */
#define FLAGS_SADMIN		0x0010 /* Services admin */

/* oper only flags */
#define FLAGS_SERVNOTICE   	0x0020 /* server notices such as kill */
#define FLAGS_CCONN        	0x0040 /* Client Connections */
#define FLAGS_REJ          	0x0080 /* Bot Rejections */
#define FLAGS_SKILL        	0x0100 /* Server Killed */
#define FLAGS_FULL         	0x0200 /* Full messages */
#define FLAGS_SPY          	0x0400 /* see STATS / LINKS */
#define FLAGS_DEBUG        	0x0800 /* 'debugging' info */
#define FLAGS_BOTS         	0x1000 /* shows bots */
#define FLAGS_EXTERNAL     	0x2000 /* show servers introduced */

/* user information flags, only settable by remote mode or local oper */
#define FLAGS_OPER         	0x4000 /* Operator */
#define FLAGS_LOCOP        	0x8000 /* Local operator -- SRB */

#define FLAGS_ADMIN			0x00020000 /* Server Admin */
#define FLAGS_TECHADMIN		0x00040000 /* Technical Admin */
#define FLAGS_NETADMIN		0x00080000 /* Network Admin */
#define FLAGS_HELPER		0x00100000 /* Network Admin */
#define UMODE_BOT		0x00200000 /* bot client */
#define UMODE_NODCC		0x00400000 /* dcc blocked */
#define UMODE_PRIVATE		0x00800000 /* hide channels from whois */
#define UMODE_REGMSG		0x01000000 /* receive privmsg only from +r nicks */
#define UMODE_STEALTH		0x02000000 /* stealth mode */
/* end of umodes */

/* brasillink only --hardman */
#define UMODE_VCOP              0x04000000 /* virtual cop */
#define UMODE_VADMIN            0x08000000 /* virtual cop */
#define UMODE_GRINGO            0x10000000 /* gringo */
#define FLAGS_VIPUSER           0x20000000 /* vip user */
#define UMODE_LINKER            0x40000000 /* is a linker */
#define UMODE_ROOT              0x80000000 /* Services root */


/* *sigh* overflow flags */
#define FLAGS2_RESTRICTED   	0x0001      /* restricted client */
#define FLAGS2_PING_TIMEOUT 	0x0002
#define FLAGS2_E_LINED      	0x0004      /* client is graced with E line */
#define FLAGS2_F_LINED      	0x0008      /* client is graced with F line */
#define FLAGS2_EXEMPTGLINE  	0x0010      /* client can't be G-lined */

/* oper priv flags */
#define FLAGS2_OPER_GLOBAL_KILL 0x0020  /* oper can global kill */
#define FLAGS2_OPER_REMOTE      0x0040  /* oper can do squits/connects */
#define FLAGS2_OPER_UNKLINE     0x0080  /* oper can use unkline */
#define FLAGS2_OPER_GLINE       0x0100  /* oper can use gline */
/* #define FLAGS2_OPER_N           0x0200 */ /* oper can umode n */
#define FLAGS2_OPER_K           0x0400  /* oper can kill/kline */
#define FLAGS2_OPER_DIE         0x0800  /* oper can die */
#define FLAGS2_OPER_REHASH      0x1000  /* oper can rehash */
#define FLAGS2_OPER_FLAGS       (FLAGS2_OPER_GLOBAL_KILL | \
                                 FLAGS2_OPER_REMOTE | \
                                 FLAGS2_OPER_UNKLINE | \
                                 FLAGS2_OPER_GLINE | \
                                 FLAGS2_OPER_K | \
                                 FLAGS2_OPER_DIE | \
                                 FLAGS2_OPER_REHASH)
/* ZIP_LINKS */

#define FLAGS2_ZIP           	0x00004000  /* (server) link is zipped */
#define FLAGS2_ZIPFIRST      	0x00008000  /* start of zip (ignore any CR/LF) */
#define FLAGS2_CBURST       	0x000010000  /* connection burst being sent */

#define FLAGS2_DOINGLIST    	0x20000  /* client is doing a list */
#ifdef IDLE_CHECK
#define FLAGS2_IDLE_LINED   	0x40000
#endif
#define FLAGS2_ALREADY_EXITED   0x80000   	/* kludge grrrr */
#define FLAGS2_SENDQ_POP  		0x100000  	/* sendq exceeded (during list) */
#define FLAGS2_WEBCHAT          0x200000  	/* webchat user */

#define USER_UMODES      (FLAGS_INVISIBLE | FLAGS_HELPER | \
					  UMODE_BOT | UMODE_IDENTIFIED | \
                                          UMODE_VCOP | UMODE_VADMIN | UMODE_GRINGO | \
					  UMODE_PRIVATE | UMODE_REGMSG | \
                                          UMODE_STEALTH | FLAGS_SPY | FLAGS_VIPUSER | UMODE_ROOT | UMODE_LINKER)
#define ALL_UMODES   (USER_UMODES | FLAGS_SERVNOTICE | FLAGS_CCONN | \
                      FLAGS_REJ | FLAGS_SKILL | FLAGS_FULL | \
                      FLAGS_DEBUG | FLAGS_EXTERNAL |  FLAGS_BOTS | \
                                          OPER_UMODES | FLAGS_SADMIN | \
                                          UMODE_ZOMBIE | FLAGS_HELPER | \
                                          FLAGS_ADMIN | FLAGS_TECHADMIN | FLAGS_NETADMIN )

#ifndef OPER_UMODES
#define OPER_UMODES  (FLAGS_OPER | FLAGS_WALLOP | FLAGS_SERVNOTICE | \
                      FLAGS_DEBUG)
#endif /* OPER_UMODES */

#ifndef LOCOP_UMODES
#define LOCOP_UMODES (FLAGS_LOCOP | FLAGS_WALLOP | FLAGS_SERVNOTICE | \
                      FLAGS_SPY | FLAGS_DEBUG)
#endif /* LOCOP_UMODES */

#define FLAGS_ID     (FLAGS_NEEDID | FLAGS_GOTID)

/*
 * flags macros.
 */
#define IsPerson(x)             (IsClient(x) && (x)->user)
#define DoAccess(x)             ((x)->flags & FLAGS_CHKACCESS)
#define IsLocal(x)              ((x)->flags & FLAGS_LOCAL)
#define IsDead(x)               ((x)->flags & FLAGS_DEADSOCKET)
#define SetAccess(x)            ((x)->flags |= FLAGS_CHKACCESS)
#define NoNewLine(x)            ((x)->flags & FLAGS_NONL)
#define ClearAccess(x)          ((x)->flags &= ~FLAGS_CHKACCESS)
#define MyConnect(x)            ((x)->local_flag != 0)
#define MyClient(x)             (MyConnect(x) && IsClient(x))

/* oper flags */
#define MyOper(x)               (MyConnect(x) && IsOper(x))
#define IsOper(x)               ((x)->umodes & FLAGS_OPER)
#define IsStaff(x)		((x)->umodes & (FLAGS_OPER|FLAGS_LOCOP|UMODE_ROOT|UMODE_LINKER|FLAGS_SADMIN|UMODE_VADMIN|UMODE_VCOP))
#define IsLocOp(x)              ((x)->umodes & FLAGS_LOCOP)
#define IsAnOper(x)             ((x)->umodes & (FLAGS_OPER|FLAGS_LOCOP))
#define IsHelper(x)				((x)->umodes & FLAGS_HELPER)
#define IsSAdmin(x)				((x)->umodes & FLAGS_SADMIN)
#define IsAdmin(x)				((x)->umodes & FLAGS_ADMIN)
#define IsNetAdmin(x)			((x)->umodes & FLAGS_NETADMIN)
#define IsTechAdmin(x)			((x)->umodes & FLAGS_TECHADMIN)
#define IsVcop(x)                     ((x)->umodes &UMODE_VCOP)
#define IsVadmin(x)                   ((x)->umodes & UMODE_VADMIN)
#define SetOper(x)              ((x)->umodes |= FLAGS_OPER)
#define SetLocOp(x)             ((x)->umodes |= FLAGS_LOCOP)
#define SetHelper(x)			((x)->umodes |= FLAGS_HELPER)
#define SetSAdmin(x)			((x)->umodes |= FLAGS_SADMIN)
#define SetAdmin(x)				((x)->umodes |= FLAGS_ADMIN)
#define SetNetAdmin(x)			((x)->umodes |= FLAGS_NETADMIN)
#define SetTechAdmin(x)			((x)->umodes |= FLAGS_TECHADMIN)
#define ClearOper(x)            ((x)->umodes &= ~FLAGS_OPER)
#define ClearLocOp(x)           ((x)->umodes &= ~FLAGS_LOCOP)
#define ClearHelper(x)			((x)->umodes &= ~FLAGS_HELPER)
#define ClearSAdmin(x)			((x)->umodes &= ~FLAGS_SADMIN)
#define ClearAdmin(x)			((x)->umodes &= ~FLAGS_ADMIN)
#define ClearNetAdmin(x)		((x)->umodes &= ~FLAGS_NETADMIN)
#define ClearTechAdmin(x)		((x)->umodes &= ~FLAGS_TECHADMIN)

#define IsPrivileged(x)         (IsAnOper(x) || IsServer(x))

/* umode flags */
#define IsPrivate(x)          	((x)->umodes & UMODE_PRIVATE)

#define IsStealth(x)		((x)->umodes & UMODE_STEALTH)
#define SetStealth(x)		((x)->umodes |= UMODE_STEALTH)
#define ClearStealth(x)		((x)->umodes &= ~UMODE_STEALTH)

#define IsBot(x)          		((x)->umodes & UMODE_BOT)
#define SetBot(x)			((x)->umodes |= UMODE_BOT)
#define ClearBot(x)			((x)->umodes &= ~UMODE_BOT)

#define IsInvisible(x)          ((x)->umodes & FLAGS_INVISIBLE)
#define SetInvisible(x)         ((x)->umodes |= FLAGS_INVISIBLE)
#define ClearInvisible(x)       ((x)->umodes &= ~FLAGS_INVISIBLE)

#define IsIdentified(x)			((x)->umodes & UMODE_IDENTIFIED)
#define SetIdentified(x)        ((x)->umodes |= UMODE_IDENTIFIED)
#define ClearIdentified(x)      ((x)->umodes &= ~UMODE_IDENTIFIED)

#define IsRegMsg(x)				((x)->umodes & UMODE_REGMSG)
#define SetRegMsg(x)        	((x)->umodes |= UMODE_REGMSG)
#define ClearRegMsg(x)      	((x)->umodes &= ~UMODE_REGMSG)

#define IsZombie(x)		((x)->umodes & UMODE_ZOMBIE)
#define SetZombie(x)        	((x)->umodes |= UMODE_ZOMBIE)
#define ClearZombie(x)      	((x)->umodes &= ~UMODE_ZOMBIE)

#define IsVAny(x)             (((x)->umodes & UMODE_VCOP) || ((x)->umodes & UMODE_VADMIN))

#define IsVCop(x)             ((x)->umodes & UMODE_VCOP)
#define SetVCop(x)            ((x)->umodes |= UMODE_VCOP)
#define ClearVCop(x)          ((x)->umodes &= ~UMODE_VCOP)

#define IsVAdmin(x)             ((x)->umodes & UMODE_VADMIN)
#define SetVAdmin(x)            ((x)->umodes |= UMODE_VADMIN)
#define ClearVAdmin(x)          ((x)->umodes &= ~UMODE_VADMIN)

//by GMitre
#define IsRoot(x)		((x)->umodes & UMODE_ROOT)
#define SetRoot(x)        	((x)->umodes |= UMODE_ROOT)
#define ClearRoot(x)      	((x)->umodes &= ~UMODE_ROOT)

#define IsLinker(x)		((x)->umodes & UMODE_LINKER)
#define SetLinker(x)        	((x)->umodes |= UMODE_LINKER)
#define ClearLinker(x)      	((x)->umodes &= ~UMODE_LINKER)

#define IsVipUser(x)            ((x)->umodes & FLAGS_VIPUSER)
#define SetVipUser(x)		((x)->umodes |= FLAGS_VIPUSER)
#define ClearVipUser(x)		((x)->umodes &= ~FLAGS_VIPUSER)

//end

#define IsGringo(x)             ((x)->umodes & UMODE_GRINGO)
#define SetGringo(x)            ((x)->umodes |= UMODE_GRINGO)
#define ClearGringo(x)          ((x)->umodes &= ~UMODE_GRINGO)

#define IsNoDCC(x)		((x)->umodes & UMODE_NODCC)
#define SetNoDCC(x)        	((x)->umodes |= UMODE_NODCC)
#define ClearNoDCC(x)      	((x)->umodes &= ~UMODE_NODCC)

#define SendWallops(x)          ((x)->umodes & FLAGS_WALLOP)
#define ClearWallops(x)         ((x)->umodes &= ~FLAGS_WALLOP)

#define SendServNotice(x)       (((x)->umodes & FLAGS_SERVNOTICE) && IsAnOper(x))
#define SendCConnNotice(x)      ((x)->umodes & FLAGS_CCONN)
#define SendRejNotice(x)        ((x)->umodes & FLAGS_REJ)
#define SendSkillNotice(x)      ((x)->umodes & FLAGS_SKILL)
#define SendFullNotice(x)       ((x)->umodes & FLAGS_FULL)
#define SendSpyNotice(x)        ((x)->umodes & FLAGS_SPY)
#define SendDebugNotice(x)      ((x)->umodes & FLAGS_DEBUG)
#define SetWallops(x)           ((x)->umodes |= FLAGS_WALLOP)

/* service flags */
#define SetService(x)           ((x)->flags |= FLAGS_SERVICE)
#define IsService(x)        	((x)->flags & FLAGS_SERVICE)
#define ClearService(x)        	((x)->flags &= ~FLAGS_SERVICE)

/* SSL */
#define SetSecure(x)            ((x)->flags |= FLAGS_SSL)
#define IsSecure(x)        	    ((x)->flags & FLAGS_SSL)


#ifdef REJECT_HOLD
#define IsRejectHeld(x)         ((x)->flags & FLAGS_REJECT_HOLD)
#define SetRejectHold(x)        ((x)->flags |= FLAGS_REJECT_HOLD)
#endif

#define SetIpHash               ((x)->flags |= FLAGS_IPHASH)
#define ClearIpHash             ((x)->flags &= ~FLAGS_IPHASH)
#define IsIpHash                ((x)->flags & FLAGS_IPHASH)

#define SetNeedId(x)            ((x)->flags |= FLAGS_NEEDID)
#define IsNeedId(x)             (((x)->flags & FLAGS_NEEDID) != 0)

#define SetGotId(x)             ((x)->flags |= FLAGS_GOTID)
#define IsGotId(x)              (((x)->flags & FLAGS_GOTID) != 0)

/*
 * flags2 macros.
 */
#define IsRestricted(x)         ((x)->flags2 & FLAGS2_RESTRICTED)
#define SetRestricted(x)        ((x)->flags2 |= FLAGS2_RESTRICTED)
#define ClearDoingList(x)       ((x)->flags2 &= ~FLAGS2_DOINGLIST)
#define SetDoingList(x)         ((x)->flags2 |= FLAGS2_DOINGLIST)
#define IsDoingList(x)          ((x)->flags2 & FLAGS2_DOINGLIST)
#define ClearSendqPop(x)        ((x)->flags2 &= ~FLAGS2_SENDQ_POP)
#define SetSendqPop(x)          ((x)->flags2 |= FLAGS2_SENDQ_POP)
#define IsSendqPopped(x)        ((x)->flags2 & FLAGS2_SENDQ_POP)
#define SetWebchat(x)           ((x)->flags2 |= FLAGS2_WEBCHAT)
#define IsWebchat(x)            ((x)->flags2 & FLAGS2_WEBCHAT)
#define IsElined(x)             ((x)->flags2 & FLAGS2_E_LINED)
#define SetElined(x)            ((x)->flags2 |= FLAGS2_E_LINED)
#define IsFlined(x)             ((x)->flags2 & FLAGS2_F_LINED)
#define SetFlined(x)            ((x)->flags2 |= FLAGS2_F_LINED)
#define IsExemptGline(x)	  ((x)->flags2 & FLAGS2_EXEMPTGLINE)
#define SetExemptGline(x)	  ((x)->flags2 |= FLAGS2_EXEMPTGLINE)

#ifdef IDLE_CHECK
#define SetIdlelined(x)         ((x)->flags2 |= FLAGS2_IDLE_LINED)
#define IsIdlelined(x)          ((x)->flags2 & FLAGS2_IDLE_LINED)
#endif

#define SetOperGlobalKill(x)    ((x)->flags2 |= FLAGS2_OPER_GLOBAL_KILL)
#define IsOperGlobalKill(x)     ((x)->flags2 & FLAGS2_OPER_GLOBAL_KILL)
#define SetOperRemote(x)        ((x)->flags2 |= FLAGS2_OPER_REMOTE)
#define IsOperRemote(x)         ((x)->flags2 & FLAGS2_OPER_REMOTE)
#define SetOperUnkline(x)       ((x)->flags2 |= FLAGS2_OPER_UNKLINE)
#define IsSetOperUnkline(x)     ((x)->flags2 & FLAGS2_OPER_UNKLINE)
#define SetOperGline(x)         ((x)->flags2 |= FLAGS2_OPER_GLINE)
#define IsSetOperGline(x)       ((x)->flags2 & FLAGS2_OPER_GLINE)
#define SetOperK(x)             ((x)->flags2 |= FLAGS2_OPER_K)
#define IsSetOperK(x)           ((x)->flags2 & FLAGS2_OPER_K)
#define SetOperDie(x)           ((x)->flags2 |= FLAGS2_OPER_DIE)
#define IsOperDie(x)            ((x)->flags2 & FLAGS2_OPER_DIE)
#define SetOperRehash(x)        ((x)->flags2 |= FLAGS2_OPER_REHASH)
#define IsOperRehash(x)         ((x)->flags2 & FLAGS2_OPER_REHASH)
#define CBurst(x)               ((x)->flags2 & FLAGS2_CBURST)

/*
 * 'offsetof' is defined in ANSI-C. The following definition
 * is not absolutely portable (I have been told), but so far
 * it has worked on all machines I have needed it. The type
 * should be size_t but...  --msa
 */
#ifndef offsetof
#define offsetof(t, m) (size_t)((&((t *)0L)->m))
#endif

#define CLIENT_LOCAL_SIZE sizeof(struct Client)
#define CLIENT_REMOTE_SIZE offsetof(struct Client, count)

/*
 * definitions for get_client_name
 */
#define HIDE_IP 0
#define SHOW_IP 1
#define MASK_IP 2
#define REAL_IP 3

extern time_t         check_pings(time_t current);
extern const char*    get_client_name(struct Client* client, int show_ip);
extern const char*    get_client_host(struct Client* client);
extern void           release_client_dns_reply(struct Client* client);
extern void           init_client_heap(void);
extern void           clean_client_heap(void);
extern struct Client* make_client(struct Client* from);
extern void 	      free_client(struct Client* cptr);
extern void           add_client_to_list(struct Client* client);
extern void           remove_client_from_list(struct Client *);
extern void           add_client_to_llist(struct Client** list, 
                                          struct Client* client);
extern void           del_client_from_llist(struct Client** list, 
                                            struct Client* client);
extern int            exit_client(struct Client*, struct Client*, 
                                  struct Client*, const char* comment);

extern void     count_local_client_memory(int *, int *);
extern void     count_remote_client_memory(int *, int *);
extern  int     check_registered (struct Client *);
extern  int     check_registered_user (struct Client *);

extern struct Client* find_chasing (struct Client *, char *, int *);
extern struct Client* find_client(const char* name, struct Client* client);
extern struct Client* find_server_by_name(const char* name);
extern struct Client* find_person (char *, struct Client *);
extern struct Client* find_server(const char* name);
extern struct Client* find_userhost (char *, char *, struct Client *, int *);
extern struct Client* next_client(struct Client* next, const char* name);
extern struct Client* next_client_double(struct Client* next, 
                                         const char* name);

/* 
 * Time we allow clients to spend in unknown state, before tossing.
 */
#define UNKNOWN_TIME 60
#endif /* INCLUDED_client_h */
