/*
 * IMC2 AntiFreeze Client - Developed by Mud Domain.
 * This code is certified as 100% LGPL compatible.
 * All aspects have been verified against the core components
 * contained in Oliver's relicensed code. No components licensed
 * under the GPL remain.
 *
 * All additions Copyright (C)2002-2004 Roger Libiez ( Samson )
 * Contributions by Xorith, Copyright (C)2004
 * Contributions by Orion Elder, Copyright (C)2003
 * Comments and suggestions welcome: imc@imc2.org
 * Registered with the United States Copyright Office: TX 5-962-561
 *
 * We would like to thank the following people for their hard work on
 * versions 1.00 Gold through 3.00 Mud-Net even though 
 * their contributions no longer remain:
 *
 * Scion Altera, Shogar, Kratas, Tagith, Noplex,
 * Senir, Trax and Ntanel StormBlade.
 *
 * This work is derived from:
 * IMC2 version 0.10 - an inter-mud communications protocol
 * Copyright (C) 1996 & 1997 Oliver Jowett <oliver@randomly.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#define IMC FALSE

#ifndef __IMC2_H__
#define __IMC2_H__

/* Number of entries to keep in the channel histories */
#define MAX_IMCHISTORY 20
#define MAX_IMCTELLHISTORY 20

/* This is the protocol version */
#define IMC_VERSION 2
#define IMC_VERSION_ID "IMC2 AntiFreeze CL-4 "

/* Remcon: Ask and ye shall receive. */
#define IMC_DIR          "../imc/"

#define IMC_CHANNEL_FILE IMC_DIR "imc.channels"
#define IMC_CONFIG_FILE  IMC_DIR "imc.config"
#define IMC_BAN_FILE     IMC_DIR "imc.ignores"
#define IMC_UCACHE_FILE  IMC_DIR "imc.ucache"
#define IMC_COLOR_FILE   IMC_DIR "imc.color"
#define IMC_HELP_FILE    IMC_DIR "imc.help"
#define IMC_CMD_FILE     IMC_DIR "imc.commands"

/* Make sure you set the macros in the imccfg.h file properly or things get ugly from here. */
#include "imccfg.h"

typedef enum
{
   IMCPERM_NOTSET, IMCPERM_NONE, IMCPERM_MORT, IMCPERM_IMM, IMCPERM_ADMIN, IMCPERM_IMP
} imc_permissions;

/* Flag macros */
#define IMCIS_SET(flag, bit)	((flag) & (bit))
#define IMCSET_BIT(var, bit)	((var) |= (bit))
#define IMCREMOVE_BIT(var, bit)((var) &= ~(bit))

/* Channel flags, only one so far, but you never know when more might be useful */
#define IMCCHAN_LOG      (1 <<  0)

/* Player flags */
#define IMC_TELL         (1 <<  0)
#define IMC_DENYTELL     (1 <<  1)
#define IMC_BEEP         (1 <<  2)
#define IMC_DENYBEEP     (1 <<  3)
#define IMC_INVIS        (1 <<  4)
#define IMC_PRIVACY      (1 <<  5)
#define IMC_DENYFINGER   (1 <<  6)
#define IMC_AFK          (1 <<  7)
#define IMC_COLORFLAG    (1 <<  8)
#define IMC_PERMOVERRIDE (1 <<  9)
#define IMC_NOTIFY       (1 << 10)

#define IMCPERM(ch)           (CH_IMCDATA((ch))->imcperm)
#define IMCFLAG(ch)           (CH_IMCDATA((ch))->imcflag)
#define FIRST_IMCIGNORE(ch)   (CH_IMCDATA((ch))->imcfirst_ignore)
#define LAST_IMCIGNORE(ch)    (CH_IMCDATA((ch))->imclast_ignore)
#define IMC_LISTEN(ch)        (CH_IMCDATA((ch))->imc_listen)
#define IMC_DENY(ch)          (CH_IMCDATA((ch))->imc_denied)
#define IMC_RREPLY(ch)        (CH_IMCDATA((ch))->rreply)
#define IMC_RREPLY_NAME(ch)   (CH_IMCDATA((ch))->rreply_name)
#define IMC_EMAIL(ch)         (CH_IMCDATA((ch))->email)
#define IMC_HOMEPAGE(ch)      (CH_IMCDATA((ch))->homepage)
#define IMC_AIM(ch)           (CH_IMCDATA((ch))->aim)
#define IMC_ICQ(ch)           (CH_IMCDATA((ch))->icq)
#define IMC_YAHOO(ch)         (CH_IMCDATA((ch))->yahoo)
#define IMC_MSN(ch)           (CH_IMCDATA((ch))->msn)
#define IMC_COMMENT(ch)       (CH_IMCDATA((ch))->comment)
#define IMCTELLHISTORY(ch,x)  (CH_IMCDATA((ch))->imc_tellhistory[(x)])
#define IMCISINVIS(ch)        ( IMCIS_SET( IMCFLAG((ch)), IMC_INVIS ) || hidden(ch) )
#define IMCAFK(ch)            ( IMCIS_SET( IMCFLAG((ch)), IMC_AFK ) || IS_SET(ch->pcdata->pflags,PFLAG_AFK) )

