📄 raw.c
字号:
/* raw.c
* Copyright (c) 1997 David Cole
*
* Strip off and process raw protocol from session
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "utils.h"
#define TELNET_STRINGS
#include "protocol.h"
#include "emul.h"
#include "connect.h"
#include "socket.h"
#include "term.h"
#include "raw.h"
#include "log.h"
/* Describe the different protocol types we can use on the connection.
* The order of the entries in this array is important - the index of
* array must match the RawProtocol enum defined in raw.h
*/
struct Protocols protocols[] = {
{ "telnet", 23, protoTelnet },
{ "login", 513, protoRlogin },
{ "none", -1, protoNone }
};
unsigned int numProtocols = 3;
static BOOL inCommand; /* are we reading a telnet command? */
static unsigned char cmdBuff[40]; /* build up telnet command */
static int cmdUpto; /* next available character in cmdBuff */
static BOOL ignoreTextUntilDM; /* processing TELNET Synch */
static RawProtocol rawProtocol; /* which protocol are we using? */
static BOOL startSession; /* we have just started a new telnet
* session */
static BOOL dontNAWS; /* do not send NAWS any more */
static BOOL doneNAWS; /* have done NAWS exchange */
static BOOL doneSGA; /* have done the SGA exchange */
static BOOL doneLFLOW; /* have done the LFLOW exchange */
static BOOL enableBINARY; /* binary mode negotiation is disabled
* by default */
static BOOL doneBINARY; /* have done the BINARY exchange */
static BOOL inBINARY; /* are we in binary mode? */
static BOOL compressResize; /* wait until user has finished
* resizing before sending new size to
* server? */
static BOOL needResize; /* is a user resize queued? */
static TelnetLocalOption toXdisploc; /* XDISPLOC telnet option */
static BOOL fDoSgaSent; /* TRUE if I've already sent DO SGA */
/* Enable telnet BINARY mode negotiation
*/
void rawEnableBinaryMode()
{
enableBINARY = TRUE;
}
/* Return whether or not we are in telnet BINARY mode
*/
BOOL rawInBinaryMode()
{
return inBINARY;
}
/* From rfc1258. As soon as the connection is established, we send a
* message of the form:
* <null>
* client-user-name<null>
* server-user-name<null>
* terminal-type/speed<null>
*/
static void rawRloginStart(void)
{
char msg[64]; /* build message here */
int idx; /* current position in msg */
char* userName = connectGetUser(); /* user to client/server user-name */
char* term = connectGetTerm(); /* terminal type */
char* str; /* copy strings into msg */
int p2offset; /* index of parameter-2 (server-user-name) */
int p3offset; /* index of parameter-3 */
/* Copy in initial null
*/
msg[0] = 0;
/* Copy in client-user-name + null
*/
for (idx = 1, str = userName; *str; ++idx, ++str)
msg[idx] = *str;
msg[idx++] = '\0';
/* Copy in server-user-name + null
*/
p2offset = idx;
for (str = userName; *str; ++idx, ++str)
msg[idx] = *str;
msg[idx++] = '\0';
/* Copy in terminal-type
*/
p3offset = idx;
for (str = term; *str; ++idx, ++str)
msg[idx] = *str;
/* Copy in /speed (fixed at 9600) + null
*/
for (str = "/9600"; *str; ++idx, ++str)
msg[idx] = *str;
msg[idx++] = '\0';
/* Send message to remote end and log protocol
*/
socketWrite(msg, idx);
logProtocol("send \\0 %s\\0 %s\\0 %s\\0\n",
msg + 1, msg + p2offset, msg + p3offset);
}
static char* telcmd(unsigned char cmd)
{
static char buff[16];
if (TELCMD_OK(cmd))
return TELCMD(cmd);
sprintf(buff, "0x%02x", cmd);
return buff;
}
static char* telopt(unsigned char opt)
{
static char buff[16];
if (TELOPT_OK(opt))
return TELOPT(opt);
sprintf(buff, "0x%02x", opt);
return buff;
}
/* Send a telnet command to the server
*
* Args:
* cmd - the telnet command to send
* opt - option to send with the comand
*/
void rawCmd(unsigned char cmd, unsigned char opt)
{
char msg[3]; /* format command */
/* Build command, send and log it
*/
msg[0] = (char)IAC;
msg[1] = (char)cmd;
msg[2] = (char)opt;
socketWrite(msg, sizeof(msg));
logProtocol("send %s %s\n", telcmd(cmd), telopt(opt));
}
/* Make sure we ask the telnet server about options that it did not
* ask us about.
*/
static void rawTelnetStart(void)
{
logProtocol("Client initiated options\n");
ignoreTextUntilDM = FALSE;
if (!doneNAWS) {
/* Server did not ask us about NAWS, tell it we will NAWS
*/
rawCmd(WILL, TELOPT_NAWS);
doneNAWS = TRUE;
}
if (!doneLFLOW) {
/* Server did not ask us about LFLOW, tell it we will LFLOW
*/
rawCmd(WILL, TELOPT_LFLOW);
socketSetLocalFlowControl(TRUE);
}
if (!doneSGA) {
/* Tell the server not to send us GA commands.
* TCP/IP Illustrated Volume 1 pg. 407
*/
rawCmd(DO, TELOPT_SGA);
fDoSgaSent = TRUE;
}
/* Do not perform binary mode negotiation unless told to
*/
if (enableBINARY && !doneBINARY) {
rawCmd(DO, TELOPT_BINARY);
doneBINARY = TRUE;
}
if (socketHaveXServer ()) {
rawCmd(WILL, TELOPT_XDISPLOC);
toXdisploc = toIWPending;
} else {
toXdisploc = toIDontWant;
}
}
/* Perform initialisation for session on new connection
*/
void rawStartSession()
{
/* Clear telnet state
*/
cmdUpto = 0;
dontNAWS = TRUE;
doneNAWS = doneSGA = doneLFLOW = doneBINARY = FALSE;
fDoSgaSent = FALSE;
/* Flag that we have just started a new session
*/
startSession = TRUE;
/* Flag that we are not in BINARY mode
*/
inBINARY = FALSE;
if (rawProtocol == protoRlogin)
/* When doing rlogin, we have to get the ball rolling
*/
rawRloginStart();
else if (rawProtocol == protoTelnet)
rawTelnetStart();
}
/* User has started resizing the window
*/
void rawResizeBegin()
{
compressResize = TRUE;
}
/* User just finished resizing the window
*/
void rawResizeEnd()
{
compressResize = FALSE;
if (needResize)
rawSetWindowSize();
}
/* Tell the telnet/rlogin server what our window size is
*/
void rawSetWindowSize()
{
char msg[12]; /* format message */
if (dontNAWS)
/* If the server does not want to receive window size
* messages, do not send message
*/
return;
if (compressResize) {
needResize = TRUE;
return;
} else
needResize = FALSE;
termCheckSizeLimits(); // Khader
switch (rawProtocol) {
case protoTelnet:
/* Build telnet message for communicating window size
*/
msg[0] = (char)IAC;
msg[1] = (char)SB;
msg[2] = (char)TELOPT_NAWS;
msg[3] = (char)(term.winSize.cx >> 8);
msg[4] = (char)(term.winSize.cx % 0xff);
msg[5] = (char)(term.winSize.cy >> 8);
msg[6] = (char)(term.winSize.cy % 0xff);
msg[7] = (char)IAC;
msg[8] = (char)SE;
/* Send and log message
*/
socketWrite(msg, 9);
logProtocol("send SB NAWS %d %d IAC SE\n",
term.winSize.cx, term.winSize.cy);
break;
case protoRlogin:
/* Build rlogin message for communicating window size
*/
msg[0] = (char)0xff;
msg[1] = (char)0xff;
msg[2] = 's';
msg[3] = 's';
msg[4] = (char)(term.winSize.cy >> 8);
msg[5] = (char)(term.winSize.cy % 0xff);
msg[6] = (char)(term.winSize.cx >> 8);
msg[7] = (char)(term.winSize.cx % 0xff);
msg[8] = msg[4];
msg[9] = msg[5];
msg[10] = msg[6];
msg[11] = msg[7];
/* Send and log message
*/
socketWrite(msg, 12);
logProtocol("send 0xff 0xff ss %d %d %d %d\n",
term.winSize.cy, term.winSize.cx,
term.winSize.cy, term.winSize.cx);
break;
}
}
/* Tell the telnet server what terminal we are using
*/
void rawSetTerm(void)
{
unsigned char msg[20]; /* build message */
int idx; /* current position in message */
char* term = connectGetTerm(); /* current terminal type */
if (!socketConnected())
/* Do not send message if not connected
*/
return;
/* Build message
*/
msg[0] = IAC;
msg[1] = SB;
msg[2] = TELOPT_TTYPE;
msg[3] = 0;
for (idx = 4; *term; ++idx, ++term)
msg[idx] = (unsigned char)toupper(*term);
msg[idx++] = IAC;
msg[idx++] = SE;
/* Send and log message
*/
socketWrite((char*)msg, idx);
logProtocol("send SB TTYPE IS %.*s IAC SE\n", idx - 6, msg + 4);
}
/* Add a character to the current command and try to process it.
* Return whether or not to remain in command mode.
*
* Args:
* ch - character to add to command
*/
static BOOL parseTelnetCommand(unsigned char ch)
{
unsigned char cmd; /* extract telnet command */
unsigned char opt; /* extract command option */
char msg [300], display[200];
int msglen;
/* First copy the character into the command buffer
*/
if (cmdUpto == sizeof(cmdBuff)) {
logProtocol("TELNET Command buffer overflow\n");
cmdUpto = 0;
return FALSE;
}
cmdBuff[cmdUpto++] = ch;
if (cmdUpto == 1)
return TRUE; /* Minimum command length is 2 */
/* Get command
*/
cmd = cmdBuff[1];
switch (cmd) {
case IAC:
/* Command was escaped IAC (255) data byte
*/
emulAddText(cmdBuff, 1, FALSE);
cmdUpto = 0;
return FALSE; /* Not in command any more */
case DO: /* server telling us to do something */
case DONT: /* server telling us not to do something */
case WILL: /* server telling us it will do something */
case WONT: /* server telling us it won't do something */
if (cmdUpto < 3)
return TRUE; /* Options require 3 bytes */
/* Get command option
*/
opt = cmdBuff[2];
logProtocol("recv %s %s\n", telcmd(cmd), telopt(opt));
switch (opt) {
case TELOPT_BINARY:
/* Code added 11/25/98, patrick@narkinsky.ml.org
*/
switch (cmd) {
case DO:
/* Server has asked us to send BINARY
*/
if (enableBINARY) {
rawCmd(WILL, TELOPT_BINARY);
inBINARY = TRUE;
} else
rawCmd(WONT, TELOPT_BINARY);
break;
case DONT:
/* Server told us not to BINARY, tell it we WONT
*/
rawCmd(WONT, TELOPT_BINARY);
inBINARY = FALSE;
break;
case WILL:
/* Server has told us it will send BINARY
*/
if (enableBINARY) {
rawCmd(DO, TELOPT_BINARY);
inBINARY = TRUE;
} else
rawCmd(DONT, TELOPT_BINARY);
break;
case WONT:
/* Server has told us it WONT BINARY, tell it not to
*/
rawCmd(DONT, TELOPT_BINARY);
inBINARY = FALSE;
break;
}
if (enableBINARY)
doneBINARY = TRUE;
break;
case TELOPT_NAWS:
switch (cmd) {
case DO:
/* Server has asked us to NAWS
*/
dontNAWS = FALSE;
if (!doneNAWS)
rawCmd(WILL, TELOPT_NAWS);
rawSetWindowSize();
break;
case DONT:
/* Server has told us not to NAWS
*/
dontNAWS = TRUE;
break;
}
doneNAWS = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -