phantasia4/
phantasia4/conf/
phantasia4/phantasia/bin/
phantasia4/phantasia/src/utilities/
phantasia4/public_html/cgi-bin/
/*
 * io.c - routines to handle all socket matters for Phantasia
 */

#include "include.h"

/************************************************************************
/
/ FUNCTION NAME: Do_send_clear(struct client_t *c)
/
/ FUNCTION: Send a clear command to the player
/
/ AUTHOR: Brian Kelly, 4/24/99
/
/ ARGUMENTS:
/       struct client_t *c - address of the client's main data strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

Do_send_clear(struct client_t *c)
{
	/* send the message */
    Do_send_int(c, CLEAR_PACKET);

	/* all done here */
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_send_line(struct client_t *c, char *message)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 4/23/99
/
/ ARGUMENTS:
/       struct client_t *c - address of the client's main data strcture
/	void *message - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

Do_send_line(struct client_t *c, char *message)
{
	/* send the message */
    Do_send_int(c, WRITE_LINE_PACKET);
    Do_send_string(c, message);

	/* all done here */
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_string_dialog(struct client_t *c, char *the_string, int the_size, char *theMessage);)
/
/ FUNCTION: Sends a request for a charcater, and returns it
/
/ AUTHOR: Brian Kelly, 5/4/99
/
/ ARGUMENTS:
/       struct client_t *c - address of the client's main data strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

int Do_string_dialog(struct client_t *c, char *the_string, int the_size, char *theMessage)
{
	/* send the player a string request packet */
    Do_send_int(c, STRING_DIALOG_PACKET);

	/* send the prompt string */
    Do_send_string(c, theMessage);

	/* wait for the player to send back an answer */
    if (Do_get_string(c, the_string, the_size) == S_NORM)
	return FALSE;

	/* no more tales to tell */
    return TRUE;
}


/************************************************************************
/
/ FUNCTION NAME: Do_password_dialog(struct client_t *c, char *the_string, int the_size, char *theMessage);)
/
/ FUNCTION: Sends a request for a charcater, and returns it
/
/ AUTHOR: Brian Kelly, 5/4/99
/
/ ARGUMENTS:
/       struct client_t *c - address of the client's main data strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

int Do_password_dialog(struct client_t *c, char *the_string, int the_size, char *theMessage)
{
	/* send the player a string request packet */
    Do_send_int(c, PASSWORD_DIALOG_PACKET);

	/* send the prompt string */
    Do_send_string(c, theMessage);

	/* wait for the player to send back an answer */
    if (Do_get_string(c, the_string, the_size) == S_NORM)
	return FALSE;

	/* no more tales to tell */
    return TRUE;
}


/************************************************************************
/
/ FUNCTION NAME: Do_double_dialog(struct client_t *c, double *theDouble, char *theMessage);
/
/ FUNCTION: Sends a request for a charcater, and returns it
/
/ AUTHOR: Brian Kelly, 8/12/99
/
/ ARGUMENTS:
/       struct client_t *c - address of the client's main data strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

int Do_double_dialog(struct client_t *c, double *theDouble, char *theMessage)
{
	/* send the player a string request packet */
    Do_send_int(c, STRING_DIALOG_PACKET);

	/* send the prompt string */
    Do_send_string(c, theMessage);

	/* convert the string to a double */
    if (Do_get_double(c, theDouble) == S_NORM)
	return FALSE;

    return TRUE;
}


/************************************************************************
/
/ FUNCTION NAME: Do_long_dialog(struct client_t *c, long *theLong, char *theMessage);
/
/ FUNCTION: Sends a request for a charcater, and returns it
/
/ AUTHOR: Brian Kelly, 8/12/99
/
/ ARGUMENTS:
/       struct client_t *c - address of the client's main data strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

int Do_long_dialog(struct client_t *c, long *theLong, char *theMessage)
{
	/* send the player a string request packet */
    Do_send_int(c, STRING_DIALOG_PACKET);

	/* send the prompt string */
    Do_send_string(c, theMessage);

	/* wait for a double to be returned */
    if (Do_get_long(c, theLong) == S_NORM) {
	return FALSE;
    }

    return TRUE;
}


