/****************************************************************************
* ResortMUD Version 5.0 was mainly programmed by Ntanel, Garinan, Josh, *
* Badastaz, Digifuzz, Senir, Kratas, Scion, Shogar and Tagith. *
* ------------------------------------------------------------------------ *
* Copyright (C) 1996 - 2001 Haslage Net Electronics: MudWorld of Lorain, *
* Ohio. ALL RIGHTS RESERVED See /doc/RMLicense.txt for more details. *
****************************************************************************/
/*
* 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.
*/
#ifdef MCCP
#include <string.h>
#include <errno.h>
#include <arpa/telnet.h>
#include "mud.h"
char compress_start[] = { IAC, SB, TELOPT_COMPRESS, WILL, SE, '\0' };
bool write_to_descriptor( DESCRIPTOR_DATA * d, char *txt, int length );
/*
* Memory management - zlib uses these hooks to allocate and free the
* 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 )
{
DISPOSE( address );
}
/* Try to send any pending compressed-but-not-sent data in 'd' */
bool processCompressed( DESCRIPTOR_DATA * d )
{
int iStart = 0, nBlock, nWrite, len;
if( !d->out_compress )
return TRUE;
/*
* Try to write out some data..
*/
len = d->out_compress->next_out - d->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->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( d->out_compress_buf, d->out_compress_buf + iStart, len - iStart );
d->out_compress->next_out = d->out_compress_buf + len - iStart;
}
}
return TRUE;
}
/*
* Begin compressing data on 'd'
*/
bool compressStart( DESCRIPTOR_DATA * d )
{
z_stream *s;
if( d->out_compress )
return TRUE;
CREATE( s, z_stream, 1 );
CREATE( d->out_compress_buf, unsigned char, COMPRESS_BUF_SIZE );
s->next_in = NULL;
s->avail_in = 0;
s->next_out = d->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 )
{
DISPOSE( d->out_compress_buf );
DISPOSE( s );
return FALSE;
}
write_to_descriptor( d, compress_start, strlen( compress_start ) );
d->out_compress = s;
return TRUE;
}
/* Cleanly shut down compression on 'd' */
bool compressEnd( DESCRIPTOR_DATA * d )
{
unsigned char dummy[1];
if( !d->out_compress )
return TRUE;
d->out_compress->avail_in = 0;
d->out_compress->next_in = dummy;
if( deflate( d->out_compress, Z_FINISH ) != Z_STREAM_END )
return FALSE;
if( !processCompressed( d ) ) /* try to send any residual data */
return FALSE;
deflateEnd( d->out_compress );
DISPOSE( d->out_compress_buf );
DISPOSE( d->out_compress );
return TRUE;
}
/* write compressed data to user */
bool writeCompressed( DESCRIPTOR_DATA * d, char *txt, int length )
{
z_stream *s = d->out_compress;
s->next_in = ( unsigned char * )txt;
if( length <= 0 )
length = strlen( txt );
s->avail_in = length;
while( s->avail_in )
{
s->avail_out = COMPRESS_BUF_SIZE - ( s->next_out - d->out_compress_buf );
if( s->avail_out )
{
int status = deflate( s, Z_SYNC_FLUSH );
if( status != Z_OK )
return FALSE;
}
if( !processCompressed( d ) )
return FALSE;
/*
len = d->out_compress->next_out - d->out_compress_buf;
if (len > 0)
{
for (iStart = 0; iStart < len; iStart += nWrite)
{
nBlock = UMIN (len - iStart, 4096);
if ((nWrite = write(d->descriptor, d->out_compress_buf + iStart, nBlock)) < 0)
{
perror( "Write_to_descriptor: compressed" );
return FALSE;
}
if (!nWrite)
break;
}
if (!iStart)
break;
if (iStart < len)
memmove(d->out_compress_buf, d->out_compress_buf+iStart, len - iStart);
d->out_compress->next_out = d->out_compress_buf + len - iStart;
} */
}
return TRUE;
}
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 );
}
}
#endif