1 ///////////////////////////////////////////////////////////////////////////////
2 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998  Paul Brannan
4 //Copyright (C) 1998  I.Ioannou
5 //Copyright (C) 1997  Brad Johnson
6 //
7 //This program is free software; you can redistribute it and/or
8 //modify it under the terms of the GNU General Public License
9 //as published by the Free Software Foundation; either version 2
10 //of the License, or (at your option) any later version.
11 //
12 //This program is distributed in the hope that it will be useful,
13 //but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //GNU General Public License for more details.
16 //
17 //You should have received a copy of the GNU General Public License
18 //along with this program; if not, write to the Free Software
19 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 //I.Ioannou
22 //roryt@hol.gr
23 //
24 ///////////////////////////////////////////////////////////////////////////
25 
26 ///////////////////////////////////////////////////////////////////////////////
27 //
28 // Module:		tnmain.cpp
29 //
30 // Contents:	telnet main program
31 //
32 // Product:		telnet
33 //
34 // Revisions: August 11, 1998	Thomas Briggs <tbriggs@qmetric.com>
35 //            May 14, 1998		Paul Brannan <pbranna@clemson.edu>
36 //            5.April.1997		jbj@nounname.com
37 //            5.Dec.1996		jbj@nounname.com
38 //            Version 2.0
39 //
40 //            02.Apr.1995		igor.milavec@uni-lj.si
41 //					  Original code
42 //
43 ///////////////////////////////////////////////////////////////////////////////
44 
45 #include "precomp.h"
46 
47 #include "tnmain.h"
48 
49 int telCommandLine (Telnet &MyConnection);
50 
waitforkey()51 void waitforkey() {
52 	HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
53 	INPUT_RECORD InputRecord;
54 	DWORD dwInput;
55 	BOOL done = FALSE;
56 	while (!done){
57 		WaitForSingleObject( hConsole, INFINITE );
58 		if (!ReadConsoleInput(hConsole, &InputRecord, 1, &dwInput)){
59 			done = TRUE;
60 			continue;
61 		}
62 		if (InputRecord.EventType == KEY_EVENT &&
63 			InputRecord.Event.KeyEvent.bKeyDown )
64 			done = TRUE;
65 	}
66 }
67 
68 //char * cfgets ( char * buf, unsigned int length, char pszHistory[][80], int iHistLength){
cfgets(char * buf,unsigned int length,struct cmdHistory * cmdhist)69 struct cmdHistory * cfgets (char *buf, unsigned int length, struct cmdHistory *cmdhist) {
70 
71 	HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
72 	unsigned int current=0, cursor =0, iEraseLength=0, i;
73 	char chr;
74 	char temp[2];
75 	char temp1[80];
76 
77 	INPUT_RECORD InputRecord;
78 	BOOL done = FALSE;
79 
80 	temp[1] = 0;
81 	buf[0] = '\0';
82 
83 	if(!ini.get_input_redir()) {
84 		while (!done) {
85 			DWORD dwInput;
86 			int MustRefresh = 0;
87 			WaitForSingleObject( hConsole, INFINITE );
88 			if (!ReadConsoleInput(hConsole, &InputRecord, 1, &dwInput)){
89 				done = TRUE;
90 				continue;
91 			}
92 			MustRefresh = 0;
93 			if (InputRecord.EventType == KEY_EVENT &&
94 				InputRecord.Event.KeyEvent.bKeyDown ) {
95 
96 				if(InputRecord.Event.KeyEvent.dwControlKeyState &
97 					(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
98 
99 					switch(InputRecord.Event.KeyEvent.wVirtualKeyCode) {
100 					case 'D': // Thomas Briggs 8/11/98
101 						buf[0] = '\04';
102 						buf[1] = '\0';
103 						current = 1;
104 						done = true;
105 						continue;
106 					case 'U': // Paul Brannan 8/11/98
107 						buf[0] = '\0';
108 						current = 0;
109 						cursor = 0;
110 						MustRefresh = 1;
111 						break;
112 					}
113 				}
114 
115 				switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
116 				case VK_UP:
117 					// crn@ozemail.com.au
118 					if (cmdhist != NULL) {
119 						if (!strcmp(buf, ""))
120 							strncpy(buf, cmdhist->cmd, 79);
121 						else if (cmdhist->prev != NULL) {
122 							cmdhist = cmdhist->prev;
123 							strncpy(buf, cmdhist->cmd, 79);
124 						}
125 						current = strlen(buf);
126 					}
127 					///
128 					MustRefresh = 1;
129 					break;
130 				case VK_DOWN:
131 					// crn@ozemail.com.au
132 					if (cmdhist != NULL) {
133 						if (cmdhist->next != NULL) {
134 							cmdhist = cmdhist->next;
135 							strncpy(buf, cmdhist->cmd, 79);
136 						} else {
137 							strncpy(buf, "", 79);
138 						}
139 						current = strlen(buf);
140 					}
141 					///
142 					MustRefresh = 1;
143 					break;
144 				case VK_RIGHT:		//crn@ozemail.com.au (added ctrl+arrow)
145 					if (cursor < current) {
146 						if (InputRecord.Event.KeyEvent.dwControlKeyState &
147 							(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
148 							unsigned int j, k;
149                             for (j = cursor; j <= current; j++)
150                             {
151                                 if (buf[j + 1] == ' ' || (j + 1) == current)
152                                     break;
153                                 for (k = ++j; k <= current; k++)
154                                 {
155                                     if (buf[k] != ' ' || k == current) {
156                                         cursor = k == current ? --k : k;
157                                         break;
158                                     }
159                                 }
160                             }
161 						} else
162 							cursor++;
163 						MustRefresh = 1;
164 						break;
165 					}
166 				case VK_LEFT:		//crn@ozemail.com.au (added ctrl+arrow)
167 					if (cursor > 0) {
168 						if(InputRecord.Event.KeyEvent.dwControlKeyState &
169 							(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
170 							int j, k;
171                             for (j = cursor; j >= 0; j--)
172                             {
173                                 if (buf[j - 1] != ' ')
174                                     break;
175                                 for (k = --j; k >= 0; k--)
176                                 {
177                                     if (buf[k] == ' ' || k == 0) {
178                                         cursor = !k ? k : ++k;
179                                         break;
180                                     }
181                                 }
182                             }
183 						} else
184 							cursor--;
185 						MustRefresh = 1;
186 						break;
187 					}
188 				case VK_HOME:
189 					if (cursor>0) cursor = 0;
190 					MustRefresh = 1;
191 					break;
192 				case VK_END:
193 					if (cursor<current) cursor = current;
194 					MustRefresh = 1;
195 					break;
196 				case VK_DELETE:
197 					if (current > 0 && current > cursor) {
198 						strcpy(&buf[cursor],&buf[cursor+1]);
199 						current--;
200 						buf[current] = 0;
201 						printit("\r");
202 						for (i = 0; i < current+strlen("telnet>")+1 ;i++)
203 							printit(" ");
204 					}
205 					MustRefresh = 1;
206 					break;
207 				case VK_BACK:
208 					if (cursor > 0 ) {
209 						strcpy(&buf[cursor-1],&buf[cursor]);
210 						current--;
211 						cursor--;
212 						buf[current] = 0;
213 						printit("\r");
214 						for (i = 0; i < current+strlen("telnet>")+1 ;i++)
215 							printit(" ");
216 					}
217 					MustRefresh = 1;
218 					break;
219 
220 				default:
221 					chr = InputRecord.Event.KeyEvent.uChar.AsciiChar;
222 					if (chr == '\r') {
223 						done = TRUE;
224 						continue;
225 					}
226 					if (current >= length-1){
227 						done = TRUE;
228 						continue;
229 					}
230 					if ( isprint (chr) ){
231 						strncpy(temp1,&buf[cursor],79);
232 						strncpy(&buf[cursor+1],temp1,79-(cursor+1));
233 						buf[cursor++]=chr;
234 						current++;
235 						buf[current] = 0;
236 						MustRefresh = 1;
237 					}
238 					break;
239 				}
240 				if (MustRefresh == 1)
241 				{
242 					printit("\rtelnet");
243 					for (i = 0; i <= iEraseLength ;i++)
244 						printit(" ");
245 					printit("\rtelnet>");
246 					printit(buf);
247 					iEraseLength = strlen(buf);
248 					for (i = 0; i < current-cursor; i++)
249 						printit("\b");
250 				}
251 			}
252 		}
253 		buf[current] = 0;
254 		if (strcmp(buf, "")) {
255 			if (cmdhist == NULL) {
256 				cmdhist = new struct cmdHistory;
257 				if (cmdhist == NULL) {
258 					printit ("\nUnable to allocate memory for history buffer -- use the \"flush\" command to clear the buffer.\n");
259 					return cmdhist;
260 				}
261 				strncpy(cmdhist->cmd, buf, 79);
262 				cmdhist->next = NULL;
263 				cmdhist->prev = NULL;
264 			} else {
265 				while (cmdhist->next != NULL)	//  move to the end of the list
266 					cmdhist = cmdhist->next;
267 				cmdhist->next = new struct cmdHistory;
268 				if (cmdhist->next == NULL) {
269 					printit ("\nUnable to allocate memory for history buffer -- use the \"flush\" command to clear the buffer.\n");
270 					return cmdhist;
271 				}
272 				cmdhist->next->prev = cmdhist;	//  previous is where we are now
273 				cmdhist = cmdhist->next;
274 				strncpy(cmdhist->cmd, buf, 79);
275 				cmdhist->next = NULL;
276 			}
277 			while (cmdhist->next)
278 				cmdhist = cmdhist->next;
279 		}
280 		return cmdhist;
281 		///
282 	} else {
283 		WaitForSingleObject( hConsole, INFINITE );
284 		DWORD dwInput;
285 		DWORD OldMode;
286 		GetConsoleMode(hConsole, &OldMode);
287 		SetConsoleMode(hConsole,
288 			OldMode &~ (ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT) );
289 		while (ReadFile(hConsole, &chr, 1, &dwInput, NULL)) {
290 			if (chr == '\r') {
291 				temp[0] = chr;
292 				printit(&temp[0]);
293 				break;
294 			}
295 			if (chr == '\b' && current > 0) {
296 				current--;
297 				printit("\b \b");
298 			}
299 			if (current >= length-1){
300 				break;
301 			}
302 			if ( isprint (chr) ){
303 				temp[0] = chr;
304 				printit(&temp[0]);
305 				buf[current++]=chr;
306 			}
307 		}
308 		buf[current] = 0;
309 		SetConsoleMode(hConsole, OldMode);
310 		return NULL;
311 	}
312 }
313 
314 // AVS ** for fix bug in command 'keys load keymapname' without file
315 // static char keyfile[MAX_PATH*2];
316 
main(int ArgC,char * ArgV[])317 int main(int ArgC, char* ArgV[]) {
318 
319 	CONSOLE_SCREEN_BUFFER_INFO  ConsoleScreenBufferInfo;
320 	GetConsoleScreenBufferInfo(
321 		GetStdHandle(STD_OUTPUT_HANDLE),
322 		&ConsoleScreenBufferInfo
323 		);
324 
325 	char *k;
326 	char startdir[MAX_PATH*2];
327 	char exename[MAX_PATH];
328 
329 	// strncpy(startdir, ArgV[0],MAX_PATH);
330 	// This should be more accurate than using argv[0] (Paul Brannan 9/16/98)
331 	GetModuleFileName(NULL, startdir, sizeof(startdir));
332 
333 	// Get the current console title so it can be set later
334 	// ("Pedro A. Aranda Guti�rrez" <paag@coppi.tid.es>)
335 	TCHAR ConsoleTitle[255];
336 	GetConsoleTitle(ConsoleTitle, sizeof(ConsoleTitle));
337 
338 	k = strrchr(startdir, '\\');
339 	if (k == NULL){						// if the \ character is not found...
340 		strcpy(exename, startdir);
341 		strcpy(startdir,"");			// set the path to nothing
342 	} else {
343 		// end the string after the last '\' to get rid of the file name
344 		strcpy(exename, k+1);
345 		k[1] = 0;
346 	}
347 
348 	printm(0, FALSE, MSG_COPYRIGHT);
349 	printm(0, FALSE, MSG_COPYRIGHT_1);
350 
351 	// set up the ini class
352 	ini.init(startdir, exename);
353 
354 	// Process the command line arguments and connect to a host if necessary
355 	if(ini.Process_Params(ArgC, ArgV)) {
356 		const char *szHost = ini.get_host();
357 		const char *strPort = ini.get_port();
358 		if(!*szHost) {
359 			Telnet MyConnection;
360 			while(telCommandLine(MyConnection));
361 		} else {
362 			Telnet MyConnection;
363 			if(MyConnection.Open(szHost, strPort) == TNPROMPT) {
364 				// still connected
365 				printit("\n");
366 				telCommandLine(MyConnection);
367 			}
368 		}
369 	}
370 	//// (Paul Brannan 5/14/98)
371 
372 	if(ini.get_term_width() != -1 || ini.get_term_height() != -1) {
373 		SetConsoleScreenBufferSize(
374 			GetStdHandle(STD_OUTPUT_HANDLE),	// handle of console screen buffer
375 			ConsoleScreenBufferInfo.dwSize		// new size in character rows and cols.
376 			);
377 		SetConsoleWindowInfo(
378 			GetStdHandle(STD_OUTPUT_HANDLE),	// handle of console screen buffer
379 			TRUE,								// coordinate type flag
380 			&ConsoleScreenBufferInfo.srWindow 	// address of new window rectangle
381 			);
382 	}
383 	SetConsoleTextAttribute(
384 		GetStdHandle(STD_OUTPUT_HANDLE),		// handle of console screen buffer
385 		ConsoleScreenBufferInfo.wAttributes 	// text and background colors
386 		);
387 
388 	// Restore the original console title
389 	// ("Pedro A. Aranda Guti�rrez" <paag@coppi.tid.es>)
390 	SetConsoleTitle(ConsoleTitle);
391 
392 	return 0;
393 }
394 
395 // AVS
396 enum {
397 	BAD_USAGE = -3,
398 		EMPTY_LINE = -2,
399 		INVALID_CMD = -1,
400 		__FIRST_COMMAND = 0,
401 
402 		OPEN = __FIRST_COMMAND,
403 		CLOSE,
404 		KEYS,
405 		QUIT,
406 		HELP,
407 		HELP2,				// there is way for synonims
408 		K_LOAD,				// subcommand of 'keys'
409 		K_SWITCH,			// subcommand of 'keys'
410 		K_DISPLAY,			// subcommand of 'keys'
411 
412 		SET,				// Paul Brannan 5/30/98
413 
414 		SUSPEND,
415 		FASTQUIT,			// Thomas Briggs 8/11/98
416 		CMD_HISTORY,		// crn@ozemail.com.au
417 		CLEAR_HISTORY,		// crn@ozemail.com.au
418 
419 		ALIASES,			// Paul Brannan 1/1/99
420 
421 		__COMMAND_LIST_SIZE	// must be last
422 };
423 
424 
425 struct command {
426 	const char* cmd;				// command
427 	int   minLen,			// minimal length for match
428 		  minParms,			// minimal count of parms
429 		  maxParms;			// maximal -/- (negative disables)
430 	int   isSubCmd,			// is a subcommand - number of wich command
431 		  haveSubCmd;		// have subcommands? 0 or 1
432 	const char* usage;			// text of usage
433 };
434 
435 command cmdList[__COMMAND_LIST_SIZE] = {
436 	{"open",     1,	1,  2,	-1,		0,	"o[pen] host [port]\n"},
437 	{"close",    2,	0,  0,	-1,		0,	NULL},
438 	{"keys",     2,	1,  3,	-1,		1,	"ke[ys] l[oad] keymapname [file]\n"
439 										"ke[ys] d[isplay]\n"
440 										"ke[ys] s[witch] number\n"},
441 	// Ioannou : i change it to q, to be more compatible with unix telnet
442 	{"quit",     1,	0,  0,	-1,		0,	NULL}, // must type it exactly
443 	{"?",        1,	0,  0,	-1,		0,	NULL},
444 	{"help",     1,	0,  0,	-1,		0,	NULL},
445 	{"load",     1,	1,  2,	KEYS,	0,	NULL},
446 	{"switch",   1,	1,  1,	KEYS,	0,	NULL},
447 	{"display",  1,	0,  0,	KEYS,	0,	NULL},
448 	// Paul Brannan 5/30/98
449 	{"set",      3,	0,	2,	-1,		0,	"set will display available groups.\n"
450 										"set groupname will display all variables/values in a group.\n"
451 										"set [variable [value]] will set variable to value.\n"},
452 	// Thomas Briggs 8/11/98
453 	{"z",		1,	0,	0,	-1,		0,	"suspend telnet\n"},
454 	{"\04",		1,	0,	0,	-1,		0,	NULL},
455 	// crn@ozemail.com.au
456 	{"history",	2,	0,	0,	-1,	0,	"show command history"},
457 	{"flush",	2,	0,	0,	-1,	0,	"flush history buffer"},
458 	// Paul Brannan 1/1/99
459 	{"aliases",	5,	0,	0,	-1,		0,	NULL}
460 };
461 
462 // a maximal count of parms
463 #define MAX_PARM_COUNT 3
464 #define MAX_TOKEN_COUNT (MAX_PARM_COUNT+2)
465 
cmdMatch(const char * cmd,const char * token,int tokenLen,int minM)466 static int cmdMatch(const char* cmd, const char* token, int tokenLen, int minM) {
467     if ( tokenLen < minM ) return 0;
468 	// The (unsigned) gets rid of a compiler warning (Paul Brannan 5/25/98)
469     if ( (unsigned)tokenLen > strlen(cmd) ) return 0;
470     if ( strcmp(cmd,token) == 0 ) return 1;
471 
472     int i;
473     for ( i = 0; i < minM; i++ ) if ( cmd[i] != token[i] ) return 0;
474 
475     for ( i = minM; i < tokenLen; i++ ) if ( cmd[i] != token[i] ) return 0;
476 
477     return 1;
478 };
479 
printUsage(int cmd)480 static void printUsage(int cmd) {
481 	if ( cmdList[cmd].usage != NULL ) {
482 		printit(cmdList[cmd].usage);
483 		return;
484 	};
485 	if ( cmdList[cmd].isSubCmd >= 0 ) {
486 		printUsage(cmdList[cmd].isSubCmd);
487 		return;
488 	   }
489 	   printm(0, FALSE, MSG_BADUSAGE);
490 };
491 
tokenizeCommand(char * szCommand,int & argc,char ** argv)492 int tokenizeCommand(char* szCommand, int& argc, char** argv) {
493     char* tokens[MAX_TOKEN_COUNT];
494     char* p;
495     int   args = 0;
496 
497 	if(!szCommand || !*szCommand) return EMPTY_LINE;
498 
499 	// Removed strtok to handle tokens with spaces; this is handled with
500 	// quotes.  (Paul Brannan 3/18/99)
501 	char *token_start = szCommand;
502 	for(p = szCommand;; p++) {
503 		if(*p == '\"') {
504 			char *tmp = p;
505 			for(p++; *p != '\"' && *p != 0; p++);	// Find the next quote
506 			if(*p != 0) strcpy(p, p + 1);			// Remove quote#2
507 			strcpy(tmp, tmp + 1);					// Remove quote#1
508 		}
509 		if(*p == 0 || *p == ' ' || *p == '\t') {
510 			tokens[args] = token_start;
511 			args++;
512 			if(args >= MAX_TOKEN_COUNT) break;		// Break if too many args
513 			token_start = p + 1;
514 			if(*p == 0) break;
515 			*p = 0;
516 		}
517 	}
518 	// while ( (p = strtok((args?NULL:szCommand), " \t")) != NULL && args < MAX_TOKEN_COUNT ) {
519 	// 	tokens[args] = p;
520 	// 	args++;
521 	// };
522 
523     if ( !args ) return EMPTY_LINE;
524     argc = args - 1;
525     args = 0;
526     int curCmd = -1;
527     int ok = -1;
528     while ( ok < 0 ) {
529 		int tokenLen = strlen(tokens[args]);
530 		int match = 0;
531 		for ( int i = 0; i<__COMMAND_LIST_SIZE; i++ ) {
532 			if ( cmdMatch(cmdList[i].cmd, tokens[args], tokenLen, cmdList[i].minLen) ) {
533 				if (argc < cmdList[i].minParms || argc > cmdList[i].maxParms) {
534 					printUsage(i);
535 					return BAD_USAGE;
536 				};
537 				if ( cmdList[i].haveSubCmd && curCmd == cmdList[i].isSubCmd) {
538 					curCmd = i;
539 					args++;
540 					argc--;
541 					match = 1;
542 					break;
543 				};
544 				if ( curCmd == cmdList[i].isSubCmd ) {
545 					ok = i;
546 					match = 1;
547 					break;
548 				};
549 				printUsage(i);
550 				return BAD_USAGE;
551 			};
552 		};
553 		if ( !match ) {
554 			if ( curCmd < 0 ) return INVALID_CMD;
555 			printUsage(curCmd);
556 			return -3;
557 		};
558     };
559 
560     for ( int i = 0; i<argc; i++ ) {
561         argv[i] = tokens[i+args+1];
562     };
563     return ok;
564 
565 };
566 
telCommandLine(Telnet & MyConnection)567 int telCommandLine (Telnet &MyConnection){
568 #define HISTLENGTH 25
569 	int i, retval;
570 	char* Parms[MAX_PARM_COUNT];
571 	char szCommand[80];
572 	int bDone = 0;
573 	char *extitle, *newtitle;
574 	struct cmdHistory *cmdhist;
575 	cmdhist = NULL;
576 
577 	// printit("\n");  // crn@ozemail.com.au 14/12/98
578 	while (!bDone){
579 		// printit("\n"); // Paul Brannan 5/25/98
580 		printit( "telnet>");
581 		cmdhist = cfgets (szCommand, 79, cmdhist);
582 		printit( "\n");
583 
584 		strlwr(szCommand);  // convert command line to lower
585 		// i = sscanf(szCommand,"%80s %80s %80s %80s", szCmd, szArg1, szArg2, szArg3);
586 		switch ( tokenizeCommand(szCommand, i, Parms) ) {
587 		case BAD_USAGE:   break;
588 		case EMPTY_LINE:
589 			if(MyConnection.Resume() == TNPROMPT) {
590 				printit("\n");
591 				break;
592 			}
593 			else
594 			 	return 1;
595 		case INVALID_CMD:
596 			printm(0, FALSE, MSG_INVCMD);
597 			break;
598 		case OPEN:
599 			if (i == 1)
600 				retval = MyConnection.Open(Parms[0], "23");
601 			else
602 				retval = MyConnection.Open(Parms[0], Parms[1]);
603 			if(retval != TNNOCON && retval != TNPROMPT) return 1;
604 			if(retval == TNPROMPT) printit("\n");
605 			break;
606 		case CLOSE:
607 			MyConnection.Close();
608 			break;
609 		case FASTQUIT: // Thomas Briggs 8/11/98
610 		case QUIT:
611 			MyConnection.Close();
612 			bDone = 1;
613 			break;
614 		case HELP:
615 		case HELP2:
616 			printm(0, FALSE, MSG_HELP);
617 			printm(0, FALSE, MSG_HELP_1);
618 			break;
619 			// case KEYS: we should never get it
620 		case K_LOAD:
621 			if ( i == 1 ) {
622 				// Ioannou : changed to ini.get_keyfile()
623 				if(MyConnection.LoadKeyMap( ini.get_keyfile(), Parms[0]) != 1)
624 					printit("Error loading keymap.\n");
625 				break;
626 			};
627 			if(MyConnection.LoadKeyMap( Parms[1], Parms[0]) != 1)
628 				printit("Error loading keymap.\n");
629 			break;
630 		case K_DISPLAY:
631 			MyConnection.DisplayKeyMap();
632 			break;
633 		case K_SWITCH:
634 			MyConnection.SwitchKeyMap(atoi(Parms[0]));
635 			break;
636 
637 			// Paul Brannan 5/30/98
638 		case SET:
639 			if(i == 0) {
640 				printit("Available groups:\n");		// Print out groups
641 				ini.print_groups();					// (Paul Brannan 9/3/98)
642 			} else if(i == 1) {
643 				ini.print_vars(Parms[0]);
644 			} else if(i >= 2) {
645 				ini.set_value(Parms[0], Parms[1]);
646 				// FIX ME !!! Ioannou: here we must call the parser routine for
647 				// wrap line, not the ini.set_value
648 				//  something like Parser.ConLineWrap(Wrap_Line);
649 			}
650 			break;
651 
652 		case SUSPEND: // Thomas Briggs 8/11/98
653 
654 			// remind the user we're suspended -crn@ozemail.com.au 15/12/98
655 			extitle = new char[128];
656 			GetConsoleTitle (extitle, 128);
657 
658 			newtitle = new char[128+sizeof("[suspended]")];
659 			strcpy(newtitle, extitle);
660 			strncat(newtitle, "[suspended]", 128+sizeof("[suspended]"));
661 			if(ini.get_set_title()) SetConsoleTitle (newtitle);
662 			delete[] newtitle;
663 
664 			if (getenv("comspec") == NULL) {
665 				switch (GetWin32Version()) {
666 				case 2:		// 'cmd' is faster than 'command' in NT -crn@ozemail.com.au
667 					system ("cmd");
668 					break;
669 				default:
670 					system ("command");
671 					break;
672 				}
673 			} else {
674 				system(getenv("comspec"));
675 			}
676 
677 			if(ini.get_set_title()) SetConsoleTitle (extitle);
678 			delete[] extitle;
679 			///
680 
681 			break;
682 
683 		case CMD_HISTORY:	//crn@ozemail.com.au
684 			if (cmdhist != NULL) {
685 				while (cmdhist->prev != NULL)
686 					cmdhist = cmdhist->prev;	//rewind
687 				printf ("Command history:\n");
688 				while (1) {
689 					printf ("\t%s\n", cmdhist->cmd);
690 
691 					if (cmdhist->next != NULL)
692 						cmdhist = cmdhist->next;
693 					else
694 						break;
695 				}
696 			} else
697 				printf ("No command history available.\n");
698 
699 			break;
700 
701 		case CLEAR_HISTORY:	//crn@ozemail.com.au
702 			if (cmdhist != NULL) {
703 				while (cmdhist->next != NULL)
704 					cmdhist = cmdhist->next;	//fast forward
705 				while (cmdhist->prev != NULL) {
706 					cmdhist = cmdhist->prev;
707 					delete cmdhist->next;
708 				}
709 				delete cmdhist;
710 				cmdhist = NULL;
711 				printf ("Command history cleared.\n");
712 			} else
713 				printf ("No command history available.\n");
714 
715 		case ALIASES: // Paul Brannan 1/1/99
716 			ini.print_aliases();
717 			break;
718 
719 		default: // paranoik
720 			printm(0, FALSE, MSG_INVCMD);
721 			break;
722 		}
723 
724 	}
725 
726 	return 0;
727 }
728