Cyclone-R01-dist/
/*
 * IMC2 version 0.10 - an inter-mud communications protocol
 * Copyright (C) 1996 & 1997 Oliver Jowett <oliver@randomly.org>
 *
 * IMC2 Gold versions 1.00 though 2.00 were developed by MudWorld.
 * Copyright (C) 1999 - 2002 Haslage Net Electronics (Anthony R. Haslage)
 *
 * IMC2 MUD-Net version 3.10 was developed by Alsherok and Crimson Oracles
 * Copyright (C) 2002 Roger Libiez ( Samson )
 * Additional code Copyright (C) 2002 Orion Elder
 * Registered with the United States Copyright Office
 * TX 5-555-584
 *
 * IMC2 Hermes R01-R04 were developed by Rogel
 * Copyright (C) 2003-2004 by Rogel
 *
 * IMC2 Cyclone R01 was developed by Rogel
 * Copyright (C) 2004 by Rogel
 *
 * 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 2 of the License, 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 (see the file COPYING); if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/* This is the protocol version */
#define IMC_VERSION 2
#define IMC_VERSIONID "IMC2 R-01 Cyclone Bridge"

#define IMC_CONFIG_FILE     "./config"

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

#define DISPOSE(point) 								\
do											\
{											\
  if (!(point))									\
  {											\
	Log( "Freeing null pointer @ %s:%d\n", __FILE__, __LINE__ ); \
  }											\
  else										\
  {											\
     free((point));								\
     (point) = NULL;								\
  }											\
} while(0)

/* double-linked list handling macros -Thoric ( From the Smaug codebase ) */
/* Updated by Scion 8/6/1999 */
#define LINK(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 INSERT(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 UNLINK(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)

/* 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

/* maximum time spent in getting a connection to a remote mud */
#define IMC_LOGIN_TIMEOUT 120

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

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

/* Changing these defines 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) (max length equal to 15,938 by default) */
#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

/* connection states */
enum{ CONN_NONE, CONN_SERVERCONNECT, CONN_WAITSERVERPWD, CONN_COMPLETE } connection_states;

/* String Defines - Used to set lengths of numerous string arrays in code */
/* Should be no need to change these. */
// Large String Size
#define LSS 4096
// Medium String Size
#define MSS 1024
// Small String Size
#define SSS 256

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

#if !defined(FALSE) || !defined(TRUE)
typedef enum { FALSE, TRUE } bool;
#endif

/* String Comparison Macros */
#define STR_EQL(a,b) (strcmp ((a), (b)) == 0)
#define STR_CEQL(a,b) (strcasecmp ((a), (b)) == 0)
#define STRN_EQL(a,b,n) (strncmp ((a), (b), (n)) == 0)
#define STRN_CEQL(a,b,n) (strncasecmp ((a), (b), (n)) == 0)

/* typedefs */

typedef struct imc_connect CONNECTION;
typedef struct imc_network NETWORK;
typedef struct imc_affiliate AFFILIATE;
typedef struct imc_reminfo REMINFO;
typedef struct imc_packet PACKET;
typedef struct imc_channel CHANNEL;

extern CONNECTION *first_connection;
extern CONNECTION *last_connection;
extern NETWORK *first_network;
extern NETWORK *last_network;
extern REMINFO *first_reminfo;
extern REMINFO *last_reminfo;
extern CHANNEL *first_channel;
extern CHANNEL *last_channel;

/* 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;
};

/* an actual IMC connection */
struct imc_connect
{
   CONNECTION *next;
   CONNECTION *prev;
   AFFILIATE *affiliate;  /* network affiliate that we are posing as */
   int desc;		     /* descriptor */
   unsigned short state;     /* IMC_xxxx state */
   unsigned short version;   /* version of remote site */
   bool newoutput;          /* try to write at end of cycle regardless of fd_set state? */
   char *inbuf;		     /* input buffer */
   unsigned int insize;
   char *outbuf;		     /* output buffer */
   unsigned int outsize;
   char *ip;              /* IP of connection */
};

