diff -uN src/Makefile mccp-src/Makefile
--- src/Makefile	Mon Aug 25 12:51:09 1997
+++ mccp-src/Makefile	Wed Mar 10 12:15:05 1999
@@ -2,13 +2,13 @@
 PROF    = -O -g
 NOCRYPT =
 C_FLAGS =  -Wall $(PROF) $(NOCRYPT)
-L_FLAGS =  $(PROF)
+L_FLAGS =  $(PROF) -lz -lcrypt
 
 ROT_FILES = act_comm.o act_enter.o act_info.o act_move.o act_obj.o act_wiz.o \
           alias.o ban.o clans.o comm.o const.o curse.o db.o db2.o effects.o \
 	  fight.o finger.o flags.o forget.o handler.o healer.o interp.o note.o \
 	  lookup.o magic.o magic2.o music.o recycle.o repent.o save.o scan.o \
-	  sign.o skills.o special.o tables.o update.o wizlist.o
+	  sign.o skills.o special.o tables.o update.o wizlist.o mccp.o
 
 all:: rot
 
diff -uN src/README.Rot14.mccp mccp-src/README.Rot14.mccp
--- src/README.Rot14.mccp	Wed Dec 31 18:00:00 1969
+++ mccp-src/README.Rot14.mccp	Wed Mar 10 14:08:19 1999
@@ -0,0 +1,64 @@
+Mud Client Compression Protocol support for ROT 1.4
+
+Oliver Jowett <icecube@ihug.co.nz>, 990310
+Dominic Eidson <dominic@the-infinite.org>, 990310
+
+This patch (against Rot 1.4) adds support for compression of output to
+clients that support mccp. The two main benefits of mccp are:
+
+1. lower bandwidth use by the mud.
+2. clients (i.e. players) get large responses (such as, for example, combat
+   spam) from the mud at a higher rate - the mud will "feel" faster, despite
+   the fact that the actual round-trip times are unchanged.
+
+With a suitable client, mccp is entirely transparent to the user - it
+automatically enables itself when supported by both the server and client.
+
+For more details on the protocol, and a list of clients and servers currently
+supporting it, see <URL:http://homepages.ihug.co.nz/~icecube/compress/>. If
+you add mccp support to your mud or a mud client, mail me and I'll add it to
+the list.
+
+Improvements and bugfixes are welcome - unfortunately I don't have the time
+(or desire) to personally work on a large number of patches for many
+different codebases.
+
+To use this patch, you will need a copy of zlib installed - see
+<URL:http://www.cdrom.com/pub/infozip/zlib/>. Many systems will already have
+a version installed.
+
+Copyright/usage: see mccp.c - in essence, use as you wish, as long as
+copyright notices are retained.
+
+
+CAVEATS
+
+. This patch was thrown together in about an hour, and I last looked at the
+  Rom source code about 12 months ago. YMMV.
+  <It took me 10 minutes to create the ROT 1.4 patch, based on
+  Nemon's ROM patch - Dominic>
+. Testing has only been done over local loopback. Unforseen bugs due to timing
+  or network error handling etc. are possible.
+  <I did test it on a stock ROT, it works, at least did for me (with mcl
+  0.50.01) - Dominic>
+
+. The simple-but-stupid approach has been taken. Much of the network I/O
+  code could do with a rewrite, but I've left it mostly as-is and only changed
+  those parts that are necessary to implement mccp.
+. Telnet option negotiation and handling of IAC sequences is very naive (but,
+  it's completely nonexistant in the base code..)
+. Telnet option negotiation is not done continuously, but only when the client
+  enters a complete line.
+
+. The write_to_descriptor prototype has changed! If you call it anywhere
+  other than where the standard code calls it, you will need to:
+  - Update the prototype to the new version (see comm.cc) if you've copied
+    it to other files.
+  - Pass the entire DESCRIPTOR_DATA * of the descriptor, instead of just the
+    fd - i.e. write_to_descriptor(d, txt, len) instead of
+    write_to_descriptor(d->descriptor, txt, len).
+
+. If you must write to a descriptor by fd not DESCRIPTOR_DATA *, then
+  write_to_descriptor_2 is available -- BUT it will not compress output
+  data! If you call this function on a connection that has compression
+  enabled, compression will FAIL and the client will disconnect!
diff -uN src/comm.c mccp-src/comm.c
--- src/comm.c	Mon Aug 25 12:51:09 1997
+++ mccp-src/comm.c	Wed Mar 10 12:35:21 1999
@@ -62,7 +62,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <time.h>
-
+#include <unistd.h>
 #include "merc.h"
 #include "recycle.h"
 #include "tables.h"
@@ -116,6 +116,10 @@
 const	char	echo_off_str	[] = { '\0' };
 const	char	echo_on_str	[] = { '\0' };
 const	char 	go_ahead_str	[] = { '\0' };
+const   char    compress_will   [] = { '\0' };
+const   char    compress_do     [] = { '\0' };
+const   char    compress_dont   [] = { '\0' };
+const   char    compress_start  [] = { '\0' };
 #endif
 
 #if	defined(unix)
@@ -124,9 +128,15 @@
 #include <netinet/in.h>
 #include <sys/socket.h>
 #include "telnet.h"
+
 const	char	echo_off_str	[] = { IAC, WILL, TELOPT_ECHO, '\0' };
 const	char	echo_on_str	[] = { IAC, WONT, TELOPT_ECHO, '\0' };
 const	char 	go_ahead_str	[] = { IAC, GA, '\0' };
+
+/* mccp: compression negotiation strings */
+const   char    compress_will   [] = { IAC, WILL, TELOPT_COMPRESS, '\0' };
+const   char    compress_do     [] = { IAC, DO, TELOPT_COMPRESS, '\0' };
+const   char    compress_dont   [] = { IAC, DONT, TELOPT_COMPRESS, '\0' };
 #endif
 
 
@@ -171,21 +181,6 @@
 #include <sys/fnctl.h>
 #endif
 
-#if	defined(linux)
-int	accept		args( ( int s, struct sockaddr *addr, int *addrlen ) );
-int	bind		args( ( int s, struct sockaddr *name, int namelen ) );
-int	close		args( ( int fd ) );
-int	getpeername	args( ( int s, struct sockaddr *name, int *namelen ) );
-int	getsockname	args( ( int s, struct sockaddr *name, int *namelen ) );
-int	gettimeofday	args( ( struct timeval *tp, struct timezone *tzp ) );
-int	listen		args( ( int s, int backlog ) );
-int	read		args( ( int fd, char *buf, int nbyte ) );
-int	select		args( ( int width, fd_set *readfds, fd_set *writefds,
-			    fd_set *exceptfds, struct timeval *timeout ) );
-int	socket		args( ( int domain, int type, int protocol ) );
-int	write		args( ( int fd, char *buf, int nbyte ) );
-#endif
-
 #if	defined(macintosh)
 #include <console.h>
 #include <fcntl.h>
@@ -326,7 +321,8 @@
 void	init_descriptor		args( ( int control ) );
 void	init_descriptor_www	args( ( int wwwcontrol ) );
 bool	read_from_descriptor	args( ( DESCRIPTOR_DATA *d ) );
-bool	write_to_descriptor	args( ( int desc, char *txt, int length ) );
+bool	write_to_descriptor	args( ( DESCRIPTOR_DATA *d, char *txt, int length ) );
+bool	write_to_descriptor_2	args( ( int desc, char *txt, int length ) );
 #endif
 
 
@@ -882,10 +878,18 @@
 	{
 	    d_next = d->next;
 
-	    if ( ( d->fcommand || d->outtop > 0 )
+	    if ( ( d->fcommand || d->outtop > 0 || d->out_compress )
 	    &&   FD_ISSET(d->descriptor, &out_set) )
-	    {
-		if ( !process_output( d, TRUE ) )
+            {
+                bool ok = TRUE;
+                
+                if ( d->fcommand || d->outtop > 0 )
+                    ok = process_output( d, TRUE );
+
+                if (ok && d->out_compress)
+                    ok = processCompressed(d);
+                
+		if (!ok)
 		{
 		    if ( d->character != NULL && d->character->level > 1)
 			save_char_obj( d->character );
@@ -1023,7 +1027,7 @@
      */
     if ( check_ban(dnew->host,BAN_ALL))
     {
-	write_to_descriptor( desc,
+	write_to_descriptor_2( desc,
 	    "Your site has been banned from this mud.\n\r", 0 );
 	close( desc );
 	free_descriptor(dnew);
@@ -1038,6 +1042,10 @@
     /*
      * Send the greeting.
      */
+
+    /* mccp: tell the client we support compression */
+    write_to_buffer( dnew, compress_will, 0 );
+    
     {
 	extern char * help_greetinga;
 	extern char * help_greetingb;
@@ -1345,6 +1353,12 @@
 	    bug( "Close_socket: dclose not found.", 0 );
     }
 
+    if (dclose->out_compress) {
+        deflateEnd(dclose->out_compress);
+        free_mem(dclose->out_compress_buf, COMPRESS_BUF_SIZE);
+        free_mem(dclose->out_compress, sizeof(z_stream));
+    }
+    
     close( dclose->descriptor );
     free_descriptor(dclose);
 #if defined(MSDOS) || defined(macintosh)
@@ -1369,7 +1383,7 @@
     {
 	sprintf( log_buf, "%s input overflow!", d->host );
 	log_string( log_buf );
-	write_to_descriptor( d->descriptor,
+	write_to_descriptor( d,
 	    "\n\r*** PUT A LID ON IT!!! ***\n\r", 0 );
 	return FALSE;
     }
@@ -1454,7 +1468,7 @@
     {
 	if ( k >= MAX_INPUT_LENGTH - 2 )
 	{
-	    write_to_descriptor( d->descriptor, "Line too long.\n\r", 0 );
+	    write_to_descriptor( d, "Line too long.\n\r", 0 );
 
 	    /* skip the rest of the line */
 	    for ( ; d->inbuf[i] != '\0'; i++ )
@@ -1471,6 +1485,16 @@
 	    --k;
 	else if ( isascii(d->inbuf[i]) && isprint(d->inbuf[i]) )
 	    d->incomm[k++] = d->inbuf[i];
+        else if (d->inbuf[i] == (signed char)IAC) {
+            if (!memcmp(&d->inbuf[i], compress_do, strlen(compress_do))) {
+                i += strlen(compress_do) - 1;
+                compressStart(d);
+            }
+            else if (!memcmp(&d->inbuf[i], compress_dont, strlen(compress_dont))) {
+                i += strlen(compress_dont) - 1;
+                compressEnd(d);
+            }
+        }
     }
 
     /*
@@ -1645,7 +1669,7 @@
     /*
      * OS-dependent output.
      */
-    if ( !write_to_descriptor( d->descriptor, d->outbuf, d->outtop ) )
+    if ( !write_to_descriptor( d, d->outbuf, d->outtop ) )
     {
 	d->outtop = 0;
 	return FALSE;
@@ -1847,7 +1871,7 @@
  * If this gives errors on very long blocks (like 'ofind all'),
  *   try lowering the max block size.
  */
-bool write_to_descriptor( int desc, char *txt, int length )
+bool write_to_descriptor_2( int desc, char *txt, int length )
 {
     int iStart;
     int nWrite;
@@ -1871,8 +1895,15 @@
     return TRUE;
 }
 
-
-
+/* mccp: write_to_descriptor wrapper */
+bool write_to_descriptor(DESCRIPTOR_DATA *d, char *txt, int length)
+{
+    if (d->out_compress)
+        return writeCompressed(d, txt, length);
+    else
+        return write_to_descriptor_2(d->descriptor, txt, length);
+}
+    
 /*
  * Deal with sockets that haven't logged in yet.
  */
diff -uN src/db.c mccp-src/db.c
--- src/db.c	Mon Aug 25 12:51:09 1997
+++ mccp-src/db.c	Wed Mar 10 12:35:40 1999
@@ -56,14 +56,6 @@
 extern	int	_filbuf		args( (FILE *) );
 #endif
 
-#if !defined(OLD_RAND)
-long random();
-void srandom(unsigned int);
-int getpid();
-time_t time(time_t *tloc);
-#endif
-
-
 /* externals for counting purposes */
 extern	OBJ_DATA	*obj_free;
 extern	CHAR_DATA	*char_free;
diff -uN src/interp.c mccp-src/interp.c
--- src/interp.c	Mon Aug 25 12:51:09 1997
+++ mccp-src/interp.c	Wed Mar 10 12:13:27 1999
@@ -174,6 +174,7 @@
     { "color",          do_colour,      POS_DEAD,        0,  1,  LOG_NORMAL, 1 },
     { "combine",	do_combine,	POS_DEAD,        0,  1,  LOG_NORMAL, 1 },
     { "compact",	do_compact,	POS_DEAD,        0,  1,  LOG_NORMAL, 1 },
+    { "compress",	do_compress,	POS_DEAD,        0,  1,  LOG_NORMAL, 1 },
     { "description",	do_description,	POS_DEAD,	 0,  1,  LOG_NORMAL, 1 },
     { "long",		do_long,	POS_DEAD,        0,  1,  LOG_NORMAL, 1 },
     { "nofollow",	do_nofollow,	POS_DEAD,        0,  1,  LOG_NORMAL, 1 },
diff -uN src/interp.h mccp-src/interp.h
--- src/interp.h	Mon Aug 25 12:51:09 1997
+++ mccp-src/interp.h	Wed Mar 10 12:10:27 1999
@@ -117,6 +117,7 @@
 DECLARE_DO_FUN( do_combine	);
 DECLARE_DO_FUN( do_compact	);
 DECLARE_DO_FUN(	do_compare	);
+DECLARE_DO_FUN(	do_compress	);
 DECLARE_DO_FUN(	do_consider	);
 DECLARE_DO_FUN(	do_corner	);
 DECLARE_DO_FUN( do_count	);
diff -uN src/mccp.c mccp-src/mccp.c
--- src/mccp.c	Wed Dec 31 18:00:00 1969
+++ mccp-src/mccp.c	Wed Mar 10 12:10:27 1999
@@ -0,0 +1,206 @@
+/*
+ * mccp.c - support functions for mccp (the Mud Client Compression Protocol)
+ *
+ * see http://homepages.ihug.co.nz/~icecube/compress/ and README.Rom24-mccp
+ *
+ * Copyright (c) 1999, Oliver Jowett <icecube@ihug.co.nz>.
+ *
+ * This code may be freely distributed and used if this copyright notice is
+ * retained intact.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "merc.h"
+#include "telnet.h"
+
+char    compress_start  [] = { IAC, SB, TELOPT_COMPRESS, WILL, SE, '\0' };
+
+bool processCompressed(DESCRIPTOR_DATA *desc);
+bool	write_to_descriptor	args( ( DESCRIPTOR_DATA *d, char *txt, int length ) );
+
+/*
+ * Memory management - zlib uses these hooks to allocate and free memory
+ * it needs
+ */
+
+void *zlib_alloc(void *opaque, unsigned int items, unsigned int size)
+{
+    return calloc(items, size);
+}
+
+void zlib_free(void *opaque, void *address)
+{
+    free(address);
+}
+
+/*
+ * Begin compressing data on `desc'
+ */
+bool compressStart(DESCRIPTOR_DATA *desc)
+{
+    z_stream *s;
+    
+    if (desc->out_compress) /* already compressing */
+        return TRUE;
+
+    /* allocate and init stream, buffer */
+    s = (z_stream *)alloc_mem(sizeof(*s));
+    desc->out_compress_buf = (unsigned char *)alloc_mem(COMPRESS_BUF_SIZE);
+    
+    s->next_in = NULL;
+    s->avail_in = 0;
+
+    s->next_out = desc->out_compress_buf;
+    s->avail_out = COMPRESS_BUF_SIZE;
+
+    s->zalloc = zlib_alloc;
+    s->zfree  = zlib_free;
+    s->opaque = NULL;
+
+    if (deflateInit(s, 9) != Z_OK) {
+        /* problems with zlib, try to clean up */
+        free_mem(desc->out_compress_buf, COMPRESS_BUF_SIZE);
+        free_mem(s, sizeof(z_stream));
+        return FALSE;
+    }
+
+    write_to_descriptor(desc, compress_start, strlen(compress_start));
+
+    /* now we're compressing */
+    desc->out_compress = s;
+    return TRUE;
+}
+
+/* Cleanly shut down compression on `desc' */
+bool compressEnd(DESCRIPTOR_DATA *desc)
+{
+    unsigned char dummy[1];
+    
+    if (!desc->out_compress)
+        return TRUE;
+
+    desc->out_compress->avail_in = 0;
+    desc->out_compress->next_in = dummy;
+
+    /* No terminating signature is needed - receiver will get Z_STREAM_END */
+    
+    if (deflate(desc->out_compress, Z_FINISH) != Z_STREAM_END)
+        return FALSE;
+
+    if (!processCompressed(desc)) /* try to send any residual data */
+        return FALSE;
+
+    deflateEnd(desc->out_compress);
+    free_mem(desc->out_compress_buf, COMPRESS_BUF_SIZE);
+    free_mem(desc->out_compress, sizeof(z_stream));
+    desc->out_compress = NULL;
+    desc->out_compress_buf = NULL;
+
+    return TRUE;
+}
+
+/* Try to send any pending compressed-but-not-sent data in `desc' */
+bool processCompressed(DESCRIPTOR_DATA *desc)
+{
+    int iStart, nBlock, nWrite, len;
+
+    if (!desc->out_compress)
+        return TRUE;
+    
+    /* Try to write out some data.. */
+    len = desc->out_compress->next_out - desc->out_compress_buf;
+    if (len > 0) {
+        /* we have some data to write */
+
+        for (iStart = 0; iStart < len; iStart += nWrite)
+        {
+            nBlock = UMIN (len - iStart, 4096);
+            if ((nWrite = write (desc->descriptor, desc->out_compress_buf + iStart, nBlock)) < 0)
+            {
+                if (errno == EAGAIN ||
+                    errno == ENOSR)
+                    break;
+
+                return FALSE; /* write error */
+            }
+
+            if (nWrite <= 0)
+                break;
+        }
+
+        if (iStart) {
+            /* We wrote "iStart" bytes */
+            if (iStart < len)
+                memmove(desc->out_compress_buf, desc->out_compress_buf+iStart, len - iStart);
+
+            desc->out_compress->next_out = desc->out_compress_buf + len - iStart;
+        }
+    }
+
+    return TRUE;
+}
+
+/* write_to_descriptor, the compressed case */
+bool writeCompressed(DESCRIPTOR_DATA *desc, char *txt, int length)
+{
+    z_stream *s = desc->out_compress;
+    
+    s->next_in = (unsigned char *)txt;
+    s->avail_in = length;
+
+    while (s->avail_in) {
+        s->avail_out = COMPRESS_BUF_SIZE - (s->next_out - desc->out_compress_buf);
+            
+        if (s->avail_out) {
+            int status = deflate(s, Z_SYNC_FLUSH);
+
+            if (status != Z_OK) {
+                /* Boom */
+                return FALSE;
+            }
+        }
+
+        /* Try to write out some data.. */
+        if (!processCompressed(desc))
+            return FALSE;
+
+        /* loop */
+    }
+    
+    /* Done. */
+    return TRUE;
+}
+
+/* User-level compression toggle */
+void do_compress( CHAR_DATA *ch, char *argument )
+{
+    if (!ch->desc) {
+        send_to_char("What descriptor?!\n", ch);
+        return;
+    }
+
+    if (!ch->desc->out_compress) {
+        if (!compressStart(ch->desc)) {
+            send_to_char("Failed.\n", ch);
+            return;
+        }
+
+        send_to_char("Ok, compression enabled.\n", ch);
+    } else {
+        if (!compressEnd(ch->desc)) {
+            send_to_char("Failed.\n", ch);
+            return;
+        }
+
+        send_to_char("Ok, compression disabled.\n", ch);
+    }
+}
diff -uN src/merc.h mccp-src/merc.h
--- src/merc.h	Mon Aug 25 12:51:09 1997
+++ mccp-src/merc.h	Wed Mar 10 12:33:48 1999
@@ -52,6 +52,10 @@
 int unlink();
 int system();
 
+/* mccp: support bits */
+#include <zlib.h>
+#define TELOPT_COMPRESS 85
+#define COMPRESS_BUF_SIZE 16384
 
 
 /*
@@ -356,6 +360,8 @@
     int			outtop;
     char *		showstr_head;
     char *		showstr_point;
+    z_stream *          out_compress;		/* mccp: support data */
+    unsigned char *     out_compress_buf;
 };
 
 
@@ -2286,8 +2292,6 @@
 char *	crypt		args( ( const char *key, const char *salt ) );
 #endif
 
-
-
 /*
  * The crypt(3) function is not available on some operating systems.
  * In particular, the U.S. Government prohibits its export from the
@@ -2643,6 +2647,13 @@
 void	gain_exp	args( ( CHAR_DATA *ch, int gain ) );
 void	gain_condition	args( ( CHAR_DATA *ch, int iCond, int value ) );
 void	update_handler	args( ( void ) );
+
+/* mccp.c */
+bool compressStart(DESCRIPTOR_DATA *desc);
+bool compressEnd(DESCRIPTOR_DATA *desc);
+bool processCompressed(DESCRIPTOR_DATA *desc);
+bool writeCompressed(DESCRIPTOR_DATA *desc, char *txt, int length);
+
 
 /* wizlist.c */
 void	update_wizlist	args( ( CHAR_DATA *ch, int level ) );
