/*****************************************************************************
* DikuMUD (C) 1990, 1991 by: *
* Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen, *
* and Katja Nyboe. *
*---------------------------------------------------------------------------*
* MERC 2.1 (C) 1992, 1993 by: *
* Michael Chastain, Michael Quan, and Mitchell Tse. *
*---------------------------------------------------------------------------*
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider. *
* Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
* gorog, Grishnakh, Nivek, Tricops, and Fireblade. *
*---------------------------------------------------------------------------*
* SMAUG 1.7 FUSS by: Samson and others of the SMAUG community. *
* Their contributions are greatly appreciated. *
*---------------------------------------------------------------------------*
* LoP (C) 2006, 2007, 2008 by: the LoP team. *
*---------------------------------------------------------------------------*
* Client Compression Module *
*****************************************************************************/
/*
* mccp.c - support functions for mccp (the Mud Client Compression Protocol)
*
* see http://mccp.afkmud.com
*
* Copyright (c) 1999, Oliver Jowett <oliver@randomly.org>.
*
* This code may be freely distributed and used if this copyright notice is
* retained intact.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#ifndef WIN32
#include <arpa/telnet.h>
#else
#define TELOPT_ECHO '\x01'
#define GA '\xF9'
#define SB '\xFA'
#define SE '\xF0'
#define WILL '\xFB'
#define WONT '\xFC'
#define DO '\xFD'
#define DONT '\xFE'
#define IAC '\xFF'
#define ENOSR 63
#endif
#include "h/mud.h"
#include "h/mccp.h"
#if defined(__OpenBSD__) || defined(__FreeBSD__)
#define ENOSR 63
#endif
int mccpusers;
char will_compress2_str[] = { IAC, WILL, TELOPT_COMPRESS2, '\0' };
char start_compress2_str[] = { IAC, SB, TELOPT_COMPRESS2, IAC, SE, '\0' };
bool write_to_descriptor( DESCRIPTOR_DATA *d, char *txt, int length );
bool process_compressed( DESCRIPTOR_DATA *d )
{
int iStart = 0, nBlock, nWrite, len;
if( !d->mccp->out_compress )
return true;
/* Try to write out some data.. */
len = d->mccp->out_compress->next_out - d->mccp->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( d->descriptor, d->mccp->out_compress_buf + iStart, nBlock ) ) < 0 )
{
if( errno == EAGAIN || errno == ENOSR )
break;
return false;
}
if( !nWrite )
break;
}
if( iStart )
{
/* We wrote "iStart" bytes */
if( iStart < len )
memmove( d->mccp->out_compress_buf, d->mccp->out_compress_buf + iStart, len - iStart );
d->mccp->out_compress->next_out = d->mccp->out_compress_buf + len - iStart;
}
}
return true;
}
bool compressStart( DESCRIPTOR_DATA *d )
{
z_stream *s;
if( d->mccp->out_compress )
return true;
CREATE( s, z_stream, 1 );
CREATE( d->mccp->out_compress_buf, unsigned char, COMPRESS_BUF_SIZE );
s->next_in = NULL;
s->avail_in = 0;
s->next_out = d->mccp->out_compress_buf;
s->avail_out = COMPRESS_BUF_SIZE;
s->zalloc = Z_NULL;
s->zfree = Z_NULL;
s->opaque = NULL;
if( deflateInit( s, 9 ) != Z_OK )
{
DISPOSE( d->mccp->out_compress_buf );
DISPOSE( s );
return false;
}
write_to_descriptor( d, start_compress2_str, 0 );
d->can_compress = true;
d->mccp->out_compress = s;
mccpusers++;
return true;
}
bool compressEnd( DESCRIPTOR_DATA *d )
{
unsigned char dummy[1];
if( !d->mccp->out_compress )
return true;
d->mccp->out_compress->avail_in = 0;
d->mccp->out_compress->next_in = dummy;
if( deflate( d->mccp->out_compress, Z_FINISH ) != Z_STREAM_END )
return false;
if( !process_compressed( d ) ) /* try to send any residual data */
return false;
deflateEnd( d->mccp->out_compress );
DISPOSE( d->mccp->out_compress_buf );
DISPOSE( d->mccp->out_compress );
mccpusers--;
return true;
}
CMDF( do_compress )
{
if( !ch->desc )
{
send_to_char( "What descriptor?!\n", ch );
return;
}
if( !ch->desc->mccp->out_compress )
{
if( !compressStart( ch->desc ) )
send_to_char( "&RCompression failed to start.\r\n", ch );
else
send_to_char( "&GOk, compression enabled.\r\n", ch );
}
else
{
compressEnd( ch->desc );
ch->desc->can_compress = false;
send_to_char( "&ROk, compression disabled.\r\n", ch );
}
}