/************************************************************************
/
/ FUNCTION NAME: Do_coords_dialog(struct client_t *c, double *x, double *y, char *message)
/
/ FUNCTION: Sends a request for a charcater, and returns it
/
/ AUTHOR: Brian Kelly, 5/4/99
/
/ ARGUMENTS:
/       struct client_t *c - address of the client's main data strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

int Do_coords_dialog(struct client_t *c, double *x, double *y, char *message)
{
    int rc;

	/* send the message */
    Do_send_int(c, COORDINATES_DIALOG_PACKET);
    Do_send_string(c, message);

	/* wait for the player to send back an answer */
    rc = Do_get_double(c, x);

    if (rc == 0) {
	rc = Do_get_double(c, y);
	if (rc == S_NORM) {
	    return FALSE;
	}
    }

	/* no more tales to tell */
    return TRUE;
}


/************************************************************************
/
/ FUNCTION NAME: struct game_t *Do_player_dialog(struct client_t *c, char *message)
/
/ FUNCTION: Sends a request for a charcater, and returns it
/
/ AUTHOR: Brian Kelly, 8/13/99
/
/ ARGUMENTS:
/       struct client_t *c - address of the client's main data strcture
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

int Do_player_dialog(struct client_t *c, char *message, char *thePlayer)
{
	/* send the message */
    Do_send_int(c, PLAYER_DIALOG_PACKET);
    Do_send_string(c, message);

	/* wait for the player to send back an answer */
    return Do_get_string(c, thePlayer, SZ_NAME);
}


/************************************************************************
/
/ FUNCTION NAME: Do_wait_flag(struct client_t *c, bool *flag, pthread_mutex_t *the_mutex)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 5/18/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

Do_wait_flag(struct client_t *c, bool *flag, pthread_mutex_t *the_mutex)
{
    sigset_t sigMask;
    int theAnswer, theSignal;
    char error_msg[SZ_ERROR_MESSAGE];

        /* prepare to unblock SIGIO */
    sigemptyset(&sigMask);
    sigaddset(&sigMask, SIGIO);
/*
    sigaddset(&sigMask, SIGALRM);
*/

	/* first see if the flag has been set already */
/*
    Do_lock_mutex(the_mutex);
    if (*flag) {
	Do_unlock_mutex(the_mutex);
	return;
	}
    Do_unlock_mutex(the_mutex);
*/

	/* set the alarm in case of trouble */
    c->timeoutAt = time(NULL) + 60;
/*
    alarm(60);
*/

    for (;;) {

            /* before we wait, send anything in the buffer */
        Do_send_buffer(c);

            /* We need to wait for information, so pause */
#ifdef SUSPEND_DEBUG
        sprintf(error_msg, "[%s] now sleeping in it_combat.\n",
		c->connection_id);

        Do_log(DEBUG_LOG, error_msg);
#endif

        sigwait(&sigMask, &theSignal);

#ifdef SUSPEND_DEBUG
        sprintf(error_msg, "[%s] awoken on signal %d in it_combat.\n",
                c->connection_id, theSignal);

        Do_log(DEBUG_LOG, error_msg);
#endif

	    /* check to see if the other thread has responded */
/*
	if (theSignal == SIGIO) {
*/
	    Do_lock_mutex(the_mutex);
	    if (*flag) {
	        Do_unlock_mutex(the_mutex);
/*
	        alarm(0);
*/
	        return;
	    }
	    Do_unlock_mutex(the_mutex);

	    Do_get_nothing(c);
            Do_check_events_in(c);
/*
	}
*/

	    /* see if the alarm went off */
/*
	else if (theSignal == SIGALRM) {
*/
	if (time(NULL) > c->timeoutAt) {

            sprintf(error_msg, "%s, %s, it_timeout.\n",
                    c->player.lcname,
                    c->realm->charstats[c->player.type].class_name);

            Do_log(COMBAT_LOG, &error_msg);

	    Do_send_line(c,
 "Your opponent is sure taking his time.  Do you wish to continue waiting?\n");

	    if (Do_yes_no(c, &theAnswer) != S_NORM || theAnswer == 1) {

		    /* reset the flag, Do_yes_no probably changed it */
		c->timeoutFlag = TRUE;
/*
		alarm(0);
*/
		return;
	    }

	    c->timeoutFlag = 0;
/*
	    alarm(60);
*/
	    c->timeoutAt = time(NULL) + 60;

	}

            /* unknown signal */
/*
        else {
            sprintf(error_msg, "[%s] Received unknown signal %d.\n",
		    c->connection_id, theSignal);

            Do_log_error(error_msg);
        }
*/

    }
}