/* a network listing */
struct imc_network
{
   NETWORK *next;
   NETWORK *prev;
   char *netname;		/* name of network */
   char *host;			/* hostname */
   unsigned short port;		/* remote port */
   char *serverpw;		/* server password */
   char *clientpw;		/* client password */
   char *blacklist;     /* list of people/muds blacklisted from sending to this network */
   AFFILIATE *first_affiliate;
   AFFILIATE *last_affiliate;
};

/* a network's affiliate */
struct imc_affiliate
{
    AFFILIATE *next;
    AFFILIATE *prev;
    char *name;             /* Name of the affiliate */
    NETWORK *network;       /* Network affiliated to */
    AFFILIATE *equiv;       /* Equivalent info for affiliate's record of this connection */
    CONNECTION *connection; /* Affiliate's connection to the network */
    bool full_bridge;       /* Pass network listings through? */
};

/* channel information */
struct imc_channel
{
    CHANNEL *next;
    CHANNEL *prev;
    char *local_channels;
};

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

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

/* info about another mud on IMC */
struct imc_reminfo
{
   REMINFO *next;
   REMINFO *prev;
   NETWORK *network;
   char *name;
   char *netname;
   char *web;
   char *version;
   char *path;
   unsigned long top_sequence;
};

struct imc_keepalive
{
    REMINFO *remote;
    char destination[IMC_MNAME_LENGTH];
    unsigned int count;
    AFFILIATE *affiliate;
};

/* an event */
typedef struct _imc_event
{
   time_t when;
   void (*callback)(void *data);
   void *data;
   struct _imc_event *next;
} imc_event;

/* for the versioning table */
typedef struct
{
   unsigned char version;
   char *(*generate) (PACKET *, AFFILIATE *);
   PACKET *(*interpret) (const char *);
} _imc_vinfo;

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

/* data structures */

/* the packet memory table */
extern _imc_memory imc_memory[IMC_MEMORY];

/* the version lookup table */
extern _imc_vinfo imc_vinfo[];

/* global stats struct */
extern imc_statistics imc_stats;

/* the event list, and recycle list */
extern imc_event *imc_event_list, *imc_event_free;

/* the current time */
extern time_t imc_now;

/* next sequence number to use */
extern unsigned long imc_sequencenumber;

/* main loop for bridge */
void bridge_loop( struct timeval  last_time );

/* Logging */
void Log( const char *format, ... );

/* event handling */
void imc_add_event( int when, void (*callback)(void *), void *data );
void imc_cancel_event( void (*callback)(void *), void *data );
imc_event *imc_find_event(void (*callback)(void *), void *data);
int imc_next_event( void (*callback)(void *), void *data );
unsigned int imc_get_event_timeout( void );
void imc_run_events(time_t newtime);
void ev_close_notify( void *data );
void ev_login_timeout( void *data );
void ev_reconnect( void *data );
void ev_send_isalive( void *data );
void imc_send( PACKET *p, AFFILIATE *a );
void imc_recv( PACKET *p, AFFILIATE *a );
void imc_startup( void );
void imc_shutdown( void );
void imc_idle(unsigned int s);
void imc_idle_select( fd_set *sread, fd_set *swrite, fd_set *exc, time_t now );
bool imc_connect_to( AFFILIATE *i );
void imc_send_tell( const char *to, const char *argument, AFFILIATE *a );
void imc_send_whoreply( const char *to, const char *data, AFFILIATE *a );
void imc_send_keepalive( REMINFO *r, char *destination, AFFILIATE *a );
void imc_send_pingreply( const char *to, const char *path, AFFILIATE *a );
void imc_recv_who( PACKET *p, const char *pname, const char *type, AFFILIATE *a );
bool imc_readconfig( void );
NETWORK *imc_new_network( void );
char *find_channel_equivalent( const char *from, NETWORK *from_network, NETWORK *to_network );

/* Event support functions */
void imc_request_keepalive( AFFILIATE *a );