mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 01:24:38 +00:00
Simple W32 telnet client.
Version resource added to ping and roshttpd. svn path=/trunk/; revision=1575
This commit is contained in:
parent
5786d70e39
commit
ff1de6a212
16 changed files with 1656 additions and 3 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
39
reactos/apps/utils/net/ping/ping.rc
Normal file
39
reactos/apps/utils/net/ping/ping.rc
Normal 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
|
||||
|
39
reactos/apps/utils/net/roshttpd/common/roshttpd.rc
Normal file
39
reactos/apps/utils/net/roshttpd/common/roshttpd.rc
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
79
reactos/apps/utils/net/telnet/Makefile
Normal file
79
reactos/apps/utils/net/telnet/Makefile
Normal 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
|
307
reactos/apps/utils/net/telnet/ansi.cpp
Normal file
307
reactos/apps/utils/net/telnet/ansi.cpp
Normal 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 */
|
43
reactos/apps/utils/net/telnet/console.cpp
Normal file
43
reactos/apps/utils/net/telnet/console.cpp
Normal 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 */
|
12
reactos/apps/utils/net/telnet/console.h
Normal file
12
reactos/apps/utils/net/telnet/console.h
Normal 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 */
|
40
reactos/apps/utils/net/telnet/helpsock.cpp
Normal file
40
reactos/apps/utils/net/telnet/helpsock.cpp
Normal 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 */
|
180
reactos/apps/utils/net/telnet/main.cpp
Normal file
180
reactos/apps/utils/net/telnet/main.cpp
Normal 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 */
|
296
reactos/apps/utils/net/telnet/nvt.cpp
Normal file
296
reactos/apps/utils/net/telnet/nvt.cpp
Normal 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 */
|
130
reactos/apps/utils/net/telnet/telnet.cpp
Normal file
130
reactos/apps/utils/net/telnet/telnet.cpp
Normal 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 */
|
24
reactos/apps/utils/net/telnet/telnet.h
Normal file
24
reactos/apps/utils/net/telnet/telnet.h
Normal 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 */
|
39
reactos/apps/utils/net/telnet/telnet.rc
Normal file
39
reactos/apps/utils/net/telnet/telnet.rc
Normal 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
|
||||
|
424
reactos/apps/utils/net/telnet/vm.cpp
Normal file
424
reactos/apps/utils/net/telnet/vm.cpp
Normal 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 */
|
Loading…
Reference in a new issue