SmaugWizard/Backup/
SmaugWizard/Backup/L/
SmaugWizard/Boards/
SmaugWizard/Building/
SmaugWizard/Corpses/
SmaugWizard/Councils/
SmaugWizard/Deity/
SmaugWizard/Gods/
SmaugWizard/MudProgs/
SmaugWizard/Player/L/
SmaugWizard/Src/
SmaugWizard/Src/res/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |				*
 * -----------------------------------------------------------|   \\._.//	*
 * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version)   |   (0...0)	*
 * -----------------------------------------------------------|    ).:.(	*
 * SMAUG (C) 1994, 1995, 1996 by Derek Snider                 |    {o o}	*
 * -----------------------------------------------------------|   / ' ' \	*
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |~'~.VxvxV.~'~*
 * Scryn, Swordbearer, Rennard, Tricops, and Gorog.           |				*
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe.    *
 ****************************************************************************/
// Descriptor.cpp

#include	"stdafx.h"
#include	"smaug.h"
#include	"SmaugSocket.h"
#include	"objects.h"
#include	"rooms.h"
#include	"sysdata.h"
#include	"SmaugWizDoc.h"
#include	"character.h"
#include	"descriptor.h"


// Transfer one line from input buffer to input line.
void CDescriptor::ReadFromBuffer ()
{
	int i, j, k;

	// Hold horses if pending command already.
	if (IsCommandReady ()) then return;

	// Look for at least one new line.
	for (i = 0; m_Inbuf [i] != '\n' && m_Inbuf [i] != '\r'; i++) {
		if (m_Inbuf [i] == '\0')
		return;
	}

	// Canonical input processing.
	for (i = 0, k = 0; m_Inbuf [i] != '\n' && m_Inbuf [i] != '\r'; i++) {
		if (k >= MAX_INPUT_LENGTH - 2) {
			WriteToDescriptor ("Line too long.\n\r", 0);

			// skip the rest of the line
			for (; m_Inbuf [i] != '\0'; i++) {
				if (m_Inbuf [i] == '\n' || m_Inbuf [i] == '\r') then break;
			}
			m_Inbuf [i]   = '\n';
			m_Inbuf [i+1] = '\0';
			break;
		}

		if (m_Inbuf [i] == '\b' && k > 0) then --k;
		else if (isascii (m_Inbuf [i]) && isprint (m_Inbuf [i])) then
			m_Incomm [k++] = m_Inbuf [i];
	}

	// Finish off the line.
	if (k == 0) then m_Incomm [k++] = ' ';
	m_Incomm [k] = '\0';

	// Deal with bozos with #repeat 1000 ...
	if (k > 1 || m_Incomm [0] == '!') {
		if (m_Incomm [0] != '!' && strcmp (m_Incomm, m_Inlast)) {
			m_Repeat = 0;
		} else {
			if (++m_Repeat >= 20) {
				sprintf (log_buf, "%s input spamming!",
					IsHost () ? m_pHost : "(unknown)");
				gpDoc->LogString (log_buf, LOG_PLAYER);
				WriteToDescriptor ("\n\r*** PUT A LID ON IT!!! ***\n\r", 0);
				strcpy (m_Incomm, "quit");
			}
		}
	}

	// Do '!' substitution.
	if (m_Incomm [0] == '!') then strcpy (m_Incomm, m_Inlast);
	else strcpy (m_Inlast, m_Incomm);

	// Shift the input buffer.
	while (m_Inbuf [i] == '\n' || m_Inbuf [i] == '\r')
		i++;
	for (j = 0; (m_Inbuf [j] = m_Inbuf [i+j]) != '\0'; j++) ;
}


// Append onto an output buffer.
void CDescriptor::WriteToBuffer (const char* txt, int length /* = 0 */)
{
    // @@@ ECS
    if (this == NULL) then return;
       
	// Find length in case caller didn't.
    if (length <= 0) then length = strlen (txt);

	// Initial \n\r if needed.
	if (m_Outtop == 0 && !m_bFcommand) {
		m_pOutbuf [0] = '\n';
		m_pOutbuf [1] = '\r';
		m_Outtop = 2;
	}

	// Expand the buffer as needed.
	while (m_Outtop + length >= m_Outsize) {
		char *outbuf;
		TRY outbuf = new char [2 * m_Outsize];
		CATCH (CMemoryException, ex) {
			// @@@ Deal with too large a memory increment...
			length = m_Outsize - m_Outtop - 1;
			break;
		}
		END_CATCH

		strncpy (outbuf, m_pOutbuf, m_Outtop);
		delete [] m_pOutbuf;
		m_pOutbuf = outbuf;
		m_Outsize *= 2;
	}

	// Copy.
	if (length > 0) {
		memcpy (m_pOutbuf + m_Outtop, txt, length);
		m_Outtop += length;
	}

	// Tell Winsock to wake us when the socket becomes ready
	if (! m_pSocket->SelectReadWrite ()) {
		if (m_pCharacter != NULL) then
			save_char_obj (m_pCharacter);
		m_Outtop = 0;
		RemoveCharacter (*this);
	}
}


// WriteToDescriptor bypasses the whole buffered output system.  Blech!
BOOL CDescriptor::WriteToDescriptor (char *txt, int length /* = 0 */)
{
	int		iStart;
	int		nWrite;
	int		nBlock;

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

	for (iStart = 0; iStart < length; iStart += nWrite) {
		nBlock = UMIN (length - iStart, 4096);
		// @@@ Should check WSAEWOULDBLOCK, and we don't want MessageBox...
		nWrite = m_pSocket->Send (txt + iStart, nBlock);
		if (nWrite == SOCKET_ERROR || nWrite != nBlock) then {
			gpDoc->LogString ("WriteToDescriptor:SOCKET_ERROR", LOG_COMM);
			return FALSE;
		}
	}

	// Tell Winsock to wake us when the socket becomes ready
	m_pSocket->SelectReadWrite ();

	return TRUE;
}


BOOL CDescriptor::ReadFromDescriptor ()
{
	int iStart;

	if (IsCommandReady ()) then {
		if (! m_pSocket->SelectReadWrite ()) {
			if (m_pCharacter) then save_char_obj (m_pCharacter);
			m_Outtop = 0;
			RemoveCharacter (*this);
		}
//		SelectReadWrite ();
		return TRUE;
	}

	// Check for overflow.
	iStart = strlen (m_Inbuf);
	if (iStart >= sizeof (m_Inbuf) - 10) {
		wsprintf (log_buf, "%s input overflow!",
			IsHost () ? m_pHost : "(unknown)");
		gpDoc->LogString (log_buf, LOG_COMM);
		m_pSocket->SelectReadWrite ();
//@@@	MessageBox (0, "input overflow!", "Serv", MB_ICONHAND|MB_OK);
		WriteToDescriptor ("\n\r*** PUT A LID ON IT!!! ***\n\r", 0);
		return FALSE;
	}

	// Snarf input.
	for (;;) {
		int nRead;
		nRead = m_pSocket->Receive (m_Inbuf + iStart,
			sizeof (m_Inbuf) - 10 - iStart);
		if (nRead > 0) {
			iStart += nRead;
			if (m_Inbuf [iStart-1] == '\n' || m_Inbuf [iStart-1] == '\r')
				then break;
		}
		else if (nRead == 0) {
//			gpDoc->LogString ("EOF encountered on read.");
			return FALSE;
		}
		else if (WSAGetLastError () == WSAEWOULDBLOCK) then break;
		else {
//			perror ("ReadFromDescriptor");
//			MessageBox (0, "ReadFromDescriptor", "Serv", MB_ICONHAND|MB_OK);
			gpDoc->LogString ("ReadFromDescriptor () got error", LOG_COMM);
			return FALSE;
		}
	}

	m_Inbuf [iStart] = '\0';
	return TRUE;
}


void CDescriptor::GetConnectionInfo ()
{
	CString		PAddr, Msg;
	UINT		PPort;

	if (m_pHost && m_pHost [0] == 0) {
		delete [] m_pHost;
		m_pHost = NULL;
	}

	if (! m_pSocket->GetPeerName (PAddr, PPort)) {
		Msg.Format ("SocketAccept:GetPeerName failure %d", GetLastError ());
		gpDoc->LogString (Msg, LOG_COMM);
		if (! IsHost ()) then m_pHost = str_dup ("@unknown");
	} else {
		Msg.Format ("Sock.sinaddr:  %s", (const char*) PAddr);
		if (! IsHost ()) {
			PAddr = '@' + PAddr;
			m_pHost = str_dup (PAddr);
		}
		gpDoc->LogString (Msg, LOG_COMM);
	}
}


void CDescriptor::Shutdown ()
{
	delete m_pSocket;
	delete [] m_pHost;
	delete [] m_pOutbuf;
	free (pagebuf);
	delete m_HostAndName;
	STRFREE (user);
}