Simple W32 telnet client.

Version resource added to ping and roshttpd.

svn path=/trunk/; revision=1575
This commit is contained in:
Emanuele Aliberti 2001-01-27 22:38:43 +00:00
parent 5786d70e39
commit ff1de6a212
16 changed files with 1656 additions and 3 deletions

View 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

View 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

View file

@ -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

View file

@ -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

View 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

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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 */