/* Should not need to edit anything below this point */

#define LGST 4096 /* Large String */
#define SMST 1024 /* Small String */

/* Macro taken from DOTD codebase. Fcloses a file, then nulls its pointer for safety. */
#define IMCFCLOSE(fp)  fclose((fp)); (fp)=NULL;

/*
 * Memory allocation macros.
 */
#define IMCCREATE(result, type, number)                           \
do                                                                \
{                                                                 \
    if (!((result) = (type *) calloc ((number), sizeof(type))))   \
    {                                                             \
	imclog( "Malloc failure @ %s:%d\n", __FILE__, __LINE__ );   \
	abort();                                                    \
    }                                                             \
} while(0)

#define IMCDISPOSE(point)     \
do                            \
{                             \
   if((point))                \
   {                          \
      free((point));          \
      (point) = NULL;         \
   }                          \
} while(0)

#define IMCSTRALLOC strdup
#define IMCSTRFREE IMCDISPOSE

/* double-linked list handling macros -Thoric ( From the Smaug codebase ) */
/* Updated by Scion 8/6/1999 */
#define IMCLINK(link, first, last, next, prev)  \
do                                              \
{                                               \
   if ( !(first) )                              \
   {                                            \
      (first) = (link);                         \
      (last) = (link);                          \
   }                                            \
   else                                         \
      (last)->next = (link);                    \
   (link)->next = NULL;                         \
   if ((first) == (link))                       \
      (link)->prev = NULL;                      \
   else                                         \
      (link)->prev = (last);                    \
   (last) = (link);                             \
} while(0)

#define IMCINSERT(link, insert, first, next, prev)    \
do                                                    \
{                                                     \
   (link)->prev = (insert)->prev;                     \
   if ( !(insert)->prev )                             \
      (first) = (link);                               \
   else                                               \
      (insert)->prev->next = (link);                  \
   (insert)->prev = (link);                           \
   (link)->next = (insert);                           \
} while(0)

#define IMCUNLINK(link, first, last, next, prev) \
do                                               \
{                                                \
   if ( !(link)->prev )                          \
   {                                             \
      (first) = (link)->next;                    \
	if((first))                                \
	   (first)->prev = NULL;                   \
   }                                             \
   else                                          \
   {                                             \
      (link)->prev->next = (link)->next;         \
   }                                             \
   if( !(link)->next )                           \
   {                                             \
      (last) = (link)->prev;                     \
	if((last))                                 \
	   (last)->next = NULL;                    \
   }                                             \
   else                                          \
   {                                             \
      (link)->next->prev = (link)->prev;         \
   }                                             \
} while(0)

/* activation states */
#define IA_NONE        0
#define IA_CONFIG1     1
#define IA_CONFIG2     2
#define IA_UP          3

/* connection states */
#define IMC_CLOSED     0 /* No active connection */
#define IMC_CONNECTING 1 /* Contacting router */
#define IMC_WAIT1      2 /* Waiting for router verification */
#define IMC_CONNECTED  3 /* Fully connected */

/* Less tweakable parameters - only change these if you know what they do */

/* number of packets to remember at a time */
#define IMC_MEMORY 256

/* start dropping really old packets based on this figure */
#define IMC_PACKET_LIFETIME 60

/* min input/output buffer size */
#define IMC_MINBUF        256

/* max input/output buffer size */
#define IMC_MAXBUF        16384

/* Changing these impacts the protocol itself - other muds may drop your
 * packets if you get this wrong
 */
/* max length of any packet */
#define IMC_PACKET_LENGTH 16300

/* max length of any mud name */
#define IMC_MNAME_LENGTH  20

/* max length of any player name */
#define IMC_PNAME_LENGTH  40

/* max length of any player@mud name */
#define IMC_NAME_LENGTH   (IMC_MNAME_LENGTH+IMC_PNAME_LENGTH+1)

/* max length of a path */
#define IMC_PATH_LENGTH   200

/* max length of a packet type */
#define IMC_TYPE_LENGTH   20

/* max length of a password */
#define IMC_PW_LENGTH     20

