1 ///////////////////////////////////////////////////////////////////////////////
2 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998-2000 Paul Brannan
4 //Copyright (C) 1998 I.Ioannou
5 //Copyright (C) 1997 Brad Johnson
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.
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.
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.
24 ///////////////////////////////////////////////////////////////////////////
27 // Written by Paul Brannan <pbranna@clemson.edu>
28 // Last modified August 30, 1998
30 // This is a class designed for use with Brad Johnson's Console Telnet
31 // see the file tnconfig.h for more information
38 #include <sys/types.h>
42 // Turn off the "forcing value to bool 'true' or 'false'" warning
44 #pragma warning(disable: 4800)
47 // This is the ini variable that is used for everybody
51 // set all default values
57 default_config
[0] = '\0';
58 strcpy(printer_name
, "LPT1");
65 eightbit_ansi
= FALSE
;
67 disable_break
= FALSE
;
70 preserve_colors
= FALSE
;
72 lock_linewrap
= FALSE
;
77 keyboard_paste
= FALSE
;
100 strcpy(escape_key
, "]");
101 strcpy(scrollback_key
, "[");
102 strcpy(dial_key
, "\\");
103 strcpy(default_config
, "ANSI");
104 strcpy(term
, "ansi");
106 strcpy(scroll_mode
, "DUMP");
118 TConfig::~TConfig() {
120 for(int j
= 0; j
< alias_total
; j
++) delete[] aliases
[j
];
185 MAX_INI_VARS
// must be last
188 struct ini_variable
{
189 const char *name
; // variable name
190 const char *section
; // name of ini file section the variable is in
191 enum ini_data_type data_type
; // type of data
192 void *ini_data
; // pointer to data
193 int max_size
; // max size if string
196 // Note: default values are set in the constructor, TConfig()
197 ini_variable ini_varlist
[MAX_INI_VARS
];
209 MAX_INI_GROUPS
// Must be last
212 char *ini_groups
[MAX_INI_GROUPS
];
214 void TConfig::init_varlist() {
215 static const ini_variable static_ini_varlist
[MAX_INI_VARS
] = {
216 {"Inifile", NULL
, INI_STRING
, &inifile
, sizeof(inifile
)},
217 {"Keyfile", "Keyboard", INI_STRING
, &keyfile
, sizeof(keyfile
)},
218 {"Dumpfile", "Terminal", INI_STRING
, &dumpfile
, sizeof(dumpfile
)},
219 {"Default_Config","Keyboard", INI_STRING
, &default_config
, sizeof(default_config
)},
220 {"Term", "Terminal", INI_STRING
, &term
, sizeof(term
)},
221 {"Input_Redir", "Terminal", INI_INT
, &input_redir
, 0},
222 {"Output_Redir","Terminal", INI_INT
, &output_redir
, 0},
223 {"Strip_Redir", "Terminal", INI_BOOL
, &strip_redir
, 0},
224 {"Destructive_Backspace","Terminal",INI_BOOL
, &dstrbksp
, 0},
225 {"EightBit_Ansi","Terminal", INI_BOOL
, &eightbit_ansi
, 0},
226 {"VT100_Mode", "Terminal", INI_BOOL
, &vt100_mode
, 0},
227 {"Disable_Break","Terminal", INI_BOOL
, &disable_break
, 0},
228 {"Speaker_Beep","Terminal", INI_BOOL
, &speaker_beep
, 0},
229 {"Beep", "Terminal", INI_BOOL
, &do_beep
, 0},
230 {"Preserve_Colors","Terminal", INI_BOOL
, &preserve_colors
, 0},
231 {"Wrap_Line", "Terminal", INI_BOOL
, &wrapline
, 0},
232 {"Lock_linewrap","Terminal", INI_BOOL
, &lock_linewrap
, 0},
233 {"Fast_Write", "Terminal", INI_BOOL
, &fast_write
, 0},
234 {"Term_Width", "Terminal", INI_INT
, &term_width
, 0},
235 {"Term_Height", "Terminal", INI_INT
, &term_height
, 0},
236 {"Window_Width","Terminal", INI_INT
, &window_width
, 0},
237 {"Window_Height","Terminal", INI_INT
, &window_height
, 0},
238 {"Wide_Enable", "Terminal", INI_BOOL
, &wide_enable
, 0},
239 {"Ctrlbreak_as_Ctrlc","Keyboard", INI_BOOL
, &ctrlbreak_as_ctrlc
, 0},
240 {"Buffer_Size", "Terminal", INI_INT
, &buffer_size
, 0},
241 {"Set_Title", "Terminal", INI_BOOL
, &set_title
, 0},
242 {"Blink_bg", "Colors", INI_INT
, &blink_bg
, 0},
243 {"Blink_fg", "Colors", INI_INT
, &blink_fg
, 0},
244 {"Underline_bg","Colors", INI_INT
, &underline_bg
, 0},
245 {"Underline_fg","Colors", INI_INT
, &underline_fg
, 0},
246 {"UlBlink_bg", "Colors", INI_INT
, &ulblink_bg
, 0},
247 {"UlBlink_fg", "Colors", INI_INT
, &ulblink_fg
, 0},
248 {"Normal_bg", "Colors", INI_INT
, &normal_bg
, 0},
249 {"Normal_fg", "Colors", INI_INT
, &normal_fg
, 0},
250 {"Scroll_bg", "Colors", INI_INT
, &scroll_bg
, 0},
251 {"Scroll_fg", "Colors", INI_INT
, &scroll_fg
, 0},
252 {"Status_bg", "Colors", INI_INT
, &status_bg
, 0},
253 {"Status_fg", "Colors", INI_INT
, &status_fg
, 0},
254 {"Enable_Mouse","Mouse", INI_BOOL
, &enable_mouse
, 0},
255 {"Printer_Name","Printer", INI_STRING
, &printer_name
, sizeof(printer_name
)},
256 {"Escape_Key", "Keyboard", INI_STRING
, &escape_key
, 1},
257 {"Scrollback_Key","Keyboard", INI_STRING
, &scrollback_key
, 1},
258 {"Dial_Key", "Keyboard", INI_STRING
, &dial_key
, 1},
259 {"Alt_Erase", "Keyboard", INI_BOOL
, &alt_erase
, 0},
260 {"Keyboard_Paste","Keyboard", INI_BOOL
, &keyboard_paste
, 0},
261 {"Scroll_Mode", "Scrollback", INI_STRING
, &scroll_mode
, sizeof(scroll_mode
)},
262 {"Scroll_Size", "Scrollback", INI_INT
, &scroll_size
, 0},
263 {"Scroll_Enable","Scrollback", INI_BOOL
, &scroll_enable
, 0},
264 {"Scriptname", "Scripting", INI_STRING
, &scriptname
, sizeof(scriptname
)},
265 {"Script_enable","Scripting", INI_BOOL
, &script_enable
, 0},
266 {"Netpipe", "Pipes", INI_STRING
, &netpipe
, sizeof(netpipe
)},
267 {"Iopipe", "Pipes", INI_STRING
, &iopipe
, sizeof(iopipe
)}
270 static const char *static_ini_groups
[MAX_INI_GROUPS
] = {
281 memcpy(ini_varlist
, static_ini_varlist
, sizeof(ini_varlist
));
282 memcpy(ini_groups
, static_ini_groups
, sizeof(ini_groups
));
285 void TConfig::init(char *dirname
, char *execname
) {
286 // Copy temporary dirname to permanent startdir
287 strncpy(startdir
, dirname
, sizeof(startdir
));
288 startdir
[sizeof(startdir
) - 1] = 0;
290 // Copy temp execname to permanent exename (Thomas Briggs 12/7/98)
291 strncpy(exename
, execname
, sizeof(exename
));
292 exename
[sizeof(exename
) - 1] = 0;
294 // Initialize INI file
298 // Note that this must be done early, so error messages will be printed
302 // Initialize aliases (Paul Brannan 1/1/99)
305 // Make sure the file that we're trying to work with exists
306 int iResult
= access(inifile
, 04);
308 // Thomas Briggs 9/14/98
310 // Tell the user what file we are reading
311 // We cannot print any messages before initializing telnet_redir
312 printm(0, FALSE
, MSG_CONFIG
, inifile
);
314 // Tell the user that the file doesn't exist, but later read the
315 // file anyway simply to populate the defaults
316 printm(0, FALSE
, MSG_NOINI
, inifile
);
318 init_vars(); // Initialize misc. vars
319 keyfile_init(); // Initialize keyfile
322 // Alias support (Paul Brannan 1/1/99)
323 void TConfig::init_aliases() {
327 // Find the correct buffer size
328 // FIX ME!! some implementations of Mingw32 don't have a
329 // GetPrivateProfileSecionNames function. What do we do about this?
332 int size
=1024, Result
= 0;
334 buffer
= new char[size
];
335 Result
= GetPrivateProfileSectionNames(buffer
, size
, inifile
);
336 if(Result
< size
- 2) break;
345 // Find the maximum number of aliases
348 for(tmp
= buffer
; *tmp
!= 0; tmp
+= strlen(tmp
) + 1)
351 aliases
= new char*[max
];
353 // Load the aliases into an array
354 for(tmp
= buffer
; *tmp
!= 0; tmp
+= strlen(tmp
) + 1) {
356 for(int j
= 0; j
< MAX_INI_GROUPS
; j
++) {
357 if(!stricmp(ini_groups
[j
], tmp
)) flag
= 1;
360 aliases
[alias_total
] = new char[strlen(tmp
)+1];
361 strcpy(aliases
[alias_total
], tmp
);
369 void TConfig::print_aliases() {
370 for(int j
= 0; j
< alias_total
; j
++) {
372 set_string(alias_name
, aliases
[j
], sizeof(alias_name
));
373 for(unsigned int i
= strlen(alias_name
); i
< sizeof(alias_name
) - 1; i
++)
375 alias_name
[sizeof(alias_name
) - 1] = 0;
377 if((j
% 4) == 3) printit("\n");
382 bool find_alias(const char *alias_name
) {
386 void TConfig::print_vars() {
388 for(j
= 0; j
< MAX_INI_VARS
; j
++) {
389 if(print_value(ini_varlist
[j
].name
) > 40) printit("\n");
390 else if(j
% 2) printit("\n");
393 if(j
% 2) printit("\n");
396 // Paul Brannan 9/3/98
397 void TConfig::print_vars(char *s
) {
398 if(!strnicmp(s
, "all", 3)) { // Print out all vars
403 // See if the group exists
405 for(j
= 0, flag
= 0; j
< MAX_INI_GROUPS
; j
++)
406 if(!stricmp(ini_groups
[j
], s
)) break;
407 // If not, print out the value of the variable by that name
408 if(j
== MAX_INI_GROUPS
) {
414 // Print out the vars in the given group
416 for(j
= 0; j
< MAX_INI_VARS
; j
++) {
417 if(ini_varlist
[j
].section
== NULL
) continue;
418 if(!stricmp(ini_varlist
[j
].section
, s
)) {
419 if(print_value(ini_varlist
[j
].name
) > 40) printit("\n");
420 else if(count
% 2) printit("\n");
425 if(count
% 2) printit("\n");
428 // Paul Brannan 9/3/98
429 void TConfig::print_groups() {
430 for(int j
= 0; j
< MAX_INI_GROUPS
; j
++) {
432 set_string(group_name
, ini_groups
[j
], sizeof(group_name
));
433 for(unsigned int i
= strlen(group_name
); i
< sizeof(group_name
) - 1; i
++)
435 group_name
[sizeof(group_name
) - 1] = 0;
437 if((j
% 4) == 3) printit("\n");
442 // Ioannou : The index in the while causes segfaults if there is no match
443 // changes to for(), and strcmp to stricmp (prompt gives rong names)
445 bool TConfig::set_value(const char *var
, const char *value
) {
447 //while(strcmp(var, ini_varlist[j].name) && j < MAX_INI_VARS) j++;
448 for (int j
= 0; j
< MAX_INI_VARS
; j
++)
450 if (stricmp(var
, ini_varlist
[j
].name
) == 0)
452 switch(ini_varlist
[j
].data_type
) {
454 set_string((char *)ini_varlist
[j
].ini_data
, value
,
455 ini_varlist
[j
].max_size
);
458 *(int *)ini_varlist
[j
].ini_data
= atoi(value
);
461 set_bool((bool *)ini_varlist
[j
].ini_data
, value
);
471 int TConfig::print_value(const char *var
) {
473 //while(strcmp(var, ini_varlist[j].name) && j < MAX_INI_VARS) j++;
475 for (int j
= 0; j
< MAX_INI_VARS
; j
++)
477 if (stricmp(var
, ini_varlist
[j
].name
) == 0)
480 set_string(var_name
, var
, sizeof(var_name
));
481 for(unsigned int i
= strlen(var_name
); i
< sizeof(var_name
) - 1; i
++)
483 var_name
[sizeof(var_name
) - 1] = 0;
484 Result
= sizeof(var_name
);
488 Result
= Result
/ 8 + 8;
490 switch(ini_varlist
[j
].data_type
) {
492 printit((char *)ini_varlist
[j
].ini_data
);
493 Result
+= strlen((char *)ini_varlist
[j
].ini_data
);
496 char buffer
[20]; // this may not be safe
497 // Ioannou : Paul this was _itoa, but Borland needs itoa !!
498 itoa(*(int *)ini_varlist
[j
].ini_data
, buffer
, 10);
500 Result
+= strlen(buffer
);
503 if(*(bool *)ini_varlist
[j
].ini_data
== true) {
518 void TConfig::init_vars() {
520 for(int j
= 0; j
< MAX_INI_VARS
; j
++) {
521 if(ini_varlist
[j
].section
!= NULL
) {
522 GetPrivateProfileString(ini_varlist
[j
].section
, ini_varlist
[j
].name
, "",
523 buffer
, sizeof(buffer
), inifile
);
524 if(*buffer
!= 0) set_value(ini_varlist
[j
].name
, buffer
);
529 void TConfig::inifile_init() {
530 // B. K. Oxley 9/16/98
531 char* env_telnet_ini
= getenv (ENV_TELNET_INI
);
532 if (env_telnet_ini
&& *env_telnet_ini
) {
533 strncpy (inifile
, env_telnet_ini
, sizeof(inifile
));
537 strcpy(inifile
, startdir
);
538 if (sizeof(inifile
) >= strlen(inifile
)+strlen("telnet.ini")) {
539 strcat(inifile
,"telnet.ini"); // add the default filename to the path
541 // if there is not enough room set the path to nothing
546 void TConfig::keyfile_init() {
547 // check to see if there is a key config file environment variable.
549 if ((k
= getenv(ENV_TELNET_CFG
)) == NULL
){
550 // if there is no environment variable
551 GetPrivateProfileString("Keyboard", "Keyfile", "", keyfile
,
552 sizeof(keyfile
), inifile
);
553 if(keyfile
== 0 || *keyfile
== 0) {
554 // and there is no profile string
555 strcpy(keyfile
, startdir
);
556 if (sizeof(keyfile
) >= strlen(keyfile
)+strlen("telnet.cfg")) {
559 strcat(keyfile
,"telnet.cfg"); // add the default filename to the path
560 if(stat(keyfile
, &buf
) != 0) {
561 char *s
= keyfile
+ strlen(keyfile
) - strlen("telnet.cfg");
562 strcpy(s
, "keys.cfg");
565 // if there is not enough room set the path to nothing
569 // Vassili Bourdo (vassili_bourdo@softhome.net)
571 // check that keyfile really exists
572 if( access(keyfile
,04) == -1 ) {
574 char pathbuf
[MAX_PATH
], *fn
;
575 //substitute keyfile path with startdir path
576 if((fn
= strrchr(keyfile
,'\\'))) strcpy(keyfile
,fn
);
577 strcat(strcpy(pathbuf
,startdir
),keyfile
);
578 //check that startdir\keyfile does exist
579 if( access(pathbuf
,04) == -1 ) {
581 //so, look for it in all paths
582 _searchenv(keyfile
, "PATH", pathbuf
);
583 if( *pathbuf
== 0 ) //no luck - revert it to INI file value
584 GetPrivateProfileString("Keyboard", "Keyfile", "",
585 keyfile
, sizeof(keyfile
), inifile
);
587 strcpy(keyfile
, pathbuf
);
594 // set the keyfile to the value of the environment variable
595 strncpy(keyfile
, k
, sizeof(keyfile
));
599 void TConfig::redir_init() {
600 // check to see if the environment variable 'TELNET_REDIR' is not 0;
601 char* p
= getenv(ENV_TELNET_REDIR
);
603 input_redir
= output_redir
= atoi(p
);
604 if((p
= getenv(ENV_INPUT_REDIR
))) input_redir
= atoi(p
);
605 if((p
= getenv(ENV_OUTPUT_REDIR
))) output_redir
= atoi(p
);
607 input_redir
= output_redir
= GetPrivateProfileInt("Terminal",
608 "Telnet_Redir", 0, inifile
);
609 input_redir
= GetPrivateProfileInt("Terminal",
610 "Input_Redir", input_redir
, inifile
);
611 output_redir
= GetPrivateProfileInt("Terminal",
612 "Output_Redir", output_redir
, inifile
);
614 if ((input_redir
> 1) || (output_redir
> 1))
615 setlocale(LC_CTYPE
,"");
616 // tell isprint() to not ignore local characters, if the environment
617 // variable "LANG" has a valid value (e.g. LANG=de for german characters)
618 // and the file LOCALE.BLL is installed somewhere along the PATH.
621 // Modified not to use getopt() by Paul Brannan 12/17/98
622 bool TConfig::Process_Params(int argc
, char *argv
[]) {
624 char *optarg
= argv
[optind
];
627 while(optind
< argc
) {
628 if(argv
[optind
][0] != '-') break;
632 if(argv
[optind
][2] == 0)
633 optarg
= argv
[++optind
];
635 optarg
= &argv
[optind
][2];
640 set_string(dumpfile
, optarg
, sizeof(dumpfile
));
641 printm(0, FALSE
, MSG_DUMPFILE
, dumpfile
);
643 // added support for setting options on the command-line
644 // (Paul Brannan 7/31/98)
648 for(j
= 0; optarg
[j
] != ' ' && optarg
[j
] != '=' && optarg
[j
] != 0; j
++);
650 printm(0, FALSE
, MSG_USAGE
); // print a usage message
651 printm(0, FALSE
, MSG_USAGE_1
);
655 if(!set_value(optarg
, &optarg
[j
+1]))
656 printm(0, FALSE
, MSG_BADVAL
, optarg
);
660 printm(0, FALSE
, MSG_USAGE
); // print a usage message
661 printm(0, FALSE
, MSG_USAGE_1
);
666 set_string(host
, argv
[optind
++], sizeof(host
)-1);
667 if(!strnicmp(host
, "telnet://", 9)) {
668 // we have a URL to parse
671 for(s
= host
+9, t
= host
; *s
!= 0; *(t
++) = *(s
++));
673 for(s
= host
; *s
!= ':' && *s
!= 0; s
++);
680 port
= argv
[optind
++];
685 void TConfig::set_string(char *dest
, const char *src
, const int length
) {
687 strncpy(dest
, src
, l
);
688 // dest[length-1] = '\0';
689 // Ioannou : this messes strings - is this really needed ?
690 // The target string, dest, might not be null-terminated
691 // if the length of src is length or more.
692 // it should be dest[length] = '\0' for strings with length 1
693 // (Escape_string etc), but doesn't work with others (like host).
694 // dest is long enough to avoid this in all the tested cases
697 // Ioannou : ignore case for true or on
699 void TConfig::set_bool(bool *boolval
, const char *str
) {
700 if(!stricmp(str
, "true")) *boolval
= true;
701 else if(!stricmp(str
, "on")) *boolval
= true;
702 else *boolval
= (bool)atoi(str
);