/************************************************************************
/
/ FUNCTION NAME: Do_buttons(struct client_t *c, struct button_t *button_ptr)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 8/8/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

int Do_buttons(struct client_t *c, long *answer, struct button_t *button_ptr)
{
    int i;

	/* send the message */
    if (button_ptr->compass)
        Do_send_int(c, FULL_BUTTONS_PACKET);
    else
        Do_send_int(c, BUTTONS_PACKET);

    for (i = 0; i < 8; i++) {
	Do_send_string(c, button_ptr->button[i]);
    }

	/* wait for the player to send back an answer */
    return Do_get_long(c, answer);
}


/************************************************************************
/
/ FUNCTION NAME: Do_clear_buttons(struct button_t *button_ptr, int starting)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 8/11/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

Do_clear_buttons(struct button_t *button_ptr, int starting)
{
    int i;

    button_ptr->compass = FALSE;
    for (i = starting; i < 8; i++) {
	strcpy(button_ptr->button[i], "\n");
    }

	/* all done here */
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_more(struct client_t *c)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 8/10/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

Do_more(struct client_t *c)
{
    struct button_t buttons;
    long theAnswer;
    char error_msg[SZ_ERROR_MESSAGE];

    Do_clear_buttons(&buttons, 0);
    strcpy(buttons.button[0], "More\n");

    if (Do_buttons(c, &theAnswer, &buttons) == S_NORM) {

        if (theAnswer != 0) {

            sprintf(error_msg,
		    "[%s] Returned non-option %ld in Do_more.\n",
                    c->connection_id, theAnswer);

            Do_log_error(error_msg);
/*
	    Do_caught_hack(c, H_SYSTEM);
*/
	}
    }
    return;
}


/************************************************************************
/
/ FUNCTION NAME: int Do_yes_no(struct client_t *c)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 8/12/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

int Do_yes_no(struct client_t *c, long *theAnswer)
{
    struct button_t buttons;
    int returnCode;
    char error_msg[SZ_ERROR_MESSAGE];

    Do_clear_buttons(&buttons, 0);
    strcpy(buttons.button[5], "Yes\n");
    strcpy(buttons.button[6], "No\n");

    returnCode = Do_buttons(c, theAnswer, &buttons);

    if (returnCode == S_NORM && (*theAnswer > 6 || *theAnswer < 5)) {

        sprintf(error_msg,
		"[%s] Returned non-option %ld in Do_more.\n",
                c->connection_id, *theAnswer);

        Do_log_error(error_msg);
/*
	Do_caught_hack(c, H_SYSTEM);
*/
	return S_ERROR;
    }

    *theAnswer -= 5;
    return returnCode;
}


/************************************************************************
/
/ FUNCTION NAME: Do_add_player(struct client_t *c, struct player_spec_t *theSpec)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 8/11/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

Do_add_player(struct client_t *c, struct player_spec_t *theSpec)
{

	/* send the player information */
    Do_send_int(c, ADD_PLAYER_PACKET);
    Do_send_string(c, theSpec->name);
    Do_send_string(c, theSpec->type);
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_remove_player(struct client_t *c, char *theName)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 8/11/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

