player/a/
player/b/
player/c/
player/d/
player/e/
player/f/
player/g/
player/i/
player/j/
player/k/
player/m/
player/n/
player/r/
player/s/
player/v/
player/w/
player/x/
player/z/
player_fst/e/
player_fst/f/
player_fst/h/
player_fst/i/
player_fst/j/
player_fst/n/
player_fst/o/
player_fst/p/
player_fst/player/a/
player_fst/player/b/
player_fst/player/c/
player_fst/player/d/
player_fst/player/e/
player_fst/player/f/
player_fst/player/g/
player_fst/player/j/
player_fst/player/k/
player_fst/player/m/
player_fst/player/n/
player_fst/player/r/
player_fst/player/s/
player_fst/player/v/
player_fst/player/w/
player_fst/player/x/
player_fst/player/z/
player_fst/u/
player_fst/v/
player_fst/w/
player_fst/x/
/*~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 ~  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        ~
 ~  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   ~
 ~                                                                         ~
 ~  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          ~
 ~  Chastain, Michael Quan, and Mitchell Tse.                              ~
 ~                                                                         ~
 ~  Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley              ~
 ~  ACK!MUD is modified Merc2.0/2.1/2.2 code (c)Stephen Zepp 1998 Ver: 4.3 ~
 ~                                                                         ~
 ~  In order to use any part of this  PA  Diku Mud, you must comply with   ~
 ~  both the original Diku license in 'license.doc' as well the Merc       ~
 ~  license in 'license.txt', and the Ack!Mud license in 'ack_license.txt'.~
 ~  In particular, you may not remove any of these copyright notices.      ~
 ~                                                                         ~
 ~           _______      _____                                            ~
 ~          /  __  /\    / ___ \       222222        PA_MUD by Amnon Kruvi ~
 ~         /______/ /   / /___\ \            2       PA_MUD is modified    ~
 ~        / _______/   / _______ \           2       Ack!Mud, v4.3         ~
 ~       /_/          /_/       \_\        2                               ~
 ~                                      2                                  ~
 ~                                     2222222                             ~
 ~                                                                         ~
 ~                                                                         ~
 ~   Years of work have been invested to create DIKU, Merc, Ack and PA.    ~
 ~   Please show your respect by following the licenses, and issuing       ~
 ~   credits where due.                                                    ~
 ~                                                                         ~
 ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-*/

#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 <arpa/telnet.h>
#include "ack.h"
#include "globals.h"
   
char    compress_start  [] = { IAC, SB, TELOPT_COMPRESS, WILL, SE, '\0' };
char    compress2_start  [] = { IAC, SB, TELOPT_COMPRESS2, WILL, SE, '\0' };
char    compress_on_str   [] = { IAC, WILL, TELOPT_COMPRESS, '\0' };
char    compress2_on_str   [] = { IAC, WILL, TELOPT_COMPRESS2, '\0' };
  
bool processCompressed(DESCRIPTOR_DATA *desc);
bool    write_to_descriptor     args( ( DESCRIPTOR_DATA *d, char *txt, int length ) );

void *zlib_alloc(void *opaque, unsigned int items, unsigned int size)
{
    return calloc(items, size);
}

void zlib_free(void *opaque, void *address)
{
    free(address);
}

bool process_compressed(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;
            }

            if (!nWrite)
                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;
}


bool write_compressed( DESCRIPTOR_DATA * d, char *txt, int length )
{
    int     iStart = 0;
    int     nWrite = 0;
    int     nBlock;
    int     len;

    if (length <= 0)
        length = strlen(txt);

    if (d && d->out_compress)
    {
        d->out_compress->next_in = (unsigned char *)txt;
        d->out_compress->avail_in = length;

        while (d->out_compress->avail_in)
        {
            d->out_compress->avail_out = COMPRESS_BUF_SIZE - (d->out_compress->next_out - d->out_compress_buf);

            if (d->out_compress->avail_out)
            {
                int status = deflate(d->out_compress, Z_SYNC_FLUSH);

                if (status != Z_OK)
                    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;
    }

    for (iStart = 0; iStart < length; iStart += nWrite)
    {
        nBlock = UMIN (length - iStart, 4096);
        if ((nWrite = write(d->descriptor, txt + iStart, nBlock)) < 0)
        {
            perror( "Write_to_descriptor" );
            return FALSE;
        }
    }

    return TRUE;
}

char enable_compress[] =
{
    IAC, SB, TELOPT_COMPRESS, WILL, SE, 0
};
char enable_compress2[] =
{
    IAC, SB, TELOPT_COMPRESS2, IAC, SE, 0
};

bool compressStart(DESCRIPTOR_DATA *d, unsigned char telopt)
{
    z_stream *s;

    if (d->out_compress)
        return TRUE;

//    bug("Starting compression for descriptor %d", d->descriptor);

    s = (z_stream *)malloc(sizeof(*s));
    d->out_compress_buf = (unsigned char *)malloc(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)
    {
        free(d->out_compress_buf);
        free(s);
        return FALSE;
    }

    if (telopt == TELOPT_COMPRESS)
        write_to_descriptor(d, enable_compress, 0);
    else if (telopt == TELOPT_COMPRESS2)
        write_to_descriptor(d, enable_compress2, 0);
//    else
//        bug("compressStart: bad TELOPT passed");

    d->compressing = telopt;
    d->out_compress = s;

/*    if ( d->character )
    {
	if ( telopt == 85 && !IS_SET(d->character->config,CONFIG_COMPRESS))
	        SET_BIT(d->character->config,CONFIG_COMPRESS);
	if ( telopt == 86 && !IS_SET(d->character->config,CONFIG_COMPRESS2))
	        SET_BIT(d->character->config,CONFIG_COMPRESS2);
    }*/
    return TRUE;
}

bool compressEnd(DESCRIPTOR_DATA *d,unsigned char type)
{
    unsigned char dummy[1];
    unsigned char telopt;

    if (!d->out_compress)
        return TRUE;
    if (d->compressing != type)
	return FALSE;

//    bug("Stopping compression for descriptor %d", d->descriptor);

    d->out_compress->avail_in = 0;
    d->out_compress->next_in = dummy;
    telopt = d->compressing;

    if (deflate(d->out_compress, Z_FINISH) != Z_STREAM_END)
        return FALSE;

    if ( !d )
	return FALSE;

    if (!process_compressed(d)) 
        return FALSE;

    deflateEnd(d->out_compress);
    free(d->out_compress_buf);
    free(d->out_compress);
    d->compressing = 0;
    d->out_compress_buf = NULL;
    d->out_compress = NULL;

/*    if ( d->character )
    {
	if ( telopt == 85 && IS_SET(d->character->config,CONFIG_COMPRESS))
	        REMOVE_BIT(d->character->config,CONFIG_COMPRESS);
	if ( telopt == 86 && IS_SET(d->character->config,CONFIG_COMPRESS2))
	        REMOVE_BIT(d->character->config,CONFIG_COMPRESS2);
    }*/
    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 ( str_cmp(argument,"2") )
        	write_to_buffer( ch->desc, compress_on_str, 0 );
	if ( str_cmp(argument,"1") )
        	write_to_buffer( ch->desc, compress2_on_str, 0 );
        send_to_char("Ok, compression enabled.\n", ch);
    } else {
        if (!compressEnd(ch->desc,ch->desc->compressing)) {
            send_to_char("Failed.\n", ch);
            return;
        }
 
        send_to_char("Ok, compression disabled.\n", ch);
    }

	return;
}