Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / base / applications / network / telnet / src / tncon.cpp
diff --git a/base/applications/network/telnet/src/tncon.cpp b/base/applications/network/telnet/src/tncon.cpp
new file mode 100644 (file)
index 0000000..6681317
--- /dev/null
@@ -0,0 +1,366 @@
+///////////////////////////////////////////////////////////////////////////////
+//Telnet Win32 : an ANSI telnet client.
+//Copyright (C) 1998-2000 Paul Brannan
+//Copyright (C) 1998 I.Ioannou
+//Copyright (C) 1997 Brad Johnson
+//
+//This program is free software; you can redistribute it and/or
+//modify it under the terms of the GNU General Public License
+//as published by the Free Software Foundation; either version 2
+//of the License, or (at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//GNU General Public License for more details.
+//
+//You should have received a copy of the GNU General Public License
+//along with this program; if not, write to the Free Software
+//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+//I.Ioannou
+//roryt@hol.gr
+//
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Module:             tncon.cpp
+//
+// Contents:   telnet console processing
+//
+// Product:            telnet
+//
+// Revisions: August 30, 1998 Paul Brannan <pbranna@clemson.edu>
+//            July 29, 1998 Paul Brannan
+//            June 15, 1998 Paul Brannan
+//            May 16, 1998 Paul Brannan
+//            5.April.1997 jbj@nounname.com
+//            9.Dec.1996 jbj@nounname.com
+//            Version 2.0
+//
+//            02.Apr.1995      igor.milavec@uni-lj.si
+//                                       Original code
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "precomp.h"
+
+#define KEYEVENT InputRecord[i].Event.KeyEvent
+
+// Paul Brannan 6/25/98
+// #ifdef __MINGW32__
+// #define KEYEVENT_CHAR KEYEVENT.AsciiChar
+// #else
+#define KEYEVENT_CHAR KEYEVENT.uChar.AsciiChar
+// #endif
+
+#define KEYEVENT_PCHAR &KEYEVENT_CHAR
+
+// This is for local echo (Paul Brannan 5/16/98)
+inline void DoEcho(const char *p, int l, TConsole &Console,
+                                  TNetwork &Network, NetParams *pParams) {
+       // Pause the console (Paul Brannan 8/24/98)
+       if(Network.get_local_echo()) {
+               ResetEvent(pParams->hUnPause);
+               SetEvent(pParams->hPause);
+               while (!*pParams->bNetPaused); // Pause
+
+               Console.WriteCtrlString(p, l);
+
+               SetEvent(pParams->hUnPause); // Unpause
+       }
+}
+
+// This is for line mode (Paul Brannan 12/31/98)
+static char buffer[1024];
+static unsigned int bufptr = 0;
+
+// Line mode -- currently uses sga/echo to determine when to enter line mode
+// (as in RFC 858), but correct behaviour is as described in RFC 1184.
+// (Paul Brannan 12/31/98)
+// FIX ME!!  What to do with unflushed data when we change from line mode
+// to character mode?
+inline bool DoLineModeSpecial(char keychar, TConsole &Console, TNetwork &Network,
+                                          NetParams *pParams) {
+       if(keychar == VK_BACK) {
+               if(bufptr) bufptr--;
+               DoEcho("\b \b", 3, Console, Network, pParams);
+               return true;
+       } else if(keychar == VK_RETURN) {
+               Network.WriteString(buffer, bufptr);
+               Network.WriteString("\012", 1);
+               DoEcho("\r\n", 2, Console, Network, pParams);
+               bufptr = 0;
+               return true;
+       }
+       return false;
+}
+
+inline void DoLineMode(const char *p, int p_len, TConsole &Console,
+                                          TNetwork &Network) {
+       if(Network.get_line_mode()) {
+               if(bufptr < sizeof(buffer) + p_len - 1) {
+                       memcpy(buffer + bufptr, p, p_len);
+                       bufptr += p_len;
+               } else {
+                       Console.Beep();
+               }
+       } else {
+               Network.WriteString(p, p_len);
+       }
+}
+
+// Paul Brannan 5/27/98
+// Fixed this code for use with appliation cursor keys
+// This should probably be optimized; it's pretty ugly as it is
+// Rewrite #1: now uses ClosestStateKey (Paul Brannan 12/9/98)
+const char *ClosestStateKey(WORD keyCode, DWORD keyState,
+                                                       KeyTranslator &KeyTrans) {
+       char const *p;
+
+       if((p = KeyTrans.TranslateKey(keyCode, keyState))) return p;
+
+       // Check numlock and scroll lock (Paul Brannan 9/23/98)
+       if((p = KeyTrans.TranslateKey(keyCode, keyState & ~NUMLOCK_ON))) return p;
+       if((p = KeyTrans.TranslateKey(keyCode, keyState & ~ENHANCED_KEY
+               & ~NUMLOCK_ON))) return p;
+       if((p = KeyTrans.TranslateKey(keyCode, keyState & ~SCROLLLOCK_ON))) return p;
+       if((p = KeyTrans.TranslateKey(keyCode, keyState & ~ENHANCED_KEY
+               & ~SCROLLLOCK_ON))) return p;
+
+       //       John Ioannou (roryt@hol.gr)
+       //   Athens 31/03/97 00:25am GMT+2
+       //   fix for win95 CAPSLOCK bug
+       //   first check if the user has keys with capslock and then we filter it
+       if((p = KeyTrans.TranslateKey(keyCode, keyState & ~ENHANCED_KEY))) return p;
+       if((p = KeyTrans.TranslateKey(keyCode, keyState & ~CAPSLOCK_ON))) return p;
+       if((p = KeyTrans.TranslateKey(keyCode, keyState & ~ENHANCED_KEY
+               & ~CAPSLOCK_ON))) return p;
+
+       return 0; // we couldn't find a suitable key translation
+}
+
+const char *FindClosestKey(WORD keyCode, DWORD keyState,
+                                                  KeyTranslator &KeyTrans) {
+       char const *p;
+
+       // Paul Brannan 7/20/98
+       if(ini.get_alt_erase()) {
+               if(keyCode == VK_BACK) {
+                       keyCode = VK_DELETE;
+                       keyState |= ENHANCED_KEY;
+               } else if(keyCode == VK_DELETE && (keyState & ENHANCED_KEY)) {
+                       keyCode = VK_BACK;
+                       keyState &= ~ENHANCED_KEY;
+               }
+       }
+
+       DWORD ext_mode = KeyTrans.get_ext_mode();
+       if(ext_mode) {
+               // Not as fast as an unrolled loop, but certainly more
+               // compact (Paul Brannan 12/9/98)
+               for(DWORD j = ext_mode; j >= APP_KEY; j -= APP_KEY) {
+                       if((j | ext_mode) == ext_mode) {
+                               if((p = ClosestStateKey(keyCode, keyState | j,
+                                       KeyTrans))) return p;
+                       }
+               }
+       }
+       return ClosestStateKey(keyCode, keyState, KeyTrans);
+}
+
+// Paul Brannan Feb. 22, 1999
+int do_op(tn_ops op, TNetwork &Network, Tnclip &Clipboard) {
+       switch(op) {
+       case TN_ESCAPE:
+               return TNPROMPT;
+       case TN_SCROLLBACK:
+               return TNSCROLLBACK;
+       case TN_DIAL:
+               return TNSPAWN;
+       case TN_PASTE:
+               if(ini.get_keyboard_paste()) Clipboard.Paste();
+               else return 0;
+               break;
+       case TN_NULL:
+               Network.WriteString("", 1);
+               return 0;
+       case TN_CR:
+               Network.WriteString("\r", 2); // CR must be followed by NUL
+               return 0;
+       case TN_CRLF:
+               Network.WriteString("\r\n", 2);
+               return 0;
+       }
+       return 0;
+}
+
+int telProcessConsole(NetParams *pParams, KeyTranslator &KeyTrans,
+                                         TConsole &Console, TNetwork &Network, TMouse &Mouse,
+                                         Tnclip &Clipboard, HANDLE hThread)
+{
+       KeyDefType_const keydef;
+       const char *p;
+       int p_len;
+       unsigned int i;
+       int opval;
+       HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
+
+       SetConsoleMode(hConsole, ini.get_enable_mouse() ? ENABLE_MOUSE_INPUT : 0);
+
+       const DWORD nHandle = 2;
+       HANDLE hHandle[nHandle] = {hConsole, pParams->hExit};
+
+       for (;;) {
+               DWORD dwInput;
+               switch (WaitForMultipleObjects(nHandle, hHandle, FALSE, INFINITE)) {
+        case WAIT_OBJECT_0: {
+
+                       // Paul Brannan 7/29/98
+                       if(ini.get_input_redir()) {
+                               char InputBuffer[10];
+
+                               // Correction from Joe Manns <joe.manns@ardenenginneers.com>
+                               // to fix race conditions (4/13/99)
+                               int bResult;
+                               bResult = ReadFile(hConsole, InputBuffer, 10, &dwInput, 0);
+                               if(bResult && dwInput == 0) return TNNOCON;
+
+                               // no key translation for redirected input
+                               Network.WriteString(InputBuffer, dwInput);
+                               break;
+                       }
+
+                       INPUT_RECORD InputRecord[11];
+                       if (!ReadConsoleInput(hConsole, &InputRecord[0], 10, &dwInput))
+                               return TNPROMPT;
+
+                       for (i = 0; (unsigned)i < dwInput; i++){
+                               switch (InputRecord[i].EventType) {
+                               case KEY_EVENT:{
+                                       if (KEYEVENT.bKeyDown) {
+
+                                               WORD  keyCode  = KEYEVENT.wVirtualKeyCode;
+                                               DWORD keyState = KEYEVENT.dwControlKeyState;
+
+                                               // Paul Brannan 5/27/98
+                                               // Moved the code that was here to FindClosestKey()
+                                               keydef.szKeyDef = FindClosestKey(keyCode,
+                                                       keyState, KeyTrans);
+
+                                               if(keydef.szKeyDef) {
+                                                       if(!keydef.op->sendstr)
+                                                               if((opval = do_op(keydef.op->the_op, Network,
+                                                                       Clipboard)) != 0)
+                                                                       return opval;
+                                               }
+
+                                               if(Network.get_line_mode()) {
+                                                       if(DoLineModeSpecial(KEYEVENT_CHAR, Console, Network, pParams))
+                                                               continue;
+                                               }
+
+                                               p = keydef.szKeyDef;
+                                               if (p == NULL) { // if we don't have a translator
+                                                       if(!KEYEVENT_CHAR) continue;
+                                                       p_len = 1;
+                                                       p = KEYEVENT_PCHAR;
+                                               } else {
+                                                       p_len = strlen(p);
+                                               }
+
+                                               // Local echo (Paul Brannan 5/16/98)
+                                               DoEcho(p, p_len, Console, Network, pParams);
+                                               // Line mode (Paul Brannan 12/31/98)
+                                               DoLineMode(p, p_len, Console, Network);
+                                       }
+                                                          }
+                                       break;
+
+                               case MOUSE_EVENT:
+                                       if(!InputRecord[i].Event.MouseEvent.dwEventFlags) {
+                                               ResetEvent(pParams->hUnPause);
+                                               SetEvent(pParams->hPause);
+                                               while (!*pParams->bNetPaused);  // thread paused
+                                               // SuspendThread(hThread);
+
+                                               // Put the mouse's X and Y coords back into the
+                                               // input buffer
+                                               DWORD Result;
+                                               WriteConsoleInput(hConsole, &InputRecord[i], 1,
+                                                       &Result);
+
+                                               Mouse.doMouse();
+
+                                               SetEvent(pParams->hUnPause);
+                                               // ResumeThread(hThread);
+                                       }
+                                       break;
+
+                               case FOCUS_EVENT:
+                                       break;
+                               case WINDOW_BUFFER_SIZE_EVENT:
+                                       // FIX ME!!  This should take care of the window re-sizing bug
+                                       // Unfortunately, it doesn't.
+                                       Console.sync();
+                                       Network.do_naws(Console.GetWidth(), Console.GetHeight());
+                                       break;
+                               }
+
+                       } // keep going until no more input
+                       break;
+                                                       }
+        default:
+                       return TNNOCON;
+               }
+       }
+}
+
+WORD scrollkeys() {
+       HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
+       INPUT_RECORD InputRecord;
+       BOOL done = FALSE;
+
+       while (!done) {
+               DWORD dwInput;
+               WaitForSingleObject( hConsole, INFINITE );
+               if (!ReadConsoleInput(hConsole, &InputRecord, 1, &dwInput)){
+                       done = TRUE;
+                       continue;
+               }
+               if (InputRecord.EventType == KEY_EVENT &&
+                       InputRecord.Event.KeyEvent.bKeyDown ) {
+                       // Why not just return the key code?  (Paul Brannan 12/5/98)
+                       return InputRecord.Event.KeyEvent.wVirtualKeyCode;
+               } else if(InputRecord.EventType == MOUSE_EVENT) {
+                       if(!InputRecord.Event.MouseEvent.dwEventFlags) {
+                               // Put the mouse's X and Y coords back into the input buffer
+                               WriteConsoleInput(hConsole, &InputRecord, 1, &dwInput);
+                               return SC_MOUSE;
+                       }
+               }
+       }
+       return SC_ESC;
+}
+
+// FIX ME!!  This is more evidence that tncon.cpp ought to have class structure
+// (Paul Brannan 12/10/98)
+
+// Bryan Montgomery 10/14/98
+static TNetwork net;
+void setTNetwork(TNetwork tnet) {
+       net = tnet;
+}
+
+// Thomas Briggs 8/17/98
+BOOL WINAPI ControlEventHandler(DWORD event) {
+       switch(event) {
+       case CTRL_BREAK_EVENT:
+               // Bryan Montgomery 10/14/98
+               if(ini.get_control_break_as_c()) net.WriteString("\x3",1);
+               return TRUE;
+       default:
+               return FALSE;
+       }
+}