Simple W32 telnet client.
authorEmanuele Aliberti <ea@iol.it>
Sat, 27 Jan 2001 22:38:43 +0000 (22:38 +0000)
committerEmanuele Aliberti <ea@iol.it>
Sat, 27 Jan 2001 22:38:43 +0000 (22:38 +0000)
Version resource added to ping and roshttpd.

svn path=/trunk/; revision=1575

16 files changed:
reactos/apps/utils/net/ping/makefile
reactos/apps/utils/net/ping/ping.c
reactos/apps/utils/net/ping/ping.rc [new file with mode: 0644]
reactos/apps/utils/net/roshttpd/common/roshttpd.rc [new file with mode: 0644]
reactos/apps/utils/net/roshttpd/makefile
reactos/apps/utils/net/telnet/Makefile [new file with mode: 0644]
reactos/apps/utils/net/telnet/ansi.cpp [new file with mode: 0644]
reactos/apps/utils/net/telnet/console.cpp [new file with mode: 0644]
reactos/apps/utils/net/telnet/console.h [new file with mode: 0644]
reactos/apps/utils/net/telnet/helpsock.cpp [new file with mode: 0644]
reactos/apps/utils/net/telnet/main.cpp [new file with mode: 0644]
reactos/apps/utils/net/telnet/nvt.cpp [new file with mode: 0644]
reactos/apps/utils/net/telnet/telnet.cpp [new file with mode: 0644]
reactos/apps/utils/net/telnet/telnet.h [new file with mode: 0644]
reactos/apps/utils/net/telnet/telnet.rc [new file with mode: 0644]
reactos/apps/utils/net/telnet/vm.cpp [new file with mode: 0644]

index c1bdf2c..26a11a9 100644 (file)
@@ -6,7 +6,7 @@ PATH_TO_TOP = ../../..
 TARGETNAME=ping
 CFLAGS = -I../../../include
 
-OBJECTS = $(TARGETNAME).o
+OBJECTS = $(TARGETNAME).o $(TARGETNAME).coff
 PROGS = $(TARGETNAME).exe
 LIBS = ../../../lib/ntdll/ntdll.a \
        ../../../lib/ws2_32/ws2_32.a
index b9d28ca..285c037 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* $Id: ping.c,v 1.3 2001/01/27 22:38:42 ea Exp $
+ *
  * COPYRIGHT:   See COPYING in the top level directory
  * PROJECT:     ReactOS ping utility
  * FILE:        apps/net/ping/ping.c
diff --git a/reactos/apps/utils/net/ping/ping.rc b/reactos/apps/utils/net/ping/ping.rc
new file mode 100644 (file)
index 0000000..0a4e588
--- /dev/null
@@ -0,0 +1,39 @@
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD      
+       FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+       FILEFLAGS       0x1L
+#else
+       FILEFLAGS       0x0L
+#endif
+       FILEOS          0x40004L
+       FILETYPE        0x2L
+       FILESUBTYPE     0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName",       RES_STR_COMPANY_NAME
+            VALUE "FileDescription",   "ReactOS TCP/IPv4 Win32 Ping\0"
+            VALUE "FileVersion",       RES_STR_FILE_VERSION
+            VALUE "InternalName",      "ping\0"
+            VALUE "LegalCopyright",    RES_STR_LEGAL_COPYRIGHT
+            VALUE "OriginalCopyright", "Casper S. Hornstrup (chorns@users.sourceforge.net)\0"
+            VALUE "OriginalFilename",  "ping.exe\0"
+            VALUE "ProductName",       RES_STR_PRODUCT_NAME
+            VALUE "ProductVersion",    RES_STR_PRODUCT_VERSION
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
diff --git a/reactos/apps/utils/net/roshttpd/common/roshttpd.rc b/reactos/apps/utils/net/roshttpd/common/roshttpd.rc
new file mode 100644 (file)
index 0000000..6c72702
--- /dev/null
@@ -0,0 +1,39 @@
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD      
+       FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+       FILEFLAGS       0x1L
+#else
+       FILEFLAGS       0x0L
+#endif
+       FILEOS          0x40004L
+       FILETYPE        0x2L
+       FILESUBTYPE     0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName",       RES_STR_COMPANY_NAME
+            VALUE "FileDescription",   "ReactOS HTTP Win32 Server\0"
+            VALUE "FileVersion",       RES_STR_FILE_VERSION
+            VALUE "InternalName",      "roshttpd\0"
+            VALUE "LegalCopyright",    RES_STR_LEGAL_COPYRIGHT
+            VALUE "OriginalCopyright", "Casper S. Hornstrup (chorns@users.sourceforge.net)\0"
+            VALUE "OriginalFilename",  "roshttpd.exe\0"
+            VALUE "ProductName",       RES_STR_PRODUCT_NAME
+            VALUE "ProductVersion",    RES_STR_PRODUCT_VERSION
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
index 639bcaf..f306709 100644 (file)
@@ -8,7 +8,7 @@ TARGETNAME=roshttpd
 CFLAGS = -Iinclude -DUNICODE -D_UNICODE -DDBG
 
 MAIN_OBJECTS = $(TARGETNAME).o config.o error.o http.o httpd.o
-COMMON_OBJECTS = common/list.o common/socket.o common/thread.o
+COMMON_OBJECTS = common/list.o common/socket.o common/thread.o common/$(TARGETNAME).coff
 
 OBJECTS = $(MAIN_OBJECTS) $(COMMON_OBJECTS)
 PROGS = $(TARGETNAME).exe
