summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Khon <fjoe@FreeBSD.org>2002-01-07 20:26:38 +0000
committerMax Khon <fjoe@FreeBSD.org>2002-01-07 20:26:38 +0000
commitefce757995697686c97291c8519d36ff87badd02 (patch)
tree614e212ba22dd1ae25f9fa5d0ed382443fc7d8da
parentUpgrade to 0.11.5. (diff)
- add -DWITH_MCCP (mccp v1/v2 support)
- assume maintainership
Notes
Notes: svn path=/head/; revision=52729
-rw-r--r--net/tinyfugue/Makefile19
-rw-r--r--net/tinyfugue/files/mccp-patch218
-rw-r--r--net/tinyfugue/files/mccp.c426
-rw-r--r--net/tinyfugue/files/mccp.h141
4 files changed, 802 insertions, 2 deletions
diff --git a/net/tinyfugue/Makefile b/net/tinyfugue/Makefile
index 5585af693765..b827178eb9c6 100644
--- a/net/tinyfugue/Makefile
+++ b/net/tinyfugue/Makefile
@@ -13,7 +13,7 @@ MASTER_SITES= ftp://tf.tcp.com/pub/tinyfugue/ \
ftp://ftp.ci.uminho.pt/pub/mirrors/tinyfugue/
DISTNAME= tf-40s1
-MAINTAINER= ports@FreeBSD.org
+MAINTAINER= fjoe@FreeBSD.org
.if defined(PARALLEL_PACKAGE_BUILD)
BROKEN= tries to cd to directory that do not exist yet
@@ -26,4 +26,19 @@ MAKE_ENV= TFVER=${DISTNAME:S/^tf-//}
MAN1= tf.1
-.include <bsd.port.mk>
+.include <bsd.port.pre.mk>
+
+.if defined(WITH_MCCP)
+EXTRA_PATCHES= ${FILESDIR}/mccp-patch
+PKGNAMESUFFIX= -mccp
+
+post-extract:
+ @${CP} ${FILESDIR}/mccp.[ch] ${WRKSRC}/src
+.else
+pre-extract:
+ @${ECHO_MSG}
+ @${ECHO_MSG} "You can enable MCCP v1/v2 support by defining WITH_MCCP"
+ @${ECHO_MSG}
+.endif
+
+.include <bsd.port.post.mk>
diff --git a/net/tinyfugue/files/mccp-patch b/net/tinyfugue/files/mccp-patch
new file mode 100644
index 000000000000..047a6d96cc8f
--- /dev/null
+++ b/net/tinyfugue/files/mccp-patch
@@ -0,0 +1,218 @@
+--- src/rules.mak.orig Sun Mar 7 04:43:25 1999
++++ src/rules.mak Fri Jun 23 05:46:38 2000
+@@ -50,6 +50,7 @@ main.$O: main.c config.h port.h dstring.
+ variable.h tty.h $(BUILDERS)
+ makehelp.$O: makehelp.c config.h port.h $(BUILDERS)
+ malloc.$O: malloc.c config.h port.h signals.h malloc.h $(BUILDERS)
++mccp.$O: mccp.c mccp.h
+ output.$O: output.c config.h port.h dstring.h $(TF_H) util.h tfio.h socket.h \
+ output.h macro.h search.h tty.h variable.h expr.h $(BUILDERS)
+ process.$O: process.c config.h port.h dstring.h $(TF_H) util.h tfio.h \
+@@ -59,7 +60,7 @@ signals.$O: signals.c config.h port.h ds
+ process.h tty.h output.h signals.h variable.h $(BUILDERS)
+ socket.$O: socket.c config.h port.h dstring.h $(TF_H) util.h tfio.h tfselect.h \
+ history.h world.h socket.h output.h process.h macro.h keyboard.h \
+- commands.h command.h signals.h search.h $(BUILDERS)
++ commands.h command.h signals.h search.h mccp.h $(BUILDERS)
+ tfio.$O: tfio.c config.h port.h dstring.h $(TF_H) util.h tfio.h tfselect.h \
+ output.h macro.h history.h search.h signals.h variable.h $(BUILDERS)
+ tty.$O: tty.c config.h port.h $(TF_H) dstring.h util.h tty.h output.h macro.h \
+--- src/socket.c.orig Sun Mar 7 04:43:25 1999
++++ src/socket.c Sat Jul 1 06:22:52 2000
+@@ -67,6 +67,10 @@ struct sockaddr_in {
+ #include "search.h"
+ #include "variable.h" /* set_var_by_*() */
+
++#ifdef MUDCOMPRESS
++# include "mccp.h"
++#endif
++
+ #ifdef _POSIX_VERSION
+ # include <sys/wait.h>
+ #endif
+@@ -206,6 +210,9 @@ typedef struct Sock { /* an open connec
+ TIME_T time[2]; /* time of last receive/send */
+ char state; /* state of parser finite state automaton */
+ long pid; /* pid of name resolution process */
++#ifdef MUDCOMPRESS
++ mc_state *mccp; /* mud compression struct */
++#endif
+ } Sock;
+
+
+@@ -806,6 +813,9 @@ int opensock(world, autologin, quietlogi
+ tsock = *(tsock ? &tsock->next : &hsock) = xsock;
+ xsock->activity = 0;
+ Stringinit(xsock->buffer);
++#ifdef MUDCOMPRESS
++ xsock->mccp = mudcompress_new();
++#endif
+ xsock->prompt = NULL;
+ init_queue(xsock->queue = (Queue *)XMALLOC(sizeof(Queue)));
+ xsock->next = NULL;
+@@ -1297,6 +1307,9 @@ static void nukesock(sock)
+ #endif /* NONBLOCKING_GETHOST */
+ }
+ Stringfree(sock->buffer);
++#ifdef MUDCOMPRESS
++ mudcompress_delete(sock->mccp);
++#endif
+ if (sock->prompt) free_aline(sock->prompt);
+ while(sock->queue->head)
+ free_aline((Aline*)unlist(sock->queue->head, sock->queue));
+@@ -1728,8 +1741,25 @@ static int handle_socket_input()
+ }
+
+ do { /* while (n > 0 && !interrupted() && (received += count) < SPAM) */
+- do count = recv(xsock->fd, buffer, sizeof(buffer), 0);
+- while (count < 0 && errno == EINTR);
++#ifdef MUDCOMPRESS
++ if (!mudcompress_pending(xsock->mccp))
++ {
++ do count = recv(xsock->fd, buffer, sizeof(buffer), 0);
++ while (count < 0 && errno == EINTR);
++
++ if (count > 0) {
++ mudcompress_receive(xsock->mccp, buffer, count);
++ if (mudcompress_error(xsock->mccp)) {
++ count = -1;
++ errno = EIO;
++ }
++ }
++ }
++#else
++ do count = recv(xsock->fd, buffer, sizeof(buffer), 0);
++ while (count < 0 && errno == EINTR);
++#endif
++
+ if (count <= 0) {
+ int err = errno;
+ #ifdef SUNOS_5_4
+@@ -1761,6 +1791,25 @@ static int handle_socket_input()
+ return received;
+ }
+
++ received += count;
++
++#ifdef MUDCOMPRESS
++ {
++ const char *resp;
++
++ count = 0;
++ while (count < sizeof(buffer)
++ && mudcompress_pending(xsock->mccp)) {
++ count += mudcompress_get(xsock->mccp, buffer + count,
++ sizeof(buffer) - count);
++ }
++
++ resp = mudcompress_response(xsock->mccp);
++ if (resp)
++ transmit(resp,strlen(resp));
++ }
++#endif
++
+ for (place = buffer; place - buffer < count; place++) {
+
+ /* We always accept 8-bit data, even though RFCs 854 and 1123
+@@ -1958,7 +2007,6 @@ static int handle_socket_input()
+ }
+
+ /* See if anything arrived while we were parsing */
+-
+ FD_ZERO(&readfds);
+ FD_SET(xsock->fd, &readfds);
+ tv.tv_sec = tv.tv_usec = 0;
+@@ -1976,7 +2024,13 @@ static int handle_socket_input()
+ if (errno != EINTR) die("handle_socket_input: select", errno);
+ }
+
+- } while (n > 0 && !interrupted() && (received += count) < SPAM);
++#ifdef MUDCOMPRESS
++ if (mudcompress_pending(xsock->mccp)) {
++ n = 1;
++ }
++#endif
++
++ } while (n > 0 && !interrupted() && received < SPAM);
+
+ /* If lpflag is on and we got a partial line from the fg world,
+ * assume the line is a prompt.
+--- src/tf.1.catman.orig Sun Mar 7 04:43:25 1999
++++ src/tf.1.catman Sat Jun 24 01:25:46 2000
+@@ -152,6 +152,8 @@ TF(1)
+
+ Recall previously received text.
+
++ Support for the Mud Client Compression Protocol version 1 and 2.
++
+
+ CCOONNFFIIGGUURRAATTIIOONN FFIILLEESS
+ _T_F will attempt to read two files when starting. The
+--- src/tf.1.nroffman.orig Sun Mar 7 04:43:25 1999
++++ src/tf.1.nroffman Sat Jun 24 01:25:04 2000
+@@ -112,6 +112,8 @@ Separate LP and Diku style prompts from
+ Page output using a --More-- prompt.
+ .sp
+ Recall previously received text.
++.sp
++Support for Mud Client Compression Protocol versions 1 and 2.
+
+ .SH "CONFIGURATION FILES"
+ .PP
+--- src/vars.mak.orig Sun Mar 7 04:43:25 1999
++++ src/vars.mak Fri Jun 23 06:07:44 2000
+@@ -15,14 +15,14 @@
+ # Predefined variables:
+ # O - object file suffix (e.g., "o" or "obj")
+
+-TFVER=40s1
++TFVER=40s1-mccp
+
+ SOURCE = command.c dstring.c expand.c help.c history.c keyboard.c \
+ macro.c main.c malloc.c output.c process.c search.c signals.c \
+ socket.c tfio.c tty.c util.c variable.c world.c
+
+ OBJS = command.$O dstring.$O expand.$O expr.$O help.$O history.$O keyboard.$O \
+- macro.$O main.$O malloc.$O output.$O process.$O search.$O signals.$O \
++ macro.$O main.$O malloc.$O mccp.$O output.$O process.$O search.$O signals.$O \
+ socket.$O tfio.$O tty.$O util.$O variable.$O world.$O \
+ regexp.$O $(OTHER_OBJS)
+
+--- unix/tfconfig.orig Sun Mar 7 04:43:28 1999
++++ unix/tfconfig Wed Jul 5 05:56:02 2000
+@@ -482,6 +482,14 @@ else
+ echo "I can't find <pwd.h>. Filename '~user' expansion won't be supported."
+ fi
+
++### Find zlib.h
++if echo '#include <zlib.h>' >test.c; ${CPP} test.c >/dev/null 2>&1; then
++ echo "#define MUDCOMPRESS" >&4
++ echo "Found <zlib.h>."
++else
++ echo "I can't find <zlib.h>. The Mud Client Compression Protocol will not be supported."
++fi
++
+ ### Figure out how to do varadic args.
+ if [ "$STD_C" = "1" ] || [ "$GNU_C" = "1" ]; then
+ if echo '#include <stdarg.h>' >test.c; ${CPP} test.c >/dev/null 2>&1; then
+@@ -756,6 +764,12 @@ elif eval "${LIBTEST} -lsocket ${LIBS} >
+ else
+ echo "Warning: can't find connect() or a library that might have it."
+ echo "/* warning: tfconfig couldn't find connect() */" >&4
++fi
++
++### Test for zlib for mud compression
++if eval "${LIBTEST} -lz ${LIBS} >/dev/null 2>&1" && test -f ${AOUT}; then
++ echo "Will link with -lz."
++ LIBS="-lz $LIBS"
+ fi
+
+ ### Test for SOCKS firewall proxy server.
+--- unixmake.orig Sun Mar 7 04:43:24 1999
++++ unixmake Sat Jul 1 06:27:28 2000
+@@ -20,4 +20,4 @@ export PATH
+
+ MAKE=${MAKE-make}
+ export MAKE
+-${MAKE} -f unix/Makefile `egrep '^TFVER=' src/vars.mak` MAKE="${MAKE}" $*
++${MAKE} -j 1 -f unix/Makefile `egrep '^TFVER=' src/vars.mak` MAKE="${MAKE}" $*
diff --git a/net/tinyfugue/files/mccp.c b/net/tinyfugue/files/mccp.c
new file mode 100644
index 000000000000..79dd82b4952a
--- /dev/null
+++ b/net/tinyfugue/files/mccp.c
@@ -0,0 +1,426 @@
+/*
+ * Client decompression module for the mud client compression protocol.
+ * See http://homepages.ihug.co.nz/~icecube/compress/ for more details.
+ *
+ * mccpDecompress.c - module code. Link this with your client code.
+ *
+ * Oliver Jowett <icecube$ihug.co.nz>. Demangle address as needed.
+ *
+ * This code is placed in the public domain.
+ *
+ */
+
+/* Modified: 20000530 */
+
+/* See mccp.h for API information */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+#ifdef MUDCOMPRESS
+
+#include <zlib.h>
+
+#include "mccp.h"
+
+/* Telnet values we're interested in */
+
+#define IAC 255
+#define DONT 254
+#define DO 253
+#define WONT 252
+#define WILL 251
+#define SB 250
+#define SE 240
+
+#define TELOPT_COMPRESS 85
+#define TELOPT_COMPRESS2 86
+
+/* We say DO COMPRESS2 to WILL COMPRESS2, then DONT COMPRESS to WILL COMPRESS
+ * -or-
+ * We say DO COMPRESS to WILL COMPRESS if it arrives before any COMPRESS2.
+ *
+ * Later the server sends IAC SB COMPRESS IAC SE (v2) or IAC SB COMPRESS WILL
+ * SE (v1), and immediately following
+ * that, begins compressing
+ *
+ * Compression ends on a Z_STREAM_END, no other marker is used
+ */
+
+static char will_v1[] = { IAC, WILL, TELOPT_COMPRESS, 0 };
+static char do_v1[] = { IAC, DO, TELOPT_COMPRESS, 0 };
+static char dont_v1[] = { IAC, DONT, TELOPT_COMPRESS, 0 };
+static char on_v1[] = { IAC, SB, TELOPT_COMPRESS, WILL, SE, 0 };
+
+static char will_v2[] = { IAC, WILL, TELOPT_COMPRESS2, 0 };
+static char do_v2[] = { IAC, DO, TELOPT_COMPRESS2, 0 };
+static char on_v2[] = { IAC, SB, TELOPT_COMPRESS2, IAC, SE, 0 };
+
+/* "Opaque" state object */
+
+struct mc_state_s {
+ z_stream *stream; /* stream we're using */
+
+ unsigned char *inbuf; /* input buffer (data from mud) */
+ unsigned int insize; /* .. and how much is used */
+ unsigned int inalloc; /* .. and how much is allocated */
+
+ unsigned char *outbuf; /* output buffer (data to user) */
+ unsigned int outsize; /* .. and how much is used */
+ unsigned int outalloc; /* .. and how much is allocated */
+
+ int error;
+ int resp_v1; /* waiting to send IAC DO/DONT COMPRESS */
+ int resp_v2; /* waiting to send IAC DO COMPRESS2 */
+ int got_v2; /* responded to a IAC WILL COMPRESS2 already */
+
+ unsigned long comp;
+ unsigned long uncomp;
+};
+
+/* Initialise a new state object */
+mc_state *mudcompress_new(void)
+{
+ mc_state *state;
+
+ state = malloc(sizeof(*state));
+ state->stream = NULL; /* Not decompressing */
+ state->inalloc = 2048;
+ state->outalloc = 2048;
+ state->inbuf = malloc(state->inalloc);
+ state->outbuf = malloc(state->outalloc);
+ state->insize = 0;
+ state->outsize = 0;
+ state->error = 0;
+ state->comp = 0;
+ state->uncomp = 0;
+ state->resp_v1 = 0;
+ state->resp_v2 = 0;
+ state->got_v2 = 0;
+
+ return state;
+}
+
+/* Clean up a state object */
+void mudcompress_delete(mc_state *state)
+{
+ if (state->stream) {
+ inflateEnd(state->stream);
+ free(state->stream);
+ }
+
+ free(state->inbuf);
+ free(state->outbuf);
+ free(state);
+}
+
+/* zlib helpers */
+
+static void *zlib_alloc(void *opaque, unsigned int items, unsigned int size)
+{
+ return calloc(items, size);
+}
+
+static void zlib_free(void *opaque, void *address)
+{
+ free(address);
+}
+
+static void grow_inbuf(mc_state *state, int needed)
+{
+ int old = state->inalloc;
+
+ while (state->inalloc < state->insize + needed)
+ state->inalloc *= 2;
+
+ if (old != state->inalloc)
+ state->inbuf = realloc(state->inbuf, state->inalloc);
+}
+
+static void grow_outbuf(mc_state *state, int needed)
+{
+ int old = state->outalloc;
+
+ while (state->outalloc < state->outsize + needed)
+ state->outalloc *= 2;
+
+ if (old != state->outalloc)
+ state->outbuf = realloc(state->outbuf, state->outalloc);
+}
+
+static void decompress_inbuf(mc_state *state)
+{
+ int status;
+
+ /* We are now decompressing from inbuf to outbuf */
+
+ if (!state->insize)
+ return; /* nothing to decompress? */
+
+ state->stream->next_in = state->inbuf;
+ state->stream->next_out = state->outbuf + state->outsize;
+ state->stream->avail_in = state->insize;
+ state->stream->avail_out = state->outalloc - state->outsize;
+
+ status = inflate(state->stream, Z_PARTIAL_FLUSH);
+
+ if (status == Z_OK || status == Z_STREAM_END) {
+ /* Successful decompression */
+
+ /* Remove used data from inbuf */
+ state->comp += state->insize - state->stream->avail_in;
+ state->uncomp += state->stream->next_out - state->outbuf;
+
+ memmove(state->inbuf, state->stream->next_in, state->stream->avail_in);
+ state->insize = state->stream->avail_in;
+
+ /* Update outbuf pointers */
+ state->outsize = state->stream->next_out - state->outbuf;
+
+ /* Done */
+
+ if (status == Z_STREAM_END) {
+ /* Turn off compression too */
+
+ grow_outbuf(state, state->insize);
+
+ memcpy(state->outbuf + state->outsize, state->inbuf, state->insize);
+ state->outsize += state->insize;
+ state->insize = 0;
+
+ inflateEnd(state->stream);
+ free(state->stream);
+ state->stream = NULL;
+ }
+
+ return;
+ }
+
+ if (status == Z_BUF_ERROR) {
+ /* Full buffers? Maybe we need more output space.. */
+
+ if (state->outsize * 2 > state->outalloc) {
+ grow_outbuf(state, state->outalloc);
+ decompress_inbuf(state);
+ }
+
+ return;
+ }
+
+ /* Error */
+ state->error = 1;
+}
+
+/* We received some data */
+void mudcompress_receive(mc_state *state, const char *data, unsigned len)
+{
+ int i;
+
+ if (state->error)
+ return;
+
+ if (!state->stream) {
+ int residual = -1;
+ int clen;
+
+ /* Just copy to outbuf. Also copy any residual inbuf */
+
+ grow_outbuf(state, len + state->insize);
+ memcpy(state->outbuf + state->outsize, data, len);
+ state->outsize += len;
+ memcpy(state->outbuf + state->outsize, state->inbuf, state->insize);
+ state->outsize += state->insize;
+ state->insize = 0;
+
+ /* Check for Magic Marker. ugh this is messy */
+ for (i=0; i < state->outsize; i++) {
+ if (state->outbuf[i] == IAC) {
+ if (i + 1 < state->outsize && state->outbuf[i+1] == IAC) {
+ /* IAC IAC - ignore */
+ i++;
+ continue;
+ }
+
+ clen = (i + strlen(will_v1) < state->outsize) ? strlen(will_v1) : state->outsize - i;
+
+ if (!memcmp(&state->outbuf[i], will_v1, clen)) {
+ if (clen != strlen(will_v1)) {
+ /* Partial match. Save it. */
+ residual = i;
+ break;
+ }
+
+ /* If we got WILL COMPRESS2 then refuse COMPRESS, otherwise
+ * accept it
+ */
+
+ if (state->got_v2)
+ state->resp_v1 = -1;
+ else
+ state->resp_v1 = 1;
+
+ memmove(&state->outbuf[i],
+ &state->outbuf[i + strlen(will_v1)],
+ state->outsize - strlen(will_v1));
+ state->outsize -= strlen(will_v1);
+ i--;
+ continue;
+ }
+
+ if (!memcmp(&state->outbuf[i], will_v2, clen)) {
+ if (clen != strlen(will_v2)) {
+ /* Partial match. Save it. */
+ residual = i;
+ break;
+ }
+
+ state->resp_v2 = 1;
+ state->got_v2 = 1;
+
+ memmove(&state->outbuf[i],
+ &state->outbuf[i + strlen(will_v2)],
+ state->outsize - strlen(will_v2));
+ state->outsize -= strlen(will_v2);
+ i--;
+ continue;
+ }
+
+ clen = (i + strlen(on_v1) < state->outsize) ? strlen(on_v1) : state->outsize - i;
+
+ if ((!memcmp(&state->outbuf[i], on_v1, clen) && !state->got_v2) ||
+ (!memcmp(&state->outbuf[i], on_v2, clen) && state->got_v2)) {
+ if (clen != strlen(on_v1)) {
+ /* Partial match. Save it. */
+ residual = i;
+ break;
+ }
+
+ /* Switch to compression */
+ /* copy any compressible bits to our inbuf */
+
+ grow_inbuf(state, state->outsize - i - strlen(on_v1));
+
+ memcpy(state->inbuf,
+ state->outbuf + i + strlen(on_v1),
+ state->outsize - i - strlen(on_v1));
+
+ state->insize = state->outsize - i - strlen(on_v1);
+
+ /* clean up our output buffer */
+ state->outsize = i;
+
+ /* init stream */
+ state->stream = malloc(sizeof(z_stream));
+ state->stream->zalloc = zlib_alloc;
+ state->stream->zfree = zlib_free;
+ state->stream->opaque = NULL;
+
+ if (inflateInit(state->stream) != Z_OK) {
+ state->error = 1;
+ free(state->stream);
+ state->stream = NULL;
+ return;
+ }
+
+ /* Continue with decompression */
+ break;
+ }
+ }
+ }
+
+ if (!state->stream) { /* didn't start decompressing? */
+ /* We might have some residual, copy to inbuf for later checking */
+
+ if (residual != -1) {
+ grow_inbuf(state, state->outsize - residual);
+ memcpy(state->inbuf + state->insize, state->outbuf + residual, state->outsize - residual);
+ state->outsize = residual;
+ }
+
+ return;
+ }
+ } else {
+ /* New data to decompress. Copy to inbuf */
+ grow_inbuf(state, len);
+ memcpy(state->inbuf + state->insize, data, len);
+ state->insize += len;
+ }
+
+ decompress_inbuf(state);
+}
+
+/* How much data is available? */
+int mudcompress_pending(mc_state *state)
+{
+ return state->error ? 0 : state->outsize;
+}
+
+/* Was there an error? */
+int mudcompress_error(mc_state *state)
+{
+ return state->error;
+}
+
+/* Get some data */
+int mudcompress_get(mc_state *state, char *buf, int size)
+{
+ int copied;
+
+ if (state->error || !state->outsize)
+ return 0;
+
+ if (size > state->outsize)
+ copied = state->outsize;
+ else
+ copied = size;
+
+ memcpy(buf, state->outbuf, copied);
+ state->outsize -= copied;
+ if (state->outsize)
+ memmove(state->outbuf, state->outbuf + copied, state->outsize);
+
+ /* Do some more decompression */
+ decompress_inbuf(state);
+
+ return copied;
+}
+
+void mudcompress_stats(mc_state *state, unsigned long *comp, unsigned long *uncomp)
+{
+ *comp = state->comp;
+ *uncomp = state->uncomp;
+}
+
+const char *mudcompress_response(mc_state *state)
+{
+ if (state->resp_v1 == 1) {
+ state->resp_v1 = 0;
+ return do_v1;
+ }
+
+ if (state->resp_v1 == -1) {
+ state->resp_v1 = 0;
+ return dont_v1;
+ }
+
+ if (state->resp_v2) {
+ state->resp_v2 = 0;
+ return do_v2;
+ }
+
+ return NULL;
+}
+
+int mudcompress_compressing(mc_state *state)
+{
+ return (state->stream != NULL);
+}
+
+int mudcompress_v2(mc_state *state)
+{
+ return (state->stream != NULL && state->got_v2);
+}
+
+#endif /* MUDCOMPRESS */
diff --git a/net/tinyfugue/files/mccp.h b/net/tinyfugue/files/mccp.h
new file mode 100644
index 000000000000..d0086db09750
--- /dev/null
+++ b/net/tinyfugue/files/mccp.h
@@ -0,0 +1,141 @@
+/*
+ * Client decompression module for the mud client compression protocol.
+ * See http://homepages.ihug.co.nz/~icecube/compress/ for more details.
+ *
+ * mccpDecompress.h - header definitions. #include this in your client code.
+ *
+ * Oliver Jowett <icecube$ihug.co.nz>. Demangle address as needed.
+ *
+ * This code is placed in the public domain.
+ *
+ */
+
+/* Modified: 981203 */
+
+/*
+ *
+ * mc_state is an opaque type representing the current compression state of
+ * a connection. You should include a (mc_state *) in the information you
+ * store for a server connection.
+ *
+ * Initialization / cleanup:
+ *
+ * When a connection is initiated, call mudcompress_new, and store the
+ * resulting pointer in your server connection information. This pointer is
+ * used as a handle for all other functions. This does NOT begin compression
+ * - it just initialises various internal structures.
+ *
+ * When a connection is terminated, call mudcompress_delete with the handle
+ * to delete all memory allocated by the decompressor for the connection.
+ *
+ * Reading / writing:
+ *
+ * Reading from the server connection must go through the decompressor at
+ * all times. The decompressor handles both negotiation and decompression
+ * transparently - it receives input directly from the server, then provides
+ * the main client code with decompressed data, hiding all protocol details.
+ *
+ * When data is received from the mud server, call mudcompress_receive,
+ * passing it the handle for the connection, a pointer to the data read,
+ * and the length of data read. It is VITAL that ALL data read is passed
+ * to the decompressor - including data with embedded NULs!
+ *
+ * After mudcompress_receive has been called, call mudcompress_pending() to
+ * see if any decompressed data is available. It returns the number of
+ * bytes pending.
+ *
+ * If there is pending data waiting, call mudcompress_get to retrieve it.
+ * This fills up to "size" bytes in the provided buffer "buf", and returns
+ * the number of bytes copied. Your client can now process this data as if
+ * it had been directly read from the server.
+ *
+ * Be sure to check mudcompress_pending again after calling mudcompress_get!
+ * Removing some data from the decompress buffer may have allowed the
+ * decompressor to decompress some more data - in which case, you want to
+ * process it immediately, rather than waiting for another read from the
+ * mud server.
+ *
+ * Regularly call mudcompress_response. If non-NULL, you need to write the
+ * returned string to the mud server. This is needed when the decompressor
+ * is negotiating compression with the server. When called,
+ * mudcompress_response clears any pending string, so be sure to save its
+ * return value!
+ *
+ * Status information:
+ *
+ * mudcompress_error returns non-0 if there has been a (fatal) decompression
+ * error. In this case, all you can do is tell the user that something went
+ * wrong and close the connection.
+ *
+ * mudcompress_stats fills in the two (unsigned long *) values passed, with
+ * the number of compressed bytes read, and the number of bytes that they
+ * decompressed to.
+ *
+ * mudcompress_compressing returns non-0 if the connection is currently
+ * using compression.
+ *
+ */
+
+#ifndef MUDCOMPRESS_H
+#define MUDCOMPRESS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* Opaque handle for a decompressor. Details defined in Compress.c - you
+ * should never need to see them externally.
+ */
+ struct mc_state_s;
+ typedef struct mc_state_s mc_state;
+
+ /* Create a new decompressor. Return a handle to it.
+ */
+ mc_state *mudcompress_new(void);
+
+ /* Deallocate a decompressor and associated data. 'state' is invalid
+ * afterthis call.
+ */
+ void mudcompress_delete(mc_state *state);
+
+ /* Perform decompression and negotiation on some received data.
+ * 'data' is a pointer to the received data, 'len' is its length.
+ */
+ void mudcompress_receive(mc_state *state, const char *data, unsigned len);
+
+ /* Return the number of pending decompressed bytes that can currently
+ * be read by mudcompress_get
+ */
+ int mudcompress_pending(mc_state *state);
+
+ /* Return true (non-0) if this decompressor encountered a fatal error.
+ */
+ int mudcompress_error(mc_state *state);
+
+ /* Read decompressed data from the decompressor into 'buf', up to a
+ * maximum of 'size' bytes. Returns the number of bytes actually copied.
+ */
+ int mudcompress_get(mc_state *state, char *buf, int size);
+
+ /* Set *comp to the number of compressed bytes read, and *uncomp to the
+ * number of bytes they expanded to, for this decompressor.
+ */
+ void mudcompress_stats(mc_state *state, unsigned long *comp, unsigned long *uncomp);
+
+ /* Check for a negotiation response. If this returns NULL, no output is
+ * needed. If it returns non-NULL, it points to a NUL-terminated string
+ * that should be sent to the mud server. Calling this function clears
+ * the pending string (so be sure to save the result).
+ */
+ const char *mudcompress_response(mc_state *state);
+
+ /* Return true (non-0) if this decompressor has successfully negotiated
+ * compression and is currently performing decompression.
+ */
+ int mudcompress_compressing(mc_state *state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif