rm6/
rm6/clans/
rm6/councils/
rm6/deity/
rm6/doc/mudprogs/
rm6/exchange/
rm6/gods/
rm6/homes/
rm6/nations/
rm6/player/
rm6/player/a/
rm6/src/RCS/
rm6/src/dmalloc/
rm6/src/dmalloc/bin/
rm6/src/dmalloc/include/
rm6/src/dmalloc/lib/
rm6/src/scripts/
rm6/src/utils/
/****************************************************************************
 * 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