diff --git a/reactos/apps/utils/net/telnet/Makefile b/reactos/apps/utils/net/telnet/Makefile
new file mode 100644 (file)
index 0000000..95df02c
--- /dev/null
@@ -0,0 +1,79 @@
+# $Id: Makefile,v 1.1 2001/01/27 22:38:43 ea Exp $
+#
+# ReactOS Network Virtual Terminal (telnet) console client
+#
+PATH_TO_TOP=../../..
+PATH_TO_LIB=$(PATH_TO_TOP)/lib
+
+TARGET_NAME=telnet
+
+OBJECTS=\
+       ansi.o          \
+       console.o       \
+       helpsock.o      \
+       main.o          \
+       nvt.o           \
+       telnet.o        \
+       vm.o            \
+       $(TARGET_NAME).coff
+
+LIBRARIES=\
+       $(PATH_TO_LIB)/crtdll/crtdll.a          \
+       $(PATH_TO_LIB)/kernel32/kernel32.a      \
+       $(PATH_TO_LIB)/ws2_32/ws2_32.a
+
+PROGS=$(TARGET_NAME).exe
+       
+ifeq ($(DOSCLI), yes)
+CLEAN_FILES = *.o $(TARGET_NAME).exe $(TARGET_NAME).sym
+else
+CLEAN_FILES = *.o $(TARGET_NAME).exe $(TARGET_NAME).sym
+endif
+
+all: $(TARGET_NAME).exe
+
+clean: $(CLEAN_FILES:%=%_clean)
+
+$(CLEAN_FILES:%=%_clean): %_clean:
+       - $(RM) $*
+
+.phony: clean $(CLEAN_FILES:%=%_clean)
+
+install: $(PROGS:%=$(FLOPPY_DIR)/apps/%)
+
+$(PROGS:%=$(FLOPPY_DIR)/apps/%): $(FLOPPY_DIR)/apps/%: %
+ifeq ($(DOSCLI),yes)
+       $(CP) $* $(FLOPPY_DIR)\apps\$*
+else
+       $(CP) $* $(FLOPPY_DIR)/apps/$*
+endif
+
+dist: $(PROGS:%=../../$(DIST_DIR)/apps/%)
+
+$(PROGS:%=../../$(DIST_DIR)/apps/%): ../../$(DIST_DIR)/apps/%: %
+ifeq ($(DOSCLI),yes)
+       $(CP) $* ..\..\$(DIST_DIR)\apps\$*
+else
+       $(CP) $* ../../$(DIST_DIR)/apps/$*
+endif
+
+ansi.o: telnet.h
+
+helpsock.o: telnet.h
+
+main.o: telnet.h
+
+nvt.o: telnet.h
+
+telnet.o: telnet.h
+
+telnet.coff: $(PATH_TO_TOP)/include/reactos/resource.h
+
+vm.o: telnet.h
+
+$(TARGET_NAME).exe: $(OBJECTS) $(LIBRARIES)
+       $(CC) $(OBJECTS) $(LIBRARIES) -o $(TARGET_NAME).exe
+
+include $(PATH_TO_TOP)/rules.mak
+
+# EOF
diff --git a/reactos/apps/utils/net/telnet/ansi.cpp b/reactos/apps/utils/net/telnet/ansi.cpp
new file mode 100644 (file)
index 0000000..4130efc
--- /dev/null
@@ -0,0 +1,307 @@
+/* $Id: ansi.cpp,v 1.1 2001/01/27 22:38:43 ea Exp $
+ *
+ * FILE       : ansi.cpp
+ * AUTHOR     : unknown (sources found on www.telnet.org)
+ * PROJECT    : ReactOS Operating System
+ * DESCRIPTION: telnet client for the W32 subsystem
+ * DATE       : 2001-01-21
+ * REVISIONS
+ *     2001-02-21 ea   Modified to compile under 0.0.16 src tree
+ */
+#include <winsock.h>
+#include <windows.h>
+
+#include "telnet.h"
+
+// Need to implement a Keymapper.
+// here are some example key maps
+
+// vt100 f1 - \eOP
+// vt100 f2 - \eOQ
+
+// ansi  f5 - \e[17~
+//       f6 - \e[18~
+//       f7 - \e[20~
+//       f10- \e[[V
+
+enum _ansi_state
+{
+  as_normal,
+  as_esc,
+  as_esc1
+};
+
+//SetConsoleMode
+
+///////////////////////////////////////////////////////////////////////////////
+// SET SCREEN ATTRIBUTE
+/*
+ESC [ Ps..Ps m  Ps refers to selective parameter. Multiple parameters are
+                separated by the semicolon character (073 octal). The param-
+                eters are executed in order and have the following meaning:
+
+                0 or none               All attributes off
+                1                       Bold on
+                4                       Underscore on
+                5                       Blink on
+                7                       Reverse video on
+
+                3x                      set foreground color to x
+                nx                      set background color to x
+
+                Any other parameters are ignored.
+*/
+static int sa = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+
+void ansi_set_screen_attribute(char* buffer)
+{
+  while(*buffer)
+  {
+    switch(*buffer++)
+    {
+    case '0': //Normal
+      sa = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+      break;
+    case '1': //Hign Intensity
+      sa |= FOREGROUND_INTENSITY;
+      break;
+    case '4': //Underscore
+      break;
+    case '5': //Blink.
+      sa |= BACKGROUND_INTENSITY;
+      break;
+    case '7':
+      sa = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
+      break;
+    case '8':
+      sa = 0;
+      break;
+    case '3':
+      sa = sa & (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY) |
+        (*buffer & 1)?FOREGROUND_RED:0 |
+        (*buffer & 2)?FOREGROUND_GREEN:0 |
+        (*buffer & 4)?FOREGROUND_BLUE:0;
+      if(*buffer)
+        buffer++;
+      break;
+    case '6':
+      sa = sa & (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY) |
+        (*buffer & 1)?BACKGROUND_RED:0 |
+        (*buffer & 2)?BACKGROUND_GREEN:0 |
+        (*buffer & 4)?BACKGROUND_BLUE:0;
+      if(*buffer)
+        buffer++;
+      break;
+    }
+    if(*buffer && *buffer == ';')
+      buffer++;
+  }
+  SetConsoleTextAttribute(StandardOutput,sa);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ERASE LINE
+/*
+ESC [ 0K        Same *default*
+ESC [ 1K        Erase from beginning of line to cursor
+ESC [ 2K        Erase line containing cursor
+*/
+
+void ansi_erase_line(char* buffer)
+{
+  int act = 0;
+  while(*buffer)
+  {
+    act = (*buffer++) - '0';
+  }
+
+  CONSOLE_SCREEN_BUFFER_INFO csbi;
+  GetConsoleScreenBufferInfo(StandardOutput,&csbi);
+
+  COORD pos;
+  DWORD n;
+
+  switch(act)
+  {
+  case 0: //erase to end of line
+    pos.X = csbi.dwCursorPosition.X;
+    pos.Y = csbi.dwCursorPosition.Y;
+    n = csbi.dwSize.X - csbi.dwCursorPosition.X;
+    break;
+  case 1: //erase from beginning
+    pos.X = 0;
+    pos.Y = csbi.dwCursorPosition.Y;
+    n = csbi.dwCursorPosition.X;
+    break;
+  case 2: // erase whole line
+    pos.X = 0;
+    pos.Y = csbi.dwCursorPosition.Y;
+    n = csbi.dwSize.X;
+    break;
+  }
+
+  DWORD w;
+  FillConsoleOutputCharacter(StandardOutput,' ',n,pos,&w);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SET POSITION
+// ESC [ Pl;PcH    Direct cursor addressing, where Pl is line#, Pc is column#
+// default = (1,1)
+
+void ansi_set_position(char* buffer)
+{
+  COORD pos = {0,0};
+
+  // Grab line
+  while(*buffer && *buffer != ';')
+    pos.Y = pos.Y*10 + *buffer++ - '0';
+
+  if(*buffer)
+    buffer++;
+
+  // Grab y
+  while(*buffer && *buffer != ';')
+    pos.X = pos.X*10 + *buffer++ - '0';
+
+  (pos.X)?pos.X--:0;
+  (pos.Y)?pos.Y--:0;
+
+  SetConsoleCursorPosition(StandardOutput,pos);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ERASE SCREEN
+/*
+ESC [ 0J        Same *default*
+ESC [ 2J        Erase entire screen
+*/
+
+void ansi_erase_screen(char* buffer)
+{
+  int act = 0;
+  while(*buffer)
+  {
+    act = (*buffer++) - '0';
+  }
+
+  CONSOLE_SCREEN_BUFFER_INFO csbi;
+  GetConsoleScreenBufferInfo(StandardOutput,&csbi);
+
+  COORD pos;
+  DWORD n;
+
+  switch(act)
+  {
+  case 0:
+    pos.X = csbi.dwCursorPosition.X;
+    pos.Y = csbi.dwCursorPosition.Y;
+    n = csbi.dwSize.X*csbi.dwSize.Y;
+    break;
+  case 2:
+    pos.X = 0;
+    pos.Y = 0;
+    n = csbi.dwSize.X*csbi.dwSize.Y;
+    break;
+  }
+
+  DWORD w;
+  FillConsoleOutputCharacter(StandardOutput,' ',n,pos,&w);
+  SetConsoleCursorPosition(StandardOutput,pos);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MOVE UP
+// ESC [ Pn A      Cursor up Pn lines (Pn default=1)
+
+void ansi_move_up(char* buffer)
+{
+  int cnt = *buffer?0:1;
+  while(*buffer)
+  {
+    cnt = cnt*10 + (*buffer++) - '0';
+  }
+
+  COORD pos;
+
+  CONSOLE_SCREEN_BUFFER_INFO csbi;
+  GetConsoleScreenBufferInfo(StandardOutput,&csbi);
+
+  pos.X = csbi.dwCursorPosition.X;
+  pos.Y = ((csbi.dwCursorPosition.Y-cnt)>=0)?(csbi.dwCursorPosition.Y-cnt):0;
+
+  SetConsoleCursorPosition(StandardOutput,pos);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+char codebuf[256];
+unsigned char codeptr;
+
+#define NUM_CODEC 6
+
+typedef void (*LPCODEPROC)(char*);
+
+struct 
+{
+  unsigned char cmd;
+  LPCODEPROC proc;
+} codec[NUM_CODEC] = {
+  {'m',ansi_set_screen_attribute},
+  {'H',ansi_set_position},
+  {'K',ansi_erase_line},
+  {'J',ansi_erase_screen},
+  {'A',ansi_move_up},
+  {0,0}
+};
+
+void ansi(SOCKET server,unsigned char data)
+{
+  static _ansi_state state = as_normal;
+  DWORD z;
+  switch( state)
+  {
+  case as_normal:
+    switch(data)
+    {
+    case 0:  //eat null codes.
+      break;
+    case 27: //ANSI esc.
+      state = as_esc;
+      break;
+    default: //Send all else to the console.
+      WriteConsole(StandardOutput,&data,1,&z,NULL);
+      break;
+    }
+    break;
+  case as_esc:
+    state = as_esc1;
+    codeptr=0;
+    codebuf[codeptr] = 0;
+    break;
+  case as_esc1:
+    if(data > 64)
+    {
+      int i = 0;
+      codebuf[codeptr] = 0;
+      for(i=0; codec[i].cmd && codec[i].cmd != data; i++);
+      if(codec[i].proc)
+        codec[i].proc(codebuf);
+#ifdef _DEBUG
+      else
+      {
+        char buf[256];
+        wsprintf(buf,"Unknown Ansi code:'%c' (%s)\n",data,codebuf);
+        OutputDebugString(buf);
+      }
+#endif
+      state = as_normal;
+    }
+    else
+      codebuf[codeptr++] = data;
+    break;
+  }
+}
+
+/* EOF */
diff --git a/reactos/apps/utils/net/telnet/console.cpp b/reactos/apps/utils/net/telnet/console.cpp
new file mode 100644 (file)
index 0000000..09dcaec
--- /dev/null
@@ -0,0 +1,43 @@
+/* $Id: console.cpp,v 1.1 2001/01/27 22:38:43 ea Exp $
+ *
+ * FILE       : console.cpp
+ * AUTHOR     : E.Aliberti
+ * PROJECT    : ReactOS Operating System
+ * DESCRIPTION: telnet client for the W32 subsystem
+ * DATE       : 2001-01-21
+ * REVISIONS
+ *     2001-02-21 ea   added to group console-related methods
+ */
+#include <windows.h>
+
+const char * title = "telnet - ";
+
+// Set console's title
+void console_title_connecting (
+       char const* pszHostName,
+       const int nPort
+       )
+{
+  char t[256];
+  wsprintf(t,"%sconnecting to %s:%i", title, pszHostName, nPort);
+  SetConsoleTitle(t);
+}
+
+void console_title_connected (
+       char const* pszHostName,
+       const int nPort
+       )
+{
+  char t[256];
+  wsprintf(t,"%sconnected to %s:%i", title, pszHostName, nPort);
+  SetConsoleTitle(t);
+}
+
+void console_title_not_connected (void)
+{
+  char t[256];
+  wsprintf(t,"%snot connected", title);
+  SetConsoleTitle(t);
+}
+
+/* EOF */
diff --git a/reactos/apps/utils/net/telnet/console.h b/reactos/apps/utils/net/telnet/console.h
new file mode 100644 (file)
index 0000000..0846f38
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _APPS_NET_TELNET_CONSOLE_H
+#define _APPS_NET_TELNET_CONSOLE_H 
+void console_title_connecting (
+       char const* pszHostName,
+       const int nPort
+       );
+void console_title_connected (
+       char const* pszHostName,
+       const int nPort
+       );
+void console_title_not_connected (void);
+#endif /* _APPS_NET_TELNET_CONSOLE_H */
diff --git a/reactos/apps/utils/net/telnet/helpsock.cpp b/reactos/apps/utils/net/telnet/helpsock.cpp
new file mode 100644 (file)
index 0000000..a7a6b65
--- /dev/null
@@ -0,0 +1,40 @@
+/* $Id: helpsock.cpp,v 1.1 2001/01/27 22:38:43 ea Exp $
+ *
+ * FILE       : helpsock.cpp
+ * AUTHOR     : unknown (sources found on www.telnet.org)
+ * PROJECT    : ReactOS Operating System
+ * DESCRIPTION: telnet client for the W32 subsystem
+ * DATE       : 2001-01-21
+ * REVISIONS
+ *     2001-02-21 ea   Modified to compile under 0.0.16 src tree
+ */
+#include <winsock.h>
+#include <windows.h>
+#include <process.h>
+
+#include "telnet.h"
+
+char const* sockmsg(int ecode)
+{
+  switch(ecode)
+  {
+// programming errors
+// (should never occour in release code?)
+  case WSASYSNOTREADY: return "tcp/ip network not ready";
+  case WSAEINVAL: return "invalid winsock version";
+  case WSAVERNOTSUPPORTED: return "wrong winsock version";
+  case WSANOTINITIALISED: return "winsock not initialized";
+  case WSAEINTR: "The call was canceled";
+  case WSAEINPROGRESS: "A blocking winsock operation is in progress";
+  default: return "unknown winsock error";
+// general TCP problems
+  case WSAENETDOWN: return "winsock has detected that the network subsystem has failed";
+// GetXbyY related errors:
+  case WSAHOST_NOT_FOUND: return "Authoritative Answer Host not found";
+  case WSATRY_AGAIN: return "Non-Authoritative Host not found, or SERVERFAIL";
+  case WSANO_RECOVERY: "Nonrecoverable errors: FORMERR, REFUSED, NOTIMP";
+  case WSANO_DATA: "Valid name, no data record of requested type";
+  }
+}
+
+/* EOF */
diff --git a/reactos/apps/utils/net/telnet/main.cpp b/reactos/apps/utils/net/telnet/main.cpp
new file mode 100644 (file)
index 0000000..3b382b3
--- /dev/null
@@ -0,0 +1,180 @@
+/* $Id: main.cpp,v 1.1 2001/01/27 22:38:43 ea Exp $
+ *
+ * FILE       : main.cpp
+ * AUTHOR     : unknown (sources found on www.telnet.org)
+ * PROJECT    : ReactOS Operating System
+ * DESCRIPTION: telnet client for the W32 subsystem
+ * DATE       : 2001-01-21
+ * REVISIONS
+ *     2001-02-21 ea   Modified to compile under 0.0.16 src tree
+ *     2001-02-27 ea   If run with no argument, it asks for a hostname.
+ */
+///////////////////////////////////////////////////////////////////////////////
+//
+// File:
+//        main.cpp
+// 
+// Purpose:
+//        This file provdes the main entry point for the project, and all the
+//        global scope support routines.
+//
+// Notes:
+//        This file expects to be linked without the C-Runtime. If compiling,
+//        please force the entry point symbol to be "main", and do not link in
+//        the default librarys.
+//        This means that no c-runtime functions can be used anywhere in the
+//        project. I expect this will also exclude any MFC based additions.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <winsock.h>
+#include <windows.h>
+#include <process.h>
+#include <stdlib.h>
+
+#include "telnet.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Our simple replacement for the c-runtime includes getting the StandardInput,
+// StandardOutput & StandardError handles, and providing new and delete operators, that work
+// with the win32 heap functions.
+//
+
+//
+// standard handles needed for CRT emulation
+//
+HANDLE hHeap;
+HANDLE StandardInput;
+HANDLE StandardOutput;
+HANDLE StandardError;
+
+//
+// new will use the win32 heap functions.
+//
+void* operator new(unsigned int nSize)
+{
+  return HeapAlloc(hHeap,0,nSize);
+}
+
+//
+// delete operator provides all memory de-allocation.
+// HeapFree doesn't accept NULL.
+//
+void operator delete(void* pMem)
+{
+  if(pMem) HeapFree(hHeap,0,pMem);
+}
+
+
+
+void err(char const* s, ...)
+{
+       char    buf [1024];
+       DWORD   nout;
+       
+       wvsprintf (buf, s, (char*)(s + sizeof(int)));
+       WriteFile (StandardError,"Error: ", 7, & nout, NULL);
+       WriteFile (StandardError, buf, lstrlen(buf), & nout, NULL);
+       WriteFile (StandardError, "\r\n\r\n", 4, & nout, NULL);
+#ifdef _DEBUG
+       OutputDebugString(buf);
+       OutputDebugString("\n");
+#endif
+       ExitProcess (ERROR_SUCCESS);
+}
+
+
+int main(int argc, char * argv[])
+{
+       WSADATA wd;
+       int     errn;
+       char    name [256] = {'\0'};
+       short   port = IPPORT_TELNET; /* default tcp port */
+
+       ///////////////////////////////////////
+       // CRT emulation init
+       // Get the IO handles
+       StandardInput = GetStdHandle(STD_INPUT_HANDLE);
+       StandardOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+       StandardError = GetStdHandle(STD_ERROR_HANDLE);
+
+       // Get the heap 
+       hHeap = GetProcessHeap();
+
+       // Explicitly force the console into a good mode (actually all we are doing is turning
+       // mouse input off.
+       SetConsoleMode (
+               StandardInput,
+               (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT)
+               );
+
+       ///////////////////////////////////////
+       // Init winsock
+
+       if (errn = WSAStartup (0x0101, & wd))
+       {
+               err(sockmsg(errn));
+       }
+
+       /* hostname */
+       if (1 < argc)
+       {
+               lstrcpy (name, argv [1]);
+       }
+       /*
+        * Default port is IPPORT_TELNET.
+        * User may hand one.
+        */
+       if (3 == argc)
+       {
+               port = atoi (argv[2]);
+               if (port <= 0)
+               {
+                       struct servent * service = NULL;
+                       
+                       service = getservbyname (argv[2], "tcp");
+                       if (NULL == service)
+                       {
+                               err("Invalid service name specified");
+                       }
+                       port = service->s_port;
+               }
+               else
+               {
+                       err("Invalid port specified");
+               }
+       }
+       /* Too many arguments */
+       if (3 < argc)
+       {
+               err("Usage: telnet <hostname> [<port>]");
+       }
+       /* No argument */
+       if (1 == argc)
+       {
+               DWORD Count;
+               char *c;
+               
+               WriteFile (StandardError,"host: ", 6, & Count, NULL);
+               ReadFile (StandardInput, name, sizeof name, & Count, NULL);
+               c = name;
+               while (*c > ' ') ++ c;
+               *c = '\0';
+       }
+
+       // guess what this does.
+       telnet (name, port);
+
+       //Bye bye...
+       WSACleanup ();
+
+       // Exit process terminates any waiting threads.
+       // (Its the CRT that makes a process close when the main thread exits.
+       // The WinAPI will leave the process as is for as long as it has a 
+       // thread any thread.
+       ExitProcess (EXIT_SUCCESS);
+}
+
+/* EOF */
diff --git a/reactos/apps/utils/net/telnet/nvt.cpp b/reactos/apps/utils/net/telnet/nvt.cpp
new file mode 100644 (file)
index 0000000..a455a29
--- /dev/null
@@ -0,0 +1,296 @@
+/* $Id: nvt.cpp,v 1.1 2001/01/27 22:38:43 ea Exp $
+ *
+ * FILE       : nvt.cpp
+ * AUTHOR     : unknown (sources found on www.telnet.org)
+ * PROJECT    : ReactOS Operating System
+ * DESCRIPTION: telnet client for the W32 subsystem
+ * DATE       : 2001-01-21
+ * REVISIONS
+ *     2001-02-21 ea   Modified to compile under 0.0.16 src tree
+ */
+///////////////////////////////////////////////////////////////////////////////
+//
+// file: nvt.cpp
+// 
+// purpose: Provides the "bare bones" telnet "Network Virtual Terminal"
+//          that is our default. We only se a more capable terminal, if
+//          properly requested via the telnet option.
+//
+// refrence: The following excerpt from rfc 854
+//
+///////////////////////////////////////////////////////////////////////////////
+/*
+THE NETWORK VIRTUAL TERMINAL
+   The Network Virtual Terminal (NVT) is a bi-directional character
+   device.  The NVT has a printer and a keyboard.  The printer responds
+   to incoming data and the keyboard produces outgoing data which is
+   sent over the TELNET connection and, if "echoes" are desired, to the
+   NVT's printer as well.  "Echoes" will not be expected to traverse the
+   network (although options exist to enable a "remote" echoing mode of
+   operation, no host is required to implement this option).  The code
+   set is seven-bit USASCII in an eight-bit field, except as modified
+   herein.  Any code conversion and timing considerations are local
+   problems and do not affect the NVT.
+   TRANSMISSION OF DATA
+      Although a TELNET connection through the network is intrinsically
+      full duplex, the NVT is to be viewed as a half-duplex device
+      operating in a line-buffered mode.  That is, unless and until
+      options are negotiated to the contrary, the following default
+      conditions pertain to the transmission of data over the TELNET
+      connection:
+         1)  Insofar as the availability of local buffer space permits,
+         data should be accumulated in the host where it is generated
+         until a complete line of data is ready for transmission, or
+         until some locally-defined explicit signal to transmit occurs.
+         This signal could be generated either by a process or by a
+         human user.
+         The motivation for this rule is the high cost, to some hosts,
+         of processing network input interrupts, coupled with the
+         default NVT specification that "echoes" do not traverse the
+         network.  Thus, it is reasonable to buffer some amount of data
+         at its source.  Many systems take some processing action at the
+         end of each input line (even line printers or card punches
+         frequently tend to work this way), so the transmission should
+         be triggered at the end of a line.  On the other hand, a user
+         or process may sometimes find it necessary or desirable to
+         provide data which does not terminate at the end of a line;
+         therefore implementers are cautioned to provide methods of
+         locally signaling that all buffered data should be transmitted
+         immediately.
+         2)  When a process has completed sending data to an NVT printer
+         and has no queued input from the NVT keyboard for further
+         processing (i.e., when a process at one end of a TELNET
+         connection cannot proceed without input from the other end),
+         the process must transmit the TELNET Go Ahead (GA) command.
+         This rule is not intended to require that the TELNET GA command
+         be sent from a terminal at the end of each line, since server
+         hosts do not normally require a special signal (in addition to
+         end-of-line or other locally-defined characters) in order to
+         commence processing.  Rather, the TELNET GA is designed to help
+         a user's local host operate a physically half duplex terminal
+         which has a "lockable" keyboard such as the IBM 2741.  A
+         description of this type of terminal may help to explain the
+         proper use of the GA command.
+         The terminal-computer connection is always under control of
+         either the user or the computer.  Neither can unilaterally
+         seize control from the other; rather the controlling end must
+         relinguish its control explicitly.  At the terminal end, the
+         hardware is constructed so as to relinquish control each time
+         that a "line" is terminated (i.e., when the "New Line" key is
+         typed by the user).  When this occurs, the attached (local)
+         computer processes the input data, decides if output should be
+         generated, and if not returns control to the terminal.  If
+         output should be generated, control is retained by the computer
+         until all output has been transmitted.
+         The difficulties of using this type of terminal through the
+         network should be obvious.  The "local" computer is no longer
+         able to decide whether to retain control after seeing an
+         end-of-line signal or not; this decision can only be made by
+         the "remote" computer which is processing the data.  Therefore,
+         the TELNET GA command provides a mechanism whereby the "remote"
+         (server) computer can signal the "local" (user) computer that
+         it is time to pass control to the user of the terminal.  It
+         should be transmitted at those times, and only at those times,
+         when the user should be given control of the terminal.  Note
+         that premature transmission of the GA command may result in the
+         blocking of output, since the user is likely to assume that the
+         transmitting system has paused, and therefore he will fail to
+         turn the line around manually.
+      The foregoing, of course, does not apply to the user-to-server
+      direction of communication.  In this direction, GAs may be sent at
+      any time, but need not ever be sent.  Also, if the TELNET
+      connection is being used for process-to-process communication, GAs
+      need not be sent in either direction.  Finally, for
+      terminal-to-terminal communication, GAs may be required in
+      neither, one, or both directions.  If a host plans to support
+      terminal-to-terminal communication it is suggested that the host
+      provide the user with a means of manually signaling that it is
+      time for a GA to be sent over the TELNET connection; this,
+      however, is not a requirement on the implementer of a TELNET
+      process.
+      Note that the symmetry of the TELNET model requires that there is
+      an NVT at each end of the TELNET connection, at least
+      conceptually.
+*//*
+
+   THE NVT PRINTER AND KEYBOARD
+      The NVT printer has an unspecified carriage width and page length
+      and can produce representations of all 95 USASCII graphics (codes
+      32 through 126).  Of the 33 USASCII control codes (0 through 31
+      and 127), and the 128 uncovered codes (128 through 255), the
+      following have specified meaning to the NVT printer:
+         NAME                  CODE         MEANING
+         NULL (NUL)              0      No Operation
+         Line Feed (LF)         10      Moves the printer to the
+                                        next print line, keeping the
+                                        same horizontal position.
+         Carriage Return (CR)   13      Moves the printer to the left
+                                        margin of the current line.
+         In addition, the following codes shall have defined, but not
+         required, effects on the NVT printer.  Neither end of a TELNET
+         connection may assume that the other party will take, or will
+         have taken, any particular action upon receipt or transmission
+         of these:
+         BELL (BEL)              7      Produces an audible or
+                                        visible signal (which does
+                                        NOT move the print head).
+         Back Space (BS)         8      Moves the print head one
+                                        character position towards
+                                        the left margin.
+         Horizontal Tab (HT)     9      Moves the printer to the
+                                        next horizontal tab stop.
+                                        It remains unspecified how
+                                        either party determines or
+                                        establishes where such tab
+                                        stops are located.
+         Vertical Tab (VT)       11     Moves the printer to the
+                                        next vertical tab stop.  It
+                                        remains unspecified how
+                                        either party determines or
+                                        establishes where such tab
+                                        stops are located.
+         Form Feed (FF)          12     Moves the printer to the top
+                                        of the next page, keeping
+                                        the same horizontal position.
+      All remaining codes do not cause the NVT printer to take any
+      action.
+      The sequence "CR LF", as defined, will cause the NVT to be
+      positioned at the left margin of the next print line (as would,
+      for example, the sequence "LF CR").  However, many systems and
+      terminals do not treat CR and LF independently, and will have to
+      go to some effort to simulate their effect.  (For example, some
+      terminals do not have a CR independent of the LF, but on such
+      terminals it may be possible to simulate a CR by backspacing.)
+      Therefore, the sequence "CR LF" must be treated as a single "new
+      line" character and used whenever their combined action is
+      intended; the sequence "CR NUL" must be used where a carriage
+      return alone is actually desired; and the CR character must be
+      avoided in other contexts.  This rule gives assurance to systems
+      which must decide whether to perform a "new line" function or a
+      multiple-backspace that the TELNET stream contains a character
+      following a CR that will allow a rational decision.
+         Note that "CR LF" or "CR NUL" is required in both directions
+         (in the default ASCII mode), to preserve the symmetry of the
+         NVT model.  Even though it may be known in some situations
+         (e.g., with remote echo and suppress go ahead options in
+         effect) that characters are not being sent to an actual
+         printer, nonetheless, for the sake of consistency, the protocol
+         requires that a NUL be inserted following a CR not followed by
+         a LF in the data stream.  The converse of this is that a NUL
+         received in the data stream after a CR (in the absence of
+         options negotiations which explicitly specify otherwise) should
+         be stripped out prior to applying the NVT to local character
+         set mapping.
+      The NVT keyboard has keys, or key combinations, or key sequences,
+      for generating all 128 USASCII codes.  Note that although many
+      have no effect on the NVT printer, the NVT keyboard is capable of
+      generating them.
+      In addition to these codes, the NVT keyboard shall be capable of
+      generating the following additional codes which, except as noted,
+      have defined, but not reguired, meanings.  The actual code
+      assignments for these "characters" are in the TELNET Command
+      section, because they are viewed as being, in some sense, generic
+      and should be available even when the data stream is interpreted
+      as being some other character set.
+      Synch
+         This key allows the user to clear his data path to the other
+         party.  The activation of this key causes a DM (see command
+         section) to be sent in the data stream and a TCP Urgent
+         notification is associated with it.  The pair DM-Urgent is to
+         have required meaning as defined previously.
+      Break (BRK)
+         This code is provided because it is a signal outside the
+         USASCII set which is currently given local meaning within many
+         systems.  It is intended to indicate that the Break Key or the
+         Attention Key was hit.  Note, however, that this is intended to
+         provide a 129th code for systems which require it, not as a
+         synonym for the IP standard representation.
+      Interrupt Process (IP)
+         Suspend, interrupt, abort or terminate the process to which the
+         NVT is connected.  Also, part of the out-of-band signal for
+         other protocols which use TELNET.
+
+      Abort Output (AO)
+         Allow the current process to (appear to) run to completion, but
+         do not send its output to the user.  Also, send a Synch to the
+         user.
+      Are You There (AYT)
+         Send back to the NVT some visible (i.e., printable) evidence
+         that the AYT was received.
+      Erase Character (EC)
+         The recipient should delete the last preceding undeleted
+         character or "print position" from the data stream.
+      Erase Line (EL)
+         The recipient should delete characters from the data stream
+         back to, but not including, the last "CR LF" sequence sent over
+         the TELNET connection.
+      The spirit of these "extra" keys, and also the printer format
+      effectors, is that they should represent a natural extension of
+      the mapping that already must be done from "NVT" into "local".
+      Just as the NVT data byte 68 (104 octal) should be mapped into
+      whatever the local code for "uppercase D" is, so the EC character
+      should be mapped into whatever the local "Erase Character"
+      function is.  Further, just as the mapping for 124 (174 octal) is
+      somewhat arbitrary in an environment that has no "vertical bar"
+      character, the EL character may have a somewhat arbitrary mapping
+      (or none at all) if there is no local "Erase Line" facility.
+      Similarly for format effectors:  if the terminal actually does
+      have a "Vertical Tab", then the mapping for VT is obvious, and
+      only when the terminal does not have a vertical tab should the
+
+*/
+
+#include <winsock.h>
+#include <windows.h>
+
+#include "telnet.h"
+
+void nvt(SOCKET server,unsigned char data)
+{
+  DWORD z;
+  switch(data)
+  {
+  case 0:  //eat null codes.
+    break;
+  default: //Send all else to the console.
+    WriteConsole(StandardOutput, & data, 1, & z, NULL);
+    break;
+  }
+}
+
+/* EOF */
diff --git a/reactos/apps/utils/net/telnet/telnet.cpp b/reactos/apps/utils/net/telnet/telnet.cpp
new file mode 100644 (file)
index 0000000..2a5368a
--- /dev/null
@@ -0,0 +1,130 @@
+/* $Id: telnet.cpp,v 1.1 2001/01/27 22:38:43 ea Exp $
+ *
+ * FILE       : telnet.cpp
+ * AUTHOR     : unknown (sources found on www.telnet.org)
+ * PROJECT    : ReactOS Operating System
+ * DESCRIPTION: telnet client for the W32 subsystem
+ * DATE       : 2001-01-21
+ * REVISIONS
+ *     2001-02-21 ea   Modified to compile under 0.0.16 src tree
+ */
+#include <winsock.h>
+#include <windows.h>
+
+#include "telnet.h"
+#include "console.h"
+
+
+//
+// sock_loop is the thread dedicatd to reading socket input.
+// It waits for data from the socket, and then gives it one byte at a time
+// to the telnet vm to process.
+//
+
+DWORD sock_loop(SOCKET server)
+{
+  char buf[256];
+  unsigned long read;
+  char* scan;
+
+  while( (read = recv(server,buf,sizeof(buf),0)) && read != SOCKET_ERROR )
+  {
+    scan = buf;
+    while(read--)
+      vm(server,*scan++);
+  }
+  int x = WSAGetLastError();
+  return 0;
+}
+
+DWORD input_loop(SOCKET server)
+{
+  char buf[256];
+  DWORD read;
+
+  do
+  {
+    WaitForSingleObject(StandardInput, INFINITE);
+    ReadFile(StandardInput, buf, sizeof buf, & read, NULL);
+  }
+  while(SOCKET_ERROR != send(server, buf, read, 0));
+
+  return 0;
+
+}
+
+void telnet(SOCKET server)
+{
+  DWORD dwThreadIdsock;
+  DWORD dwThreadIdinput;
+  HANDLE threads[2];
+
+
+  threads[0] = CreateThread( 
+    NULL,                        /* no security attributes        */ 
+    0,                           /* use default stack size        */ 
+    (LPTHREAD_START_ROUTINE) sock_loop,  /* thread function       */ 
+    (LPVOID)server,              /* argument to thread function   */ 
+    0,                           /* use default creation flags    */ 
+    &dwThreadIdsock);            /* returns the thread identifier */ 
+
+  //wait for the other thread to complete any setup negotiation...
+  //Sleep(500); //- this is not the problem - its just bloody stuffing up!
+
+  threads[1] = CreateThread( 
+    NULL,                        /* no security attributes        */ 
+    0,                           /* use default stack size        */ 
+    (LPTHREAD_START_ROUTINE) input_loop, /* thread function       */ 
+    (LPVOID)server,              /* argument to thread function   */ 
+    0,                           /* use default creation flags    */ 
+    &dwThreadIdinput);           /* returns the thread identifier */ 
+
+
+  WaitForMultipleObjects(2,threads,FALSE,INFINITE);
+}
+
+
+//
+// connect to the hostname,port
+// 
+void telnet(
+  char const* pszHostName,
+  const short nPort)
+{
+  unsigned long ip;
+  if((*pszHostName <= '9') && (*pszHostName >= '0'))
+  {
+     if((ip = inet_addr(pszHostName)) == INADDR_NONE)
+       err("invalid host IP address given");
+  }
+  else
+  {
+    hostent* ent = gethostbyname(pszHostName);
+    if(!ent)
+      err(sockmsg(WSAGetLastError()));
+    ip = *(unsigned long*)(ent->h_addr);
+  }
+
+  sockaddr_in name;
+  name.sin_family = AF_INET;
+  name.sin_port = htons(nPort);
+  name.sin_addr = *(in_addr*)&ip;
+
+  console_title_connecting (pszHostName, nPort);
+  
+  SOCKET server;
+
+  if((server = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
+    err(sockmsg(WSAGetLastError()));
+
+  if(SOCKET_ERROR == connect(server,(sockaddr*)&name,sizeof(sockaddr)))
+    err(sockmsg(WSAGetLastError()));
+
+  console_title_connected (pszHostName, nPort);
+  
+  telnet(server);
+
+  closesocket(server);
+}
+
+/* EOF */
diff --git a/reactos/apps/utils/net/telnet/telnet.h b/reactos/apps/utils/net/telnet/telnet.h
new file mode 100644 (file)
index 0000000..c84d9c4
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _APPS_NET_TELNET_H
+#define _APPS_NET_TELNET_H
+//Global Handles
+extern HANDLE StandardInput;
+extern HANDLE StandardOutput;
+extern HANDLE StandardError;
+
+extern char const* sockmsg(int ecode);
+extern void err(char const* s,...);
+
+extern void telnet(char const* pszHostName,const short nPort);
+extern void vm(SOCKET,unsigned char);
+
+// terminal handlers:
+void ansi(SOCKET server,unsigned char data);
+void nvt(SOCKET server,unsigned char data);
+
+// helpsock
+char const* sockmsg(int ecode);
+
+// command shell
+int shell(char const* pszHostName,const int nPort);
+
+#endif /* ndef _APPS_NET_TELNET_H */
diff --git a/reactos/apps/utils/net/telnet/telnet.rc b/reactos/apps/utils/net/telnet/telnet.rc
new file mode 100644 (file)
index 0000000..420454f
--- /dev/null
@@ -0,0 +1,39 @@
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD      
+       FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+       FILEFLAGS       0x1L
+#else
+       FILEFLAGS       0x0L
+#endif
+       FILEOS          0x40004L
+       FILETYPE        0x2L
+       FILESUBTYPE     0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName",       RES_STR_COMPANY_NAME
+            VALUE "FileDescription",   "ReactOS Telnet Win32 Client\0"
+            VALUE "FileVersion",       RES_STR_FILE_VERSION
+            VALUE "InternalName",      "telnet\0"
+            VALUE "LegalCopyright",    RES_STR_LEGAL_COPYRIGHT
+            VALUE "OriginalCopyright", "Anonymous sources found at http://www.telnet.org/\0"
+            VALUE "OriginalFilename",  "telnet.exe\0"
+            VALUE "ProductName",       RES_STR_PRODUCT_NAME
+            VALUE "ProductVersion",    RES_STR_PRODUCT_VERSION
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
diff --git a/reactos/apps/utils/net/telnet/vm.cpp b/reactos/apps/utils/net/telnet/vm.cpp
new file mode 100644 (file)
index 0000000..0db3549
--- /dev/null
@@ -0,0 +1,424 @@
+/* $Id: vm.cpp,v 1.1 2001/01/27 22:38:43 ea Exp $
+ *
+ * FILE       : vm.cpp
+ * AUTHOR     : unknown (sources found on www.telnet.org)
+ * PROJECT    : ReactOS Operating System
+ * DESCRIPTION: telnet client for the W32 subsystem
+ * DATE       : 2001-01-21
+ * REVISIONS
+ *     2001-02-21 ea   Modified to compile under 0.0.16 src tree
+ */
+#include <winsock.h>
+#include <windows.h>
+
+#include "telnet.h"
+
+//      NAME          CODE   MEANING
+// NVT codes
+#define NUL     0    // No Operation
+#define BEL     7    // BELL 
+#define BS      8    // Back Space 
+#define HT      9    // Horizontal Tab 
+#define LF     10    // Line Feed 
+#define VT     11    // Vertical Tab 
+#define FF     12    // Form Feed 
+#define CR     13    // Carriage Return 
+  
+// telnet command codes
+#define SE    240    // End of subnegotiation parameters.
+#define NOP   241    // No operation.
+#define DM    242    // Data Mark
+#define BRK   243    // Break
+#define IP    244    // Interrupt Process
+#define AO    245    // Abort output
+#define AYT   246    // Are You There
+#define EC    247    // Erase character
+#define EL    248    // Erase Line          
+#define GA    249    // Go ahead
+#define SB    250    // SuBnegotiate
+#define WILL  251    // 
+#define WONT  252    // 
+#define DO    253    // 
+#define DONT  254    // 
+#define IAC   255    // Interpret As Command
+
+//Telnet options: 
+//    0x00 - binary mode
+//    0x01 - Local Echo
+//    0x03 - Suppress GA (char at a time)
+//    0x05 - status
+//    0x06 - Timing Mark   
+//
+// do 0x25 - zub?
+//
+//    0xff - Extended Options List
+
+enum _option
+{
+  TOPT_BIN = 0,   // Binary Transmission
+  TOPT_ECHO = 1,  // Echo
+  TOPT_RECN = 2,  // Reconnection
+  TOPT_SUPP = 3,  // Suppress Go Ahead
+  TOPT_APRX = 4,  // Approx Message Size Negotiation
+  TOPT_STAT = 5,  // Status
+  TOPT_TIM = 6,   // Timing Mark
+  TOPT_REM = 7,   // Remote Controlled Trans and Echo
+  TOPT_OLW = 8,   // Output Line Width
+  TOPT_OPS = 9,   // Output Page Size
+  TOPT_OCRD = 10, // Output Carriage-Return Disposition
+  TOPT_OHT = 11,  // Output Horizontal Tabstops
+  TOPT_OHTD = 12, // Output Horizontal Tab Disposition
+  TOPT_OFD = 13,  // Output Formfeed Disposition
+  TOPT_OVT = 14,  // Output Vertical Tabstops
+  TOPT_OVTD = 15, // Output Vertical Tab Disposition
+  TOPT_OLD = 16,  // Output Linefeed Disposition
+  TOPT_EXT = 17,  // Extended ASCII
+  TOPT_LOGO = 18, // Logout
+  TOPT_BYTE = 19, // Byte Macro
+  TOPT_DATA = 20, // Data Entry Terminal
+  TOPT_SUP = 21,  // SUPDUP
+  TOPT_SUPO = 22, // SUPDUP Output
+  TOPT_SNDL = 23, // Send Location
+  TOPT_TERM = 24, // Terminal Type
+  TOPT_EOR = 25,  // End of Record
+  TOPT_TACACS = 26, // TACACS User Identification
+  TOPT_OM = 27,   // Output Marking
+  TOPT_TLN = 28,  // Terminal Location Number
+  TOPT_3270 = 29, // Telnet 3270 Regime
+  TOPT_X3 = 30,  // X.3 PAD
+  TOPT_NAWS = 31, // Negotiate About Window Size
+  TOPT_TS = 32,   // Terminal Speed
+  TOPT_RFC = 33,  // Remote Flow Control
+  TOPT_LINE = 34, // Linemode
+  TOPT_XDL = 35,  // X Display Location
+  TOPT_ENVIR = 36,// Telnet Environment Option
+  TOPT_AUTH = 37, // Telnet Authentication Option
+  TOPT_NENVIR = 39,// Telnet Environment Option
+  TOPT_EXTOP = 255, // Extended-Options-List
+  TOPT_ERROR = 256  // Magic number
+};
+
+// Wanted by linux box:
+// 37 - TOPT_AUTH
+// 24 - TOPT_TERM
+
+enum _verb
+{
+  verb_sb   = 250,
+  verb_will = 251,
+  verb_wont = 252,
+  verb_do   = 253, 
+  verb_dont = 254
+};
+
+enum _state
+{
+  state_data,   //we expect a data byte
+  state_code,   //we expect a code
+  state_option  //we expect an option
+};
+
+int option_error(_verb,_option,int,SOCKET);
+
+typedef void(*LPOPTIONPROC)(SOCKET,_verb,_option);
+typedef void(*LPDATAPROC)(SOCKET,unsigned char data);
+
+///////////////////////////////////////////////////////////////////////////////
+
+inline void yesreply(SOCKET server, _verb verb,_option option)
+{
+  unsigned char buf[3];
+  buf[0] = IAC;
+  buf[1] = (verb==verb_do)?WILL:(verb==verb_dont)?WONT:(verb==verb_will)?DO:DONT;
+  buf[2] = (unsigned char)option;
+  send(server,(char*)buf,3,0);
+}
+
+inline void noreply(SOCKET server, _verb verb,_option option)
+{
+  unsigned char buf[3];
+  buf[0] = IAC;
+  buf[1] = (verb==verb_do)?WONT:(verb==verb_dont)?WILL:(verb==verb_will)?DONT:DO;
+  buf[2] = (unsigned char)option;
+  send(server,(char*)buf,3,0);
+}
+
+inline void askfor(SOCKET server, _verb verb,_option option)
+{
+  unsigned char buf[3];
+  buf[0] = IAC;
+  buf[1] = (unsigned char)verb;
+  buf[2] = (unsigned char)option;
+  send(server,(char*)buf,3,0);
+}
+
+
+void ddww_error(SOCKET server,_verb verb,_option option)
+{
+#ifdef _DEBUG
+  char tmp[256];
+  wsprintf(tmp,"Unknown Option Code: %s, %i\n",(verb==verb_do)?"DO":(verb==verb_dont)?"DON'T":(verb==verb_will)?"WILL":"WONT",(int)option);
+  OutputDebugString(tmp);
+#endif
+
+  switch(verb)
+  {
+  case verb_will: // server wants to support something
+    noreply(server,verb,option); // I don't want that.
+    break;
+  case verb_wont: // server waants to disable support
+    return;       // don't confirm - already disabled.
+  case verb_do:   // server wants me to support something
+    noreply(server,verb,option); //I won't do that
+    break;
+  case verb_dont: // server wants me to disable something
+    return;       // don't worry, we don't do that anyway (I hope :)
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Option ECHO & SUPPRESS GA
+//
+// These options are curiously intertwined...
+// The Win32 console doesn't support ECHO_INPUT (echo) if
+// LINE_INPUT (==GA) isn't set.
+// I can't see how to code this negotiation without using
+// some form of Lock-Step algorythm
+// ie: if("WILL ECHO")
+//       Send "DO SUPP"
+//       if("WILL SUPP")
+//         Send "DO ECHO"
+//       else 
+//         Send "DONT ECHO"
+
+
+void ddww_echo(SOCKET server,_verb verb, _option option)
+{
+  DWORD mode;
+  GetConsoleMode(StandardInput, & mode); // ENABLE_ECHO_INPUT
+  
+  int set = !(mode & ENABLE_ECHO_INPUT);
+
+  switch(verb)
+  {
+  case verb_will: // server wants to echo stuff
+    if(set) return; //don't confirm - already set.
+    SetConsoleMode(StandardInput,mode & (~ENABLE_ECHO_INPUT));
+    break;
+  case verb_wont: // server don't want to echo
+    if(!set) return; //don't confirm - already unset.
+    SetConsoleMode(StandardInput,mode | ENABLE_ECHO_INPUT);
+    break;
+  case verb_do:   // server wants me to loopback
+    noreply(server,verb,option);
+    return;
+  case verb_dont: // server doesn't want me to echo
+    break;        // don't bother to reply - I don't
+  }
+  yesreply(server,verb,option);
+}
+
+
+void ddww_supp(SOCKET server,_verb verb,_option option) //Suppress GA
+{
+  DWORD mode;
+  GetConsoleMode(StandardInput,&mode); // ENABLE_LINE_INPUT
+  
+  int set = !(mode & ENABLE_LINE_INPUT);
+
+  switch(verb)
+  {
+  case verb_will: // server wants to suppress GA's
+    if(set) break; //don't confirm - already set.
+    SetConsoleMode(StandardInput,mode & (~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)));
+    askfor(server,verb_do,TOPT_SUPP);
+    askfor(server,verb_will,TOPT_SUPP);
+    askfor(server,verb_do,TOPT_ECHO);
+    break;
+  case verb_wont: // server wants to send GA's 
+    if(!set) break; //don't confirm - already unset.
+    SetConsoleMode(StandardInput,mode | ENABLE_LINE_INPUT);
+    askfor(server,verb_dont,TOPT_SUPP);
+    askfor(server,verb_wont,TOPT_SUPP);
+    break;
+  case verb_do:   // server wants me to suppress GA's
+    if(set) break;
+    askfor(server,verb_do,TOPT_SUPP);
+    break;
+  case verb_dont: // server wants me to send GA's
+    if(!set) break;
+    askfor(server,verb_dont,TOPT_SUPP);
+    break;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Option TERMINAL-TYPE
+
+void ddww_term(SOCKET server,_verb verb,_option option) //Subnegotiate terminal type
+{
+  switch(verb)
+  {
+  case verb_will:
+    noreply(server,verb,option); // I don't want terminal info
+    break;
+  case verb_wont:
+    //dat be cool - its not going to send. no need to confirm
+    break;
+  case verb_do:
+    yesreply(server,verb,option); //I'll send it when asked
+    break;
+  case verb_dont://Ok - I won't
+    break;
+  }
+}
+
+// TERMINAL TYPE subnegotation
+enum
+{
+  SB_TERM_IS = 0,
+  SB_TERM_SEND = 1
+};
+
+#define NUM_TERMINALS 2
+
+struct
+{
+  char* name;
+  LPDATAPROC termproc;
+  //pre requsites.
+} terminal[NUM_TERMINALS] = {
+  { "NVT", nvt }, 
+  { "ANSI", ansi }
+};
+
+int term_index = 0;
+
+void sbproc_term(SOCKET server,unsigned char data)
+{
+
+  if(data == SB_TERM_SEND)
+  {
+    if(term_index == NUM_TERMINALS)
+      term_index = 0;
+    else
+      term_index++;
+    char buf[16]; //pls limit 
+    buf[0] = IAC;
+    buf[1] = SB;
+    buf[2] = TOPT_TERM;
+    buf[3] = SB_TERM_IS;
+    lstrcpy(&buf[4],terminal[(term_index==NUM_TERMINALS)?(NUM_TERMINALS-1):term_index].name);
+    int nlen = lstrlen(&buf[4]);
+    buf[4+nlen] = IAC;
+    buf[5+nlen] = SE;
+    send(server,buf,4+nlen+2,0);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct
+{
+  _option option;
+  LPOPTIONPROC OptionProc;
+  LPDATAPROC DataProc;
+}  ol[] = {
+  {TOPT_ECHO,   ddww_echo,  NULL},
+  {TOPT_SUPP,   ddww_supp,  NULL},
+  {TOPT_TERM,   ddww_term,  sbproc_term},
+  {TOPT_ERROR,  ddww_error, NULL}
+};
+
+
+void vm(SOCKET server,unsigned char code)
+{
+//These vars are the finite state
+  static int state = state_data;
+  static _verb verb = verb_sb;
+  static LPDATAPROC DataProc = terminal[(term_index==NUM_TERMINALS)?(NUM_TERMINALS-1):term_index].termproc;
+// for index
+  int i=0;
+
+//Decide what to do (state based)
+  switch(state)
+  {
+  case state_data:
+    switch(code)
+    {
+    case IAC: state = state_code; break;
+    default: DataProc(server,code);
+    }
+    break;
+  case state_code:
+    state = state_data;
+    switch(code)
+    {
+    // State transition back to data
+    case IAC: 
+      DataProc(server,code);
+      break;
+    // Code state transitions back to data
+    case SE:
+      DataProc = terminal[(term_index==NUM_TERMINALS)?(NUM_TERMINALS-1):term_index].termproc;
+      break;
+    case NOP:
+      break;
+    case DM:
+      break;
+    case BRK:
+      break;
+    case IP:
+      break;
+    case AO:
+      break;
+    case AYT:
+      break;
+    case EC:
+      break;
+    case EL:
+      break;
+    case GA:
+      break;
+    // Transitions to option state
+    case SB:
+      verb = verb_sb;
+      state = state_option;
+      break;
+    case WILL:
+      verb = verb_will;
+      state = state_option;
+      break;
+    case WONT:
+      verb = verb_wont;
+      state = state_option;
+      break;
+    case DO:
+      verb = verb_do;
+      state = state_option;
+      break;
+    case DONT:
+      verb = verb_dont;
+      state = state_option;
+      break;
+    }
+    break;
+  case state_option:
+    state = state_data;
+
+    //Find the option entry
+    for(
+      i = 0;
+      ol[i].option != TOPT_ERROR && ol[i].option != code;
+      i++);
+
+    //Do some verb specific stuff
+    if(verb == verb_sb)
+      DataProc = ol[i].DataProc;
+    else
+      ol[i].OptionProc(server,verb,(_option)code);
+    break;
+  }
+}
+
+/* EOF */