#include "precomp.h"
#include "tnmain.h"
int telCommandLine (Telnet &MyConnection);
void waitforkey() {
HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD InputRecord;
DWORD dwInput;
BOOL done = FALSE;
while (!done){
WaitForSingleObject( hConsole, INFINITE );
if (!ReadConsoleInput(hConsole, &InputRecord, 1, &dwInput)){
done = TRUE;
continue;
}
if (InputRecord.EventType == KEY_EVENT &&
InputRecord.Event.KeyEvent.bKeyDown )
done = TRUE;
}
}
struct cmdHistory * cfgets (char *buf, unsigned int length, struct cmdHistory *cmdhist) {
HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
unsigned int current=0, cursor =0, iEraseLength=0, i;
char chr;
char temp[2];
char temp1[80];
INPUT_RECORD InputRecord;
BOOL done = FALSE;
temp[1] = 0;
buf[0] = '\0';
if(!ini.get_input_redir()) {
while (!done) {
DWORD dwInput;
int MustRefresh = 0;
WaitForSingleObject( hConsole, INFINITE );
if (!ReadConsoleInput(hConsole, &InputRecord, 1, &dwInput)){
done = TRUE;
continue;
}
MustRefresh = 0;
if (InputRecord.EventType == KEY_EVENT &&
InputRecord.Event.KeyEvent.bKeyDown ) {
if(InputRecord.Event.KeyEvent.dwControlKeyState &
(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
switch(InputRecord.Event.KeyEvent.wVirtualKeyCode) {
case 'D':
buf[0] = '\04';
buf[1] = '\0';
current = 1;
done = true;
continue;
case 'U':
buf[0] = '\0';
current = 0;
cursor = 0;
MustRefresh = 1;
break;
}
}
switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
case VK_UP:
if (cmdhist != NULL) {
if (!strcmp(buf, ""))
strncpy(buf, cmdhist->cmd, 79);
else if (cmdhist->prev != NULL) {
cmdhist = cmdhist->prev;
strncpy(buf, cmdhist->cmd, 79);
}
current = strlen(buf);
}
MustRefresh = 1;
break;
case VK_DOWN:
if (cmdhist != NULL) {
if (cmdhist->next != NULL) {
cmdhist = cmdhist->next;
strncpy(buf, cmdhist->cmd, 79);
} else {
strncpy(buf, "", 79);
}
current = strlen(buf);
}
MustRefresh = 1;
break;
case VK_RIGHT:
if (cursor < current) {
if (InputRecord.Event.KeyEvent.dwControlKeyState &
(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
unsigned int j, k;
for (j = cursor; j <= current; j++)
{
if (buf[j + 1] == ' ' || (j + 1) == current)
break;
for (k = ++j; k <= current; k++)
{
if (buf[k] != ' ' || k == current) {
cursor = k == current ? --k : k;
break;
}
}
}
} else
cursor++;
MustRefresh = 1;
break;
}
case VK_LEFT:
if (cursor > 0) {
if(InputRecord.Event.KeyEvent.dwControlKeyState &
(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
int j, k;
for (j = cursor; j >= 0; j--)
{
if (buf[j - 1] != ' ')
break;
for (k = --j; k >= 0; k--)
{
if (buf[k] == ' ' || k == 0) {
cursor = !k ? k : ++k;
break;
}
}
}
} else
cursor--;
MustRefresh = 1;
break;
}
case VK_HOME:
if (cursor>0) cursor = 0;
MustRefresh = 1;
break;
case VK_END:
if (cursor<current) cursor = current;
MustRefresh = 1;
break;
case VK_DELETE:
if (current > 0 && current > cursor) {
strcpy(&buf[cursor],&buf[cursor+1]);
current--;
buf[current] = 0;
printit("\r");
for (i = 0; i < current+strlen("telnet>")+1 ;i++)
printit(" ");
}
MustRefresh = 1;
break;
case VK_BACK:
if (cursor > 0 ) {
strcpy(&buf[cursor-1],&buf[cursor]);
current--;
cursor--;
buf[current] = 0;
printit("\r");
for (i = 0; i < current+strlen("telnet>")+1 ;i++)
printit(" ");
}
MustRefresh = 1;
break;
default:
chr = InputRecord.Event.KeyEvent.uChar.AsciiChar;
if (chr == '\r') {
done = TRUE;
continue;
}
if (current >= length-1){
done = TRUE;
continue;
}
if ( isprint (chr) ){
strncpy(temp1,&buf[cursor],79);
strncpy(&buf[cursor+1],temp1,79-(cursor+1));
buf[cursor++]=chr;
current++;
buf[current] = 0;
MustRefresh = 1;
}
break;
}
if (MustRefresh == 1)
{
printit("\rtelnet");
for (i = 0; i <= iEraseLength ;i++)
printit(" ");
printit("\rtelnet>");
printit(buf);
iEraseLength = strlen(buf);
for (i = 0; i < current-cursor; i++)
printit("\b");
}
}
}
buf[current] = 0;
if (strcmp(buf, "")) {
if (cmdhist == NULL) {
cmdhist = new struct cmdHistory;
if (cmdhist == NULL) {
printit ("\nUnable to allocate memory for history buffer -- use the \"flush\" command to clear the buffer.\n");
return cmdhist;
}
strncpy(cmdhist->cmd, buf, 79);
cmdhist->next = NULL;
cmdhist->prev = NULL;
} else {
while (cmdhist->next != NULL)
cmdhist = cmdhist->next;
cmdhist->next = new struct cmdHistory;
if (cmdhist->next == NULL) {
printit ("\nUnable to allocate memory for history buffer -- use the \"flush\" command to clear the buffer.\n");
return cmdhist;
}
cmdhist->next->prev = cmdhist;
cmdhist = cmdhist->next;
strncpy(cmdhist->cmd, buf, 79);
cmdhist->next = NULL;
}
while (cmdhist->next)
cmdhist = cmdhist->next;
}
return cmdhist;
} else {
WaitForSingleObject( hConsole, INFINITE );
DWORD dwInput;
DWORD OldMode;
GetConsoleMode(hConsole, &OldMode);
SetConsoleMode(hConsole,
OldMode &~ (ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT) );
while (ReadFile(hConsole, &chr, 1, &dwInput, NULL)) {
if (chr == '\r') {
temp[0] = chr;
printit(&temp[0]);
break;
}
if (chr == '\b' && current > 0) {
current--;
printit("\b \b");
}
if (current >= length-1){
break;
}
if ( isprint (chr) ){
temp[0] = chr;
printit(&temp[0]);
buf[current++]=chr;
}
}
buf[current] = 0;
SetConsoleMode(hConsole, OldMode);
return NULL;
}
}
int main(int ArgC, char* ArgV[]) {
CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
GetConsoleScreenBufferInfo(
GetStdHandle(STD_OUTPUT_HANDLE),
&ConsoleScreenBufferInfo
);
char *k;
char startdir[MAX_PATH*2];
char exename[MAX_PATH];
GetModuleFileName(NULL, startdir, sizeof(startdir));
TCHAR ConsoleTitle[255];
GetConsoleTitle(ConsoleTitle, sizeof(ConsoleTitle));
k = strrchr(startdir, '\\');
if (k == NULL){
strcpy(exename, startdir);
strcpy(startdir,"");
} else {
strcpy(exename, k+1);
k[1] = 0;
}
printm(0, FALSE, MSG_COPYRIGHT);
printm(0, FALSE, MSG_COPYRIGHT_1);
ini.init(startdir, exename);
if(ini.Process_Params(ArgC, ArgV)) {
const char *szHost = ini.get_host();
const char *strPort = ini.get_port();
if(!*szHost) {
Telnet MyConnection;
while(telCommandLine(MyConnection));
} else {
Telnet MyConnection;
if(MyConnection.Open(szHost, strPort) == TNPROMPT) {
printit("\n");
telCommandLine(MyConnection);
}
}
}
if(ini.get_term_width() != -1 || ini.get_term_height() != -1) {
SetConsoleScreenBufferSize(
GetStdHandle(STD_OUTPUT_HANDLE),
ConsoleScreenBufferInfo.dwSize
);
SetConsoleWindowInfo(
GetStdHandle(STD_OUTPUT_HANDLE),
TRUE,
&ConsoleScreenBufferInfo.srWindow
);
}
SetConsoleTextAttribute(
GetStdHandle(STD_OUTPUT_HANDLE),
ConsoleScreenBufferInfo.wAttributes
);
SetConsoleTitle(ConsoleTitle);
return 0;
}
enum {
BAD_USAGE = -3,
EMPTY_LINE = -2,
INVALID_CMD = -1,
__FIRST_COMMAND = 0,
OPEN = __FIRST_COMMAND,
CLOSE,
KEYS,
QUIT,
HELP,
HELP2,
K_LOAD,
K_SWITCH,
K_DISPLAY,
SET,
SUSPEND,
FASTQUIT,
CMD_HISTORY,
CLEAR_HISTORY,
ALIASES,
__COMMAND_LIST_SIZE
};
struct command {
const char* cmd;
int minLen,
minParms,
maxParms;
int isSubCmd,
haveSubCmd;
const char* usage;
};
command cmdList[__COMMAND_LIST_SIZE] = {
{"open", 1, 1, 2, -1, 0, "o[pen] host [port]\n"},
{"close", 2, 0, 0, -1, 0, NULL},
{"keys", 2, 1, 3, -1, 1, "ke[ys] l[oad] keymapname [file]\n"
"ke[ys] d[isplay]\n"
"ke[ys] s[witch] number\n"},
{"quit", 1, 0, 0, -1, 0, NULL},
{"?", 1, 0, 0, -1, 0, NULL},
{"help", 1, 0, 0, -1, 0, NULL},
{"load", 1, 1, 2, KEYS, 0, NULL},
{"switch", 1, 1, 1, KEYS, 0, NULL},
{"display", 1, 0, 0, KEYS, 0, NULL},
{"set", 3, 0, 2, -1, 0, "set will display available groups.\n"
"set groupname will display all variables/values in a group.\n"
"set [variable [value]] will set variable to value.\n"},
{"z", 1, 0, 0, -1, 0, "suspend telnet\n"},
{"\04", 1, 0, 0, -1, 0, NULL},
{"history", 2, 0, 0, -1, 0, "show command history"},
{"flush", 2, 0, 0, -1, 0, "flush history buffer"},
{"aliases", 5, 0, 0, -1, 0, NULL}
};
#define MAX_PARM_COUNT 3
#define MAX_TOKEN_COUNT (MAX_PARM_COUNT+2)
static int cmdMatch(const char* cmd, const char* token, int tokenLen, int minM) {
if ( tokenLen < minM ) return 0;
if ( (unsigned)tokenLen > strlen(cmd) ) return 0;
if ( strcmp(cmd,token) == 0 ) return 1;
int i;
for ( i = 0; i < minM; i++ ) if ( cmd[i] != token[i] ) return 0;
for ( i = minM; i < tokenLen; i++ ) if ( cmd[i] != token[i] ) return 0;
return 1;
};
static void printUsage(int cmd) {
if ( cmdList[cmd].usage != NULL ) {
printit(cmdList[cmd].usage);
return;
};
if ( cmdList[cmd].isSubCmd >= 0 ) {
printUsage(cmdList[cmd].isSubCmd);
return;
}
printm(0, FALSE, MSG_BADUSAGE);
};
int tokenizeCommand(char* szCommand, int& argc, char** argv) {
char* tokens[MAX_TOKEN_COUNT];
char* p;
int args = 0;
if(!szCommand || !*szCommand) return EMPTY_LINE;
char *token_start = szCommand;
for(p = szCommand;; p++) {
if(*p == '\"') {
char *tmp = p;
for(p++; *p != '\"' && *p != 0; p++);
if(*p != 0) strcpy(p, p + 1);
strcpy(tmp, tmp + 1);
}
if(*p == 0 || *p == ' ' || *p == '\t') {
tokens[args] = token_start;
args++;
if(args >= MAX_TOKEN_COUNT) break;
token_start = p + 1;
if(*p == 0) break;
*p = 0;
}
}
if ( !args ) return EMPTY_LINE;
argc = args - 1;
args = 0;
int curCmd = -1;
int ok = -1;
while ( ok < 0 ) {
int tokenLen = strlen(tokens[args]);
int match = 0;
for ( int i = 0; i<__COMMAND_LIST_SIZE; i++ ) {
if ( cmdMatch(cmdList[i].cmd, tokens[args], tokenLen, cmdList[i].minLen) ) {
if (argc < cmdList[i].minParms || argc > cmdList[i].maxParms) {
printUsage(i);
return BAD_USAGE;
};
if ( cmdList[i].haveSubCmd && curCmd == cmdList[i].isSubCmd) {
curCmd = i;
args++;
argc--;
match = 1;
break;
};
if ( curCmd == cmdList[i].isSubCmd ) {
ok = i;
match = 1;
break;
};
printUsage(i);
return BAD_USAGE;
};
};
if ( !match ) {
if ( curCmd < 0 ) return INVALID_CMD;
printUsage(curCmd);
return -3;
};
};
for ( int i = 0; i<argc; i++ ) {
argv[i] = tokens[i+args+1];
};
return ok;
};
int telCommandLine (Telnet &MyConnection){
#define HISTLENGTH 25
int i, retval;
char* Parms[MAX_PARM_COUNT];
char szCommand[80];
int bDone = 0;
char *extitle, *newtitle;
struct cmdHistory *cmdhist;
cmdhist = NULL;
while (!bDone){
printit( "telnet>");
cmdhist = cfgets (szCommand, 79, cmdhist);
printit( "\n");
strlwr(szCommand);
switch ( tokenizeCommand(szCommand, i, Parms) ) {
case BAD_USAGE: break;
case EMPTY_LINE:
if(MyConnection.Resume() == TNPROMPT) {
printit("\n");
break;
}
else
return 1;
case INVALID_CMD:
printm(0, FALSE, MSG_INVCMD);
break;
case OPEN:
if (i == 1)
retval = MyConnection.Open(Parms[0], "23");
else
retval = MyConnection.Open(Parms[0], Parms[1]);
if(retval != TNNOCON && retval != TNPROMPT) return 1;
if(retval == TNPROMPT) printit("\n");
break;
case CLOSE:
MyConnection.Close();
break;
case FASTQUIT:
case QUIT:
MyConnection.Close();
bDone = 1;
break;
case HELP:
case HELP2:
printm(0, FALSE, MSG_HELP);
printm(0, FALSE, MSG_HELP_1);
break;
case K_LOAD:
if ( i == 1 ) {
if(MyConnection.LoadKeyMap( ini.get_keyfile(), Parms[0]) != 1)
printit("Error loading keymap.\n");
break;
};
if(MyConnection.LoadKeyMap( Parms[1], Parms[0]) != 1)
printit("Error loading keymap.\n");
break;
case K_DISPLAY:
MyConnection.DisplayKeyMap();
break;
case K_SWITCH:
MyConnection.SwitchKeyMap(atoi(Parms[0]));
break;
case SET:
if(i == 0) {
printit("Available groups:\n");
ini.print_groups();
} else if(i == 1) {
ini.print_vars(Parms[0]);
} else if(i >= 2) {
ini.set_value(Parms[0], Parms[1]);
}
break;
case SUSPEND:
extitle = new char[128];
GetConsoleTitle (extitle, 128);
newtitle = new char[128+sizeof("[suspended]")];
strcpy(newtitle, extitle);
strncat(newtitle, "[suspended]", 128+sizeof("[suspended]"));
if(ini.get_set_title()) SetConsoleTitle (newtitle);
delete[] newtitle;
if (getenv("comspec") == NULL) {
switch (GetWin32Version()) {
case 2:
system ("cmd");
break;
default:
system ("command");
break;
}
} else {
system(getenv("comspec"));
}
if(ini.get_set_title()) SetConsoleTitle (extitle);
delete[] extitle;
break;
case CMD_HISTORY:
if (cmdhist != NULL) {
while (cmdhist->prev != NULL)
cmdhist = cmdhist->prev;
printf ("Command history:\n");
while (1) {
printf ("\t%s\n", cmdhist->cmd);
if (cmdhist->next != NULL)
cmdhist = cmdhist->next;
else
break;
}
} else
printf ("No command history available.\n");
break;
case CLEAR_HISTORY:
if (cmdhist != NULL) {
while (cmdhist->next != NULL)
cmdhist = cmdhist->next;
while (cmdhist->prev != NULL) {
cmdhist = cmdhist->prev;
delete cmdhist->next;
}
delete cmdhist;
cmdhist = NULL;
printf ("Command history cleared.\n");
} else
printf ("No command history available.\n");
case ALIASES:
ini.print_aliases();
break;
default:
printm(0, FALSE, MSG_INVCMD);
break;
}
}
return 0;
}