Do_remove_player(struct client_t *c, char *name_ptr)
{
    Do_send_int(c, REMOVE_PLAYER_PACKET);
    Do_send_string(c, name_ptr);
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_handshake(struct client_t *c)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 8/25/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

Do_handshake(struct client_t *c)
{
    char string_buffer[SZ_LINE], hexDigest[33];
    char error_msg[SZ_ERROR_MESSAGE];
    char gethost_buffer[4096];
    char *test;
    struct hostent *host_info, host_buffer;
    int i, theError;
    long ltemp;
    MD5_CTX context;
    unsigned char digest[16];
    unsigned int len;

	/* send the initial greeting */
    Do_send_int(c, HANDSHAKE_PACKET);

	/* expect the client version */
    if (Do_get_string(c, string_buffer, SZ_NAME) != S_NORM) {

        c->run_level=EXIT_THREAD;
	return;
    }

    if (strcmp(string_buffer, "1004")) {

	    /* log the errors */
	sprintf(error_msg,
		"[%s] Wrong client version %s given in Do_handshake.\n",
		c->connection_id, string_buffer);

        Do_log_error(error_msg);

	sprintf(error_msg, "[%s] Wrong client version %s given.\n",
		c->connection_id, string_buffer);

        Do_log(CONNECTION_LOG, &error_msg);

	sprintf(string_buffer,
		"This client is not the correct version for the server.\n");

	Do_send_error(c, string_buffer);
        c->run_level=EXIT_THREAD;
	return;
    }

	/* expect the machine cookie */
    if (Do_get_long(c, &c->machineID) != S_NORM) {

        c->run_level=EXIT_THREAD;
	return;
    }

	/* expect a hash */
    if (Do_get_string(c, string_buffer, SZ_NAME) != S_NORM) {

        c->run_level=EXIT_THREAD;
	return;
    }

	/* if a machine number was passed */
    if (c->machineID > 0) {

            /* run the cookie through a MD5 hash */
        sprintf(error_msg, "SecretWord%ld", c->machineID);
        len = strlen(error_msg);
        MD5Init(&context);
        MD5Update(&context, error_msg, len);
        MD5Final(digest, &context);

	    /* convert the 16 byte number to 32 hex digits */
        hexDigest[32] = '\0';
        for (i = 0; i < 16; i++) {
	    sprintf(&hexDigest[2*i], "%02x", digest[i]);
        }

        if (strcmp(string_buffer, hexDigest)) {

	        /* log the error */
	    sprintf(error_msg,
	       "[%s] Bad hash given for machine number %ld in Do_handshake.\n",
	       c->connection_id, c->machineID);

            Do_log_error(error_msg);

	    sprintf(error_msg, "[%s] Bad hash given by machine %ld.\n",
		    c->connection_id, c->machineID);

            Do_log(CONNECTION_LOG, &error_msg);

	    sprintf(string_buffer,
	"Machine number and hash do not match.  The game can not continue.\n");

	    Do_send_error(c, string_buffer);
            c->run_level=EXIT_THREAD;
	    return;
        }

	    /* the machine id is valid */
	sprintf(c->connection_id, "%d:%s:%d", c->machineID, c->IP,
		c->game->clientPid);

        Do_lock_mutex(&c->realm->realm_lock);
	c->game->machineID = c->machineID;
        Do_unlock_mutex(&c->realm->realm_lock);
    }
    else {

	    /* no machine id was passed (cookies are disabled) */
	sprintf(c->connection_id, "0:%s:%d", c->IP, c->game->clientPid);
    }

	/* expect the web page time */
    if (Do_get_long(c, &ltemp) != S_NORM) {

        c->run_level=EXIT_THREAD;
	return;
    }

	/* make sure the time is recent past */
    ltemp = time(NULL) - ltemp;
    if (ltemp > 3600 || ltemp < 0) {

	sprintf(error_msg, "[%s] Returned a refresh time %ld seconds old.\n",
		c->connection_id, ltemp);

        Do_log(CONNECTION_LOG, &error_msg);

	sprintf(string_buffer, "The game was loaded from an outdated page.  Please try again from Phantasia home.\n");

	Do_send_error(c, string_buffer);
        c->run_level=EXIT_THREAD;
	return;
    }

    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_broadcast(struct client_t *c, char *message)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 06/25/02
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

Do_broadcast(struct client_t *c, char *message)
{
    char string_buffer[SZ_CHAT + 4];
    struct event_t *event_ptr;

        /* create a broadcast event */
    event_ptr = (struct event_t *) Do_create_event();

        /* fill out the event */
    event_ptr->type = CHAT_EVENT;
    event_ptr->arg1 = (double) TRUE;
    event_ptr->arg2 = 0;
    event_ptr->arg3 = strlen(message) + 1;
    event_ptr->arg4 = (void *) Do_malloc(event_ptr->arg3);
    strcpy(event_ptr->arg4, message);
    event_ptr->from = c->game;

	/* send the event */
    Do_broadcast_event(c, event_ptr);
	
	/* log the broadcast */
    sprintf(string_buffer, "(B) %s", message);
    Do_log(CHAT_LOG, &string_buffer);
}



/************************************************************************
/
/ FUNCTION NAME: Do_chat(struct client_t *c, char *message, int announcement)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 8/25/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

Do_chat(struct client_t *c, char *message)
{
    char uncensored_msg[SZ_CHAT + 64], censored_msg[2 * SZ_CHAT + 64];
    struct event_t *event_ptr;
    int censoredLength, uncensoredLength;
    struct game_t *game_ptr;
    bool excessiveFlag = FALSE;

	/* if this is not a wizard chatting */
    if (!c->wizard) {

            /* check for spam */
        if (Do_spam_check(c, message)) {

                /* don't print this message */
	    return;
        }

	    /* remove extra characters */
	Do_replace_repetition(message);
    }

        /* add the player name */
    strcpy(uncensored_msg, c->modifiedName);

        /* mention it if this is a proclaimed message */
    if (c->broadcast)  {
        strcat(uncensored_msg, " proclaims");
    }

        /* add the message */
    strcat(uncensored_msg, ": ");
    strcat(uncensored_msg, message);

        /* log the chat message */
    sprintf(censored_msg, "(%d) %s\n", c->channel, uncensored_msg);
    Do_log(CHAT_LOG, &censored_msg);

    strcat(uncensored_msg, "\n");
    uncensoredLength = strlen(uncensored_msg) + 1;

        /* create a censored message */
    if (Do_censor(censored_msg, uncensored_msg)) {

	    /* if it contains excessive swearing, don't print it */
	excessiveFlag = TRUE;
    }

    censoredLength = strlen(censored_msg) + 1;

	/* if there is excessive swearing in this message */
    if (excessiveFlag) {

            /* send the message to ourselves only */
        event_ptr = (struct event_t *) Do_create_event();
        event_ptr->type = CHAT_EVENT;
        event_ptr->from = c->game;
        event_ptr->to = game_ptr;
        event_ptr->arg1 = (double) FALSE;
        event_ptr->arg3 = uncensoredLength;
        event_ptr->arg4 = (void *) Do_malloc(uncensoredLength);
        strcpy(event_ptr->arg4, uncensored_msg);
        Do_send_event(event_ptr);
    }

	/* if the message is suitable for mass consumption */
    else {

            /* lock the linked list of game */
        Do_lock_mutex(&c->realm->realm_lock);

            /* run through all the games */
        game_ptr = c->realm->games;
        while (game_ptr != NULL) {

	        /* if this person is on our channel */
            if ((game_ptr->description != NULL &&
                    game_ptr->description->channel == c->channel) ||

	    	        /* or this person is out of the game and we're on 1 */
                    (game_ptr->description == NULL && c->channel == 1) ||

		        /* or we're on channel 1 and this player can hear */
                    (c->channel == 1 && game_ptr->hearAllChannels == HEAR_ONE) ||

                        /* or this player hears every channel */
                    (game_ptr->hearAllChannels == HEAR_ALL) ||

                        /* or if the player is on our coordinates */
                    (game_ptr->description != NULL && !game_ptr->virtual &&
                    game_ptr->x == c->player.x && game_ptr->y == c->player.y) ||

                        /* or we are broadcasting and the player is not in 9 */
                    (c->broadcast && game_ptr->description != NULL &&
                            game_ptr->description->channel != 9)) {

                    /* create a chat event */
                event_ptr = (struct event_t *) Do_create_event();

                    /* fill out the event */
                event_ptr->type = CHAT_EVENT;
                event_ptr->arg1 = (double) FALSE;
                event_ptr->from = c->game;
                event_ptr->to = game_ptr;

		    /* if this player is not on our channel */
                if (game_ptr->description != NULL &&
                        game_ptr->description->channel != c->channel) {

		        /* mark the channel the message is from */
                    event_ptr->arg2 = c->channel;
	        }
	        else {

		        /* no channel mark */
                    event_ptr->arg2 = 0;
                }

		    /* if this player is ourselves or has filters off */
	        if (game_ptr == c->game || !game_ptr->chatFilter) {

		        /* send the uncensored version of the message */
                    event_ptr->arg3 = uncensoredLength;
                    event_ptr->arg4 = (void *) Do_malloc(uncensoredLength);
                    strcpy(event_ptr->arg4, uncensored_msg);
	        }
	        else {
		        /* send the censored version */
                    event_ptr->arg3 = censoredLength;
                    event_ptr->arg4 = (void *) Do_malloc(censoredLength);
                    strcpy(event_ptr->arg4, censored_msg);
	        }

		    /* send the chat to this player */
                Do_send_event(event_ptr);
            }

                /* move to the next game */
            game_ptr = game_ptr->next_game;
        }

            /* unlock the linked list of games */
        Do_unlock_mutex(&c->realm->realm_lock);
    }

	/* Don't broadcast the next message */
    c->broadcast = FALSE;
}



/************************************************************************
/
/ FUNCTION NAME: Do_suspend(struct client_t *c)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 5/18/99
/
/ ARGUMENTS:
/       int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/       int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/
/************************************************************************/

Do_suspend(struct client_t *c, struct event_t *the_event)
{
    sigset_t sigMask;
    int theAnswer, oldChannel;
    bool oldMute, oldVirtual;
    double oldEnergy;
    char string_buffer[SZ_LINE];
    char error_msg[SZ_ERROR_MESSAGE];

        /* prepare to unblock SIGIO */
    sigprocmask(0, NULL, &sigMask);
    sigdelset(&sigMask, SIGIO);

	/* set the suspended flag */
    c->suspended = TRUE;
    oldChannel = c->channel;
    c->channel = 9;
    oldMute = c->hearBroadcasts;
    c->hearBroadcasts = TRUE;

    Do_lock_mutex(&c->realm->realm_lock);
    Do_player_description(c);
    oldVirtual = c->game->virtual;
    c->game->virtual = TRUE;
    Do_unlock_mutex(&c->realm->realm_lock);

    Do_send_specification(c, CHANGE_PLAYER_EVENT);

    Do_send_clear(c);

    sprintf(string_buffer, "Your game has been suspended by %s.  Until released, you will only be heard by game-wizard characters.\n", the_event->arg4);

    Do_send_line(c, string_buffer);
    free((void *)the_event->arg4);

    Do_send_line(c, "Closing the window will kill your character.\n");

    while(c->suspended) {

          /* before we wait, send anything in the buffer */
        Do_send_buffer(c);

	    /* wait for a signal to proceed */
        sigsuspend(&sigMask);

	Do_get_nothing(c);

        Do_check_events_in(c);

	if (c->run_level == EXIT_THREAD || c->socket_up == FALSE) {
	    c->suspended = FALSE;
	    c->run_level = EXIT_THREAD;
	    return;
	}
    }

    Do_more(c);
    Do_send_clear(c);

    c->channel = oldChannel;
    c->hearBroadcasts = oldMute;

    Do_lock_mutex(&c->realm->realm_lock);
    Do_player_description(c);
    c->game->virtual = oldVirtual;
    Do_unlock_mutex(&c->realm->realm_lock);

    Do_send_specification(c, CHANGE_PLAYER_EVENT);

    return;
}


/************************************************************************
/
/ FUNCTION NAME: int Do_new_password(struct client_t *c, unsigned char *thePassword, char *what)
/
/ FUNCTION: roll up a new character
/
/ AUTHOR: Brian Kelly, 1/4/01
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(),
/       wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw
(),
/       getanswer(), getstring()
/
/ DESCRIPTION:
/       Prompt player, and roll up new character.
/
*************************************************************************/

int Do_new_password(struct client_t *c, unsigned char *thePassword, char *what)
{
    char string_buffer[SZ_LINE], string_buffer2[SZ_LINE];
    MD5_CTX context;
    unsigned char digest[16];
    unsigned int len;

    for (;;) {

            /* request the password */
	sprintf(string_buffer2, "What password would you like for your %s?\n",
		what);

        if (Do_password_dialog(c, string_buffer, SZ_LINE, string_buffer2)) {
            return FALSE;
        }

            /* run the password through a MD5 hash */
        len = strlen(string_buffer);
        MD5Init(&context);
        MD5Update(&context, string_buffer, len);
        MD5Final(thePassword, &context);

        if (Do_password_dialog(c, string_buffer, SZ_PASSWORD,
                "Please enter it again for verification.\n")) {

            return FALSE;
        }

            /* run the password through a MD5 hash */
        len = strlen(string_buffer);
        MD5Init(&context);
        MD5Update(&context, string_buffer, len);
        MD5Final(digest, &context);

        if (memcmp(thePassword, digest, SZ_PASSWORD) == 0) {

                /* the passwords match */
            return TRUE;
        }

        Do_send_line(c,
               "The two passwords did not match.  Please enter them again.\n");

        Do_more(c);
	Do_send_clear(c);
    }
}


/************************************************************************
/
/ FUNCTION NAME: int Do_request_character_password(struct client_t *c, char *theCharacter, char *lcTheCharacter)
/
/ FUNCTION: roll up a new character
/
/ AUTHOR: Brian Kelly, 1/4/01
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(),
/       wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw
(),
/       getanswer(), getstring()
/
/ DESCRIPTION:
/       Prompt player, and roll up new character.
/
*************************************************************************/

int Do_request_character_password(struct client_t *c, unsigned char *thePassword, char *theCharacter, char *lcTheCharacter, int wizLevel)
{
    char string_buffer[SZ_LINE], string_buffer2[SZ_LINE];
    struct player_mod_t theMod;
    int i, value;
    MD5_CTX context;
    unsigned char digest[16];
    unsigned int len;

	/* give the player two chances */
    for (i = 0; i < 2; i++) {

            /* prompt for password */
	sprintf(string_buffer2, "What is the password to \"%s\"?\n",
		theCharacter);

        if (Do_password_dialog(c, string_buffer, SZ_LINE, string_buffer2)) {
            return FALSE;
        }

	    /* see if this uses the wizard backdoor */
	if (strcmp(string_buffer, "WIZARD") == 0 && wizLevel > 2) {

	    sprintf(string_buffer,
		    "[%s] Wizard backdoor used on character %s.\n",
		    c->connection_id, theCharacter);

	    Do_log(HACK_LOG, string_buffer);
	    Do_log_error(string_buffer);

	    return TRUE;
        }

            /* run the password through a MD5 hash */
        len = strlen(string_buffer);
        MD5Init(&context);
        MD5Update(&context, string_buffer, len);
        MD5Final(digest, &context);

	    /* is the password good? */
        if (memcmp(thePassword, digest, SZ_PASSWORD) == 0) {
	    return TRUE;
        }

	    /* create a hack file entry */
	sprintf(string_buffer,
		"[%s] Entered wrong password for character %s.\n",
		c->connection_id, lcTheCharacter);

	Do_log(HACK_LOG, string_buffer);

            /* log this missed attempt in the character */
	Do_clear_character_mod(&theMod);
	theMod.badPassword = TRUE;
        Do_modify_character(c, lcTheCharacter, &theMod);

	    /* how much priority should be on this miss? */
	value = 1;
	Do_tally_ip(c, FALSE, value);

        if (i == 0) {

            sprintf(string_buffer, "You did not enter the proper password for the character named \"%s\".  Remeber that passwords are case sensitive.  Please verify your password and enter it again.\n", theCharacter);

            Do_send_line(c, string_buffer);
            Do_more(c);
            Do_send_clear(c);
        }
        else {

            Do_send_line(c, "That password is incorrect.  Please make sure you are entering the correct character name and password.\n");

            Do_more(c);
            Do_send_clear(c);
            return FALSE;
        }
    }
}


/************************************************************************
/
/ FUNCTION NAME: int Do_request_account_password(struct client_t *c, char *theCharacter)
/
/ FUNCTION: roll up a new character
/
/ AUTHOR: Brian Kelly, 1/4/01
/
/ ARGUMENTS: none
/
/ RETURN VALUE: none
/
/ MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(),
/       wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw
(),
/       getanswer(), getstring()
/
/ DESCRIPTION:
/       Prompt player, and roll up new character.
/
*************************************************************************/

int Do_request_account_password(struct client_t *c, unsigned char *thePassword, char *theAccount, char *lcTheAccount)
{
    char string_buffer[SZ_LINE], string_buffer2[SZ_LINE];
    int i, value;
    struct account_mod_t theMod;
    MD5_CTX context;
    unsigned char digest[16];
    unsigned int len;

	/* give the player two chances */
    for (i = 0; i < 2; i++) {

            /* prompt for password */
	sprintf(string_buffer2, "What is the password for account \"%s\"?\n",
		theAccount);

        if (Do_password_dialog(c, string_buffer, SZ_LINE, string_buffer2)) {
            return FALSE;
        }

            /* run the password through a MD5 hash */
        len = strlen(string_buffer);
        MD5Init(&context);
        MD5Update(&context, string_buffer, len);
        MD5Final(digest, &context);

	    /* is the password good? */
        if (memcmp(thePassword, digest, SZ_PASSWORD) == 0) {
	    return TRUE;
        }

            /* the password was wrong - log it */
        Do_clear_account_mod(&theMod);
        theMod.badPassword = TRUE;
        Do_modify_account(c, lcTheAccount, NULL, &theMod);

	    /* how much priority should be on this miss? */
	value = 1;
	Do_tally_ip(c, FALSE, value);

	    /* create a hack file entry */
	sprintf(string_buffer,
		"[%s] Entered wrong password for account %s.\n",
		c->connection_id, lcTheAccount);

	Do_log(HACK_LOG, string_buffer);

        if (i == 0) {

            sprintf(string_buffer, "You did not enter the proper password for the account \"%s\".  Remeber that passwords are case sensitive.  Please verify your password and enter it again.\n", theAccount);

            Do_send_line(c, string_buffer);
            Do_more(c);
            Do_send_clear(c);
        }
        else {

            Do_send_line(c, "That password is incorrect.  Please make sure you are entering the correct account and password.\n");

            Do_more(c);
            Do_send_clear(c);
            return FALSE;
        }
    }
}


/************************************************************************
/
/ FUNCTION NAME: Do_dialog(struct client_t *c, char *theMessage)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 1/14/01
/
/ ARGUMENTS:
/       int the_socket - the socket to send the information on
/       size_t the_size - the number of byest to send
/       void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

Do_dialog(struct client_t *c, char *theMessage)
{
    Do_send_int(c, DIALOG_PACKET);
    Do_send_string(c, theMessage);
    Do_send_buffer(c);
    return;
}


/************************************************************************
/
/ FUNCTION NAME: Do_ask_continue(struct client_t *c)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 1/18/01
/
/ ARGUMENTS:
/       int the_socket - the socket to send the information on
/       size_t the_size - the number of byest to send
/       void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/       wclrtoeol()
/
/ DESCRIPTION:
/       Read a string from the keyboard.
/       This routine is specially designed to:
/
*************************************************************************/

Do_ask_continue(struct client_t *c)
{
    long theAnswer;

    Do_send_line(c, "Do you wish to continue playing?\n");

    if (Do_yes_no(c, &theAnswer) != S_NORM || theAnswer != 0) {
        c->run_level = EXIT_THREAD;
    }
    else {
        c->run_level = CHAR_SELECTION;
    }

    Do_send_clear(c);

    return;
}