/* max length of a data type (estimate) */
#define IMC_DATA_LENGTH   (IMC_PACKET_LENGTH-2*IMC_NAME_LENGTH-IMC_PATH_LENGTH-IMC_TYPE_LENGTH-20)

/* max number of data keys in a packet */
#define IMC_MAX_KEYS      20

/* No real functional difference in alot of this, but double linked lists DO seem to handle better,
 * and they look alot neater too. Yes, readability IS important! - Samson
 */
typedef struct imc_channel IMC_CHANNEL;        /* Channels, both local and non-local */
typedef struct imc_siteinfo SITEINFO;          /* The given mud :) */
typedef struct imc_packet PACKET;              /* It's a packet! */
typedef struct imc_remoteinfo REMOTEINFO;      /* Information on a mud connected to IMC */
typedef struct imc_ban_data IMC_BAN;           /* Mud level bans */
typedef struct imcchar_data IMC_CHARDATA;      /* Player flags */
typedef struct imc_ignore IMC_IGNORE;	     /* Player level ignores */
typedef struct imcucache_data IMCUCACHE_DATA;  /* User cache data for gender targetting socials */
typedef struct imc_color_table IMC_COLOR;      /* The Color config */
typedef struct imc_command_table IMC_CMD_DATA; /* Command table */
typedef struct imc_help_table IMC_HELP_DATA;   /* Help table */
typedef struct imc_cmd_alias IMC_ALIAS;        /* Big, bad, bloated command alias thing */
typedef struct imc_packet_handler IMC_PHANDLER; /* custom packet handlers added dynamically */

typedef void IMC_FUN( CHAR_DATA *ch, char *argument );
#define IMC_CMD( name ) void (name)( CHAR_DATA *ch, char *argument )

extern REMOTEINFO *first_rinfo;
extern REMOTEINFO *last_rinfo;
extern SITEINFO *this_imcmud;

/* Oh yeah, baby, that rauncy looking Merc structure just got the facelift of the century.
 * Thanks to Thoric and friends for the slick idea.
 */
struct imc_cmd_alias
{
   IMC_ALIAS *next;
   IMC_ALIAS *prev;
   char *name;
};

struct imc_command_table
{
   IMC_CMD_DATA *next;
   IMC_CMD_DATA *prev;
   IMC_ALIAS *first_alias;
   IMC_ALIAS *last_alias;
   IMC_FUN *function;
   char *name;
   int level;
   bool connected;
};

struct imc_help_table
{
   IMC_HELP_DATA *next;
   IMC_HELP_DATA *prev;
   char *name;
   char *text;
   int level;
};

struct imc_color_table
{
   IMC_COLOR *next;
   IMC_COLOR *prev;
   char *name;      /* the name of the color */
   char *mudtag;    /* What the mud uses for the raw tag */
   char *imctag;    /* The imc tilde code that represents the mudtag to the network */
};

struct imc_ignore
{
   IMC_IGNORE *next;
   IMC_IGNORE *prev;
   char *name;
};

struct imcucache_data
{
   IMCUCACHE_DATA *next;
   IMCUCACHE_DATA *prev;
   char *name;
   int gender;
   time_t time;
};

struct imcchar_data
{
   IMC_IGNORE	*imcfirst_ignore; /* List of ignored people */
   IMC_IGNORE	*imclast_ignore;
   char *rreply;      /* IMC reply-to */
   char *rreply_name; /* IMC reply-to shown to char */
   char *imc_listen;  /* Channels the player is listening to */
   char *imc_denied;  /* Channels the player has been denied use of */
   char *imc_tellhistory[MAX_IMCTELLHISTORY]; /* History of received imctells - Samson 1-21-04 */
   char *email;       /* Person's email address - for imcfinger - Samson 3-21-04 */
   char *homepage;    /* Person's homepage - Samson 3-21-04 */
   char *aim;         /* Person's AOL Instant Messenger screenname - Samson 3-21-04 */
   char *yahoo;       /* Person's Y! screenname - Samson 3-21-04 */
   char *msn;         /* Person's MSN Messenger screenname - Samson 3-21-04 */
   char *comment;     /* Person's personal comment - Samson 3-21-04 */
   int icq;           /* Person's ICQ UIN Number - Samson 3-21-04 */
   int imcperm;       /* Permission level for the player */
   int imcflag;       /* Flags set on the player */
};

/* a player on IMC */
typedef struct
{
   char name[IMC_NAME_LENGTH];	/* name of character */
   int level;                  /* permission level */
} imc_char_data;

struct imc_channel
{
   IMC_CHANNEL *next;
   IMC_CHANNEL *prev;
   char *name;         /* name of channel */
   char *owner;        /* owner (singular) of channel */
   char *operators;    /* current operators of channel */
   char *invited;
   char *excluded;
   char *local_name;   /* Operational localname */
   char *dlname;       /* Default localname - sent by router */
   char *regformat;
   char *emoteformat;
   char *socformat;
   char *history[MAX_IMCHISTORY];
   bool open;
   bool refreshed;
   short level;
   long flags;
};

/* an IMC packet, as seen by the high-level code */
struct imc_packet
{
   char to[IMC_NAME_LENGTH];	/* destination of packet */
   char from[IMC_NAME_LENGTH];	/* source of packet      */
   char type[IMC_TYPE_LENGTH];	/* type of packet        */
   char *key[IMC_MAX_KEYS];
   char *value[IMC_MAX_KEYS];

  /* internal things which only the low-level code needs to know about */
   struct
   {
      char to[IMC_NAME_LENGTH];
      char from[IMC_NAME_LENGTH];
      char path[IMC_PATH_LENGTH];
      unsigned long sequence;
  } i;
};

/* The mud's connection data for the router */
/* Merged the old siteinfo struct here as well */
struct imc_siteinfo
{
   char *routername;    /* name of router */
   char *rhost;         /* DNS/IP of router */
   char *network;       /* Network name of the router, set at keepalive - Samson */
   char *serverpw;      /* server password */
   char *clientpw;      /* client password */
   char *localname;     /* One word localname */
   char *fullname;      /* FULL name of mud */
   char *ihost;         /* host AND port of mud */
   char *email;         /* contact address (email) */
   char *www;           /* homepage */
   char *base;          /* The mud's codebase name */
   char *details;       /* BRIEF description of mud */
   unsigned short rport; /* remote port of router */
   bool md5;            /* Client will support MD5 authentication */
   bool md5pass;        /* Client is using MD5 authentication */
   bool autoconnect;    /* Do we autoconnect on bootup or not? - Samson */
   int iport;           /* The port the mud itself is on */
   int minlevel;        /* Minimum player level */
   int immlevel;        /* Immortal level */
   int adminlevel;      /* Admin level */
   int implevel;        /* Implementor level */

   /* Conection parameters - These don't save in the config file */
   int desc;                /* descriptor */
   unsigned short state;    /* IMC_xxxx state */
   unsigned short version;  /* version of remote site */
   short newoutput;         /* try to write at end of cycle regardless of fd_set state? */
   char *inbuf;		    /* input buffer */
   int insize;
   char *outbuf;		    /* output buffer */
   int outsize;
   bool disconnect;     /* Will we disconnect at the next imc_loop call? */
};

/* IMC statistics */
typedef struct
{
  long rx_pkts;		        /* Received packets                      */
  long tx_pkts;		        /* Transmitted packets                   */
  long rx_bytes;		/* Received bytes                        */
  long tx_bytes;		/* Transmitted bytes                     */

  int max_pkt;                  /* Max. size packet processed            */
  int sequence_drops;           /* Dropped packets due to age            */
} imc_statistics;

/* info about another mud on IMC */
struct imc_remoteinfo
{
   REMOTEINFO *next;
   REMOTEINFO *prev;
   char *name;
   char *version;
   char *network;
   char *path;
   char *url;
   bool expired;
   unsigned long top_sequence;
};

/* A mudwide ban */
struct imc_ban_data
{
   IMC_BAN *next;
   IMC_BAN *prev;
   char *name;
};

/* for the versioning table */
typedef struct
{
   int version;
   char *(*generate) (PACKET *);
   PACKET *(*interpret) (char *);
} _imc_vinfo;

/* an entry in the memory table */
typedef struct
{
   char *from;
   unsigned long sequence;
} _imc_memory;

struct imc_packet_handler
{
   IMC_PHANDLER *next;
   IMC_PHANDLER *prev;
   char *name;
   void (*func)( imc_char_data *from, PACKET *p );
};

extern _imc_vinfo imc_vinfo[]; /* Version table */
extern char *IMC_VERSIONID;

/* External functions hooked to the mud */
bool imc_command_hook( CHAR_DATA *ch, char *command, char *argument );
void imc_startup( bool forced );
void imc_shutdown( bool reconnect );
void imc_initchar( CHAR_DATA *ch );
bool imc_loadchar( CHAR_DATA *ch, FILE *fp, const char *word );
void imc_savechar( CHAR_DATA *ch, FILE *fp );
void imc_freechardata( CHAR_DATA *ch );
void imc_loop( void );
void imc_register_packet_handler( char *name, void (*func)( imc_char_data *from, PACKET *p ) );
#ifdef _DISKIO_H_
void imc_load_pfile( CHAR_DATA *ch, char *tag, int num, char *line );
void imc_save_pfile( struct char_data *ch, FBFILE *fp );
#endif
#endif