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