/****************************************************************************
* [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);
}