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
35 // Turn off the "forcing value to bool 'true' or 'false'" warning
37 #pragma warning(disable: 4800)
40 // This is the ini variable that is used for everybody
44 // set all default values
50 default_config
[0] = '\0';
51 strcpy(printer_name
, "LPT1");
58 eightbit_ansi
= FALSE
;
60 disable_break
= FALSE
;
63 preserve_colors
= FALSE
;
65 lock_linewrap
= FALSE
;
70 keyboard_paste
= FALSE
;
93 strcpy(escape_key
, "]");
94 strcpy(scrollback_key
, "[");
95 strcpy(dial_key
, "\\");
96 strcpy(default_config
, "ANSI");
99 strcpy(scroll_mode
, "DUMP");
111 TConfig::~TConfig() {
113 for(int j
= 0; j
< alias_total
; j
++) delete[] aliases
[j
];
178 MAX_INI_VARS
// must be last
181 struct ini_variable
{
182 const char *name
; // variable name
183 const char *section
; // name of ini file section the variable is in
184 enum ini_data_type data_type
; // type of data
185 void *ini_data
; // pointer to data
186 int max_size
; // max size if string
189 // Note: default values are set in the constructor, TConfig()
190 ini_variable ini_varlist
[MAX_INI_VARS
];
202 MAX_INI_GROUPS
// Must be last
205 char *ini_groups
[MAX_INI_GROUPS
];
207 void TConfig::init_varlist() {
208 static const ini_variable static_ini_varlist
[MAX_INI_VARS
] = {
209 {"Inifile", NULL
, INI_STRING
, &inifile
, sizeof(inifile
)},
210 {"Keyfile", "Keyboard", INI_STRING
, &keyfile
, sizeof(keyfile
)},
211 {"Dumpfile", "Terminal", INI_STRING
, &dumpfile
, sizeof(dumpfile
)},
212 {"Default_Config","Keyboard", INI_STRING
, &default_config
, sizeof(default_config
)},
213 {"Term", "Terminal", INI_STRING
, &term
, sizeof(term
)},
214 {"Input_Redir", "Terminal", INI_INT
, &input_redir
, 0},
215 {"Output_Redir","Terminal", INI_INT
, &output_redir
, 0},
216 {"Strip_Redir", "Terminal", INI_BOOL
, &strip_redir
, 0},
217 {"Destructive_Backspace","Terminal",INI_BOOL
, &dstrbksp
, 0},
218 {"EightBit_Ansi","Terminal", INI_BOOL
, &eightbit_ansi
, 0},
219 {"VT100_Mode", "Terminal", INI_BOOL
, &vt100_mode
, 0},
220 {"Disable_Break","Terminal", INI_BOOL
, &disable_break
, 0},
221 {"Speaker_Beep","Terminal", INI_BOOL
, &speaker_beep
, 0},
222 {"Beep", "Terminal", INI_BOOL
, &do_beep
, 0},
223 {"Preserve_Colors","Terminal", INI_BOOL
, &preserve_colors
, 0},
224 {"Wrap_Line", "Terminal", INI_BOOL
, &wrapline
, 0},
225 {"Lock_linewrap","Terminal", INI_BOOL
, &lock_linewrap
, 0},
226 {"Fast_Write", "Terminal", INI_BOOL
, &fast_write
, 0},
227 {"Term_Width", "Terminal", INI_INT
, &term_width
, 0},
228 {"Term_Height", "Terminal", INI_INT
, &term_height
, 0},
229 {"Window_Width","Terminal", INI_INT
, &window_width
, 0},
230 {"Window_Height","Terminal", INI_INT
, &window_height
, 0},
231 {"Wide_Enable", "Terminal", INI_BOOL
, &wide_enable
, 0},
232 {"Ctrlbreak_as_Ctrlc","Keyboard", INI_BOOL
, &ctrlbreak_as_ctrlc
, 0},
233 {"Buffer_Size", "Terminal", INI_INT
, &buffer_size
, 0},
234 {"Set_Title", "Terminal", INI_BOOL
, &set_title
, 0},
235 {"Blink_bg", "Colors", INI_INT
, &blink_bg
, 0},
236 {"Blink_fg", "Colors", INI_INT
, &blink_fg
, 0},
237 {"Underline_bg","Colors", INI_INT
, &underline_bg
, 0},
238 {"Underline_fg","Colors", INI_INT
, &underline_fg
, 0},
239 {"UlBlink_bg", "Colors", INI_INT
, &ulblink_bg
, 0},
240 {"UlBlink_fg", "Colors", INI_INT
, &ulblink_fg
, 0},
241 {"Normal_bg", "Colors", INI_INT
, &normal_bg
, 0},
242 {"Normal_fg", "Colors", INI_INT
, &normal_fg
, 0},
243 {"Scroll_bg", "Colors", INI_INT
, &scroll_bg
, 0},
244 {"Scroll_fg", "Colors", INI_INT
, &scroll_fg
, 0},
245 {"Status_bg", "Colors", INI_INT
, &status_bg
, 0},
246 {"Status_fg", "Colors", INI_INT
, &status_fg
, 0},
247 {"Enable_Mouse","Mouse", INI_BOOL
, &enable_mouse
, 0},
248 {"Printer_Name","Printer", INI_STRING
, &printer_name
, sizeof(printer_name
)},
249 {"Escape_Key", "Keyboard", INI_STRING
, &escape_key
, 1},
250 {"Scrollback_Key","Keyboard", INI_STRING
, &scrollback_key
, 1},
251 {"Dial_Key", "Keyboard", INI_STRING
, &dial_key
, 1},
252 {"Alt_Erase", "Keyboard", INI_BOOL
, &alt_erase
, 0},
253 {"Keyboard_Paste","Keyboard", INI_BOOL
, &keyboard_paste
, 0},
254 {"Scroll_Mode", "Scrollback", INI_STRING
, &scroll_mode
, sizeof(scroll_mode
)},
255 {"Scroll_Size", "Scrollback", INI_INT
, &scroll_size
, 0},
256 {"Scroll_Enable","Scrollback", INI_BOOL
, &scroll_enable
, 0},
257 {"Scriptname", "Scripting", INI_STRING
, &scriptname
, sizeof(scriptname
)},
258 {"Script_enable","Scripting", INI_BOOL
, &script_enable
, 0},
259 {"Netpipe", "Pipes", INI_STRING
, &netpipe
, sizeof(netpipe
)},
260 {"Iopipe", "Pipes", INI_STRING
, &iopipe
, sizeof(iopipe
)}
263 static const char *static_ini_groups
[MAX_INI_GROUPS
] = {
274 memcpy(ini_varlist
, static_ini_varlist
, sizeof(ini_varlist
));
275 memcpy(ini_groups
, static_ini_groups
, sizeof(ini_groups
));
278 void TConfig::init(char *dirname
, char *execname
) {
279 // Copy temporary dirname to permanent startdir
280 strncpy(startdir
, dirname
, sizeof(startdir
));
281 startdir
[sizeof(startdir
) - 1] = 0;
283 // Copy temp execname to permanent exename (Thomas Briggs 12/7/98)
284 strncpy(exename
, execname
, sizeof(exename
));
285 exename
[sizeof(exename
) - 1] = 0;
287 // Initialize INI file
291 // Note that this must be done early, so error messages will be printed
295 // Initialize aliases (Paul Brannan 1/1/99)
298 // Make sure the file that we're trying to work with exists
299 int iResult
= access(inifile
, 04);
301 // Thomas Briggs 9/14/98
303 // Tell the user what file we are reading
304 // We cannot print any messages before initializing telnet_redir
305 printm(0, FALSE
, MSG_CONFIG
, inifile
);
307 // Tell the user that the file doesn't exist, but later read the
308 // file anyway simply to populate the defaults
309 printm(0, FALSE
, MSG_NOINI
, inifile
);
311 init_vars(); // Initialize misc. vars
312 keyfile_init(); // Initialize keyfile
315 // Alias support (Paul Brannan 1/1/99)
316 void TConfig::init_aliases() {
320 // Find the correct buffer size
321 // FIX ME!! some implementations of Mingw32 don't have a
322 // GetPrivateProfileSecionNames function. What do we do about this?
325 int size
=1024, Result
= 0;
327 buffer
= new char[size
];
328 Result
= GetPrivateProfileSectionNames(buffer
, size
, inifile
);
329 if(Result
< size
- 2) break;
338 // Find the maximum number of aliases
341 for(tmp
= buffer
; *tmp
!= 0; tmp
+= strlen(tmp
) + 1)
344 aliases
= new char*[max
];
346 // Load the aliases into an array
347 for(tmp
= buffer
; *tmp
!= 0; tmp
+= strlen(tmp
) + 1) {
349 for(int j
= 0; j
< MAX_INI_GROUPS
; j
++) {
350 if(!stricmp(ini_groups
[j
], tmp
)) flag
= 1;
353 aliases
[alias_total
] = new char[strlen(tmp
)+1];
354 strcpy(aliases
[alias_total
], tmp
);
362 void TConfig::print_aliases() {
363 for(int j
= 0; j
< alias_total
; j
++) {
365 set_string(alias_name
, aliases
[j
], sizeof(alias_name
));
366 for(unsigned int i
= strlen(alias_name
); i
< sizeof(alias_name
) - 1; i
++)
368 alias_name
[sizeof(alias_name
) - 1] = 0;
370 if((j
% 4) == 3) printit("\n");
375 bool find_alias(const char *alias_name
) {
379 void TConfig::print_vars() {
381 for(j
= 0; j
< MAX_INI_VARS
; j
++) {
382 if(print_value(ini_varlist
[j
].name
) > 40) printit("\n");
383 else if(j
% 2) printit("\n");
386 if(j
% 2) printit("\n");
389 // Paul Brannan 9/3/98
390 void TConfig::print_vars(char *s
) {
391 if(!strnicmp(s
, "all", 3)) { // Print out all vars
396 // See if the group exists
398 for(j
= 0, flag
= 0; j
< MAX_INI_GROUPS
; j
++)
399 if(!stricmp(ini_groups
[j
], s
)) break;
400 // If not, print out the value of the variable by that name
401 if(j
== MAX_INI_GROUPS
) {
407 // Print out the vars in the given group
409 for(j
= 0; j
< MAX_INI_VARS
; j
++) {
410 if(ini_varlist
[j
].section
== NULL
) continue;
411 if(!stricmp(ini_varlist
[j
].section
, s
)) {
412 if(print_value(ini_varlist
[j
].name
) > 40) printit("\n");
413 else if(count
% 2) printit("\n");
418 if(count
% 2) printit("\n");
421 // Paul Brannan 9/3/98
422 void TConfig::print_groups() {
423 for(int j
= 0; j
< MAX_INI_GROUPS
; j
++) {
425 set_string(group_name
, ini_groups
[j
], sizeof(group_name
));
426 for(unsigned int i
= strlen(group_name
); i
< sizeof(group_name
) - 1; i
++)
428 group_name
[sizeof(group_name
) - 1] = 0;
430 if((j
% 4) == 3) printit("\n");
435 // Ioannou : The index in the while causes segfaults if there is no match
436 // changes to for(), and strcmp to stricmp (prompt gives rong names)
438 bool TConfig::set_value(const char *var
, const char *value
) {
440 //while(strcmp(var, ini_varlist[j].name) && j < MAX_INI_VARS) j++;
441 for (int j
= 0; j
< MAX_INI_VARS
; j
++)
443 if (stricmp(var
, ini_varlist
[j
].name
) == 0)
445 switch(ini_varlist
[j
].data_type
) {
447 set_string((char *)ini_varlist
[j
].ini_data
, value
,
448 ini_varlist
[j
].max_size
);
451 *(int *)ini_varlist
[j
].ini_data
= atoi(value
);
454 set_bool((bool *)ini_varlist
[j
].ini_data
, value
);
464 int TConfig::print_value(const char *var
) {
466 //while(strcmp(var, ini_varlist[j].name) && j < MAX_INI_VARS) j++;
468 for (int j
= 0; j
< MAX_INI_VARS
; j
++)
470 if (stricmp(var
, ini_varlist
[j
].name
) == 0)
473 set_string(var_name
, var
, sizeof(var_name
));
474 for(unsigned int i
= strlen(var_name
); i
< sizeof(var_name
) - 1; i
++)
476 var_name
[sizeof(var_name
) - 1] = 0;
477 Result
= sizeof(var_name
);
481 Result
= Result
/ 8 + 8;
483 switch(ini_varlist
[j
].data_type
) {
485 printit((char *)ini_varlist
[j
].ini_data
);
486 Result
+= strlen((char *)ini_varlist
[j
].ini_data
);
489 char buffer
[20]; // this may not be safe
490 // Ioannou : Paul this was _itoa, but Borland needs itoa !!
491 itoa(*(int *)ini_varlist
[j
].ini_data
, buffer
, 10);
493 Result
+= strlen(buffer
);
496 if(*(bool *)ini_varlist
[j
].ini_data
== true) {
511 void TConfig::init_vars() {
513 for(int j
= 0; j
< MAX_INI_VARS
; j
++) {
514 if(ini_varlist
[j
].section
!= NULL
) {
515 GetPrivateProfileString(ini_varlist
[j
].section
, ini_varlist
[j
].name
, "",
516 buffer
, sizeof(buffer
), inifile
);
517 if(*buffer
!= 0) set_value(ini_varlist
[j
].name
, buffer
);
522 void TConfig::inifile_init() {
523 // B. K. Oxley 9/16/98
524 char* env_telnet_ini
= getenv (ENV_TELNET_INI
);
525 if (env_telnet_ini
&& *env_telnet_ini
) {
526 strncpy (inifile
, env_telnet_ini
, sizeof(inifile
));
530 strcpy(inifile
, startdir
);
531 if (sizeof(inifile
) >= strlen(inifile
)+strlen("telnet.ini")) {
532 strcat(inifile
,"telnet.ini"); // add the default filename to the path
534 // if there is not enough room set the path to nothing
539 void TConfig::keyfile_init() {
540 // check to see if there is a key config file environment variable.
542 if ((k
= getenv(ENV_TELNET_CFG
)) == NULL
){
543 // if there is no environment variable
544 GetPrivateProfileString("Keyboard", "Keyfile", "", keyfile
,
545 sizeof(keyfile
), inifile
);
546 if(keyfile
== 0 || *keyfile
== 0) {
547 // and there is no profile string
548 strcpy(keyfile
, startdir
);
549 if (sizeof(keyfile
) >= strlen(keyfile
)+strlen("telnet.cfg")) {
552 strcat(keyfile
,"telnet.cfg"); // add the default filename to the path
553 if(stat(keyfile
, &buf
) != 0) {
554 char *s
= keyfile
+ strlen(keyfile
) - strlen("telnet.cfg");
555 strcpy(s
, "keys.cfg");
558 // if there is not enough room set the path to nothing
562 // Vassili Bourdo (vassili_bourdo@softhome.net)
564 // check that keyfile really exists
565 if( access(keyfile
,04) == -1 ) {
567 char pathbuf
[MAX_PATH
], *fn
;
568 //substitute keyfile path with startdir path
569 if((fn
= strrchr(keyfile
,'\\'))) strcpy(keyfile
,fn
);
570 strcat(strcpy(pathbuf
,startdir
),keyfile
);
571 //check that startdir\keyfile does exist
572 if( access(pathbuf
,04) == -1 ) {
574 //so, look for it in all paths
575 _searchenv(keyfile
, "PATH", pathbuf
);
576 if( *pathbuf
== 0 ) //no luck - revert it to INI file value
577 GetPrivateProfileString("Keyboard", "Keyfile", "",
578 keyfile
, sizeof(keyfile
), inifile
);
580 strcpy(keyfile
, pathbuf
);
587 // set the keyfile to the value of the environment variable
588 strncpy(keyfile
, k
, sizeof(keyfile
));
592 void TConfig::redir_init() {
593 // check to see if the environment variable 'TELNET_REDIR' is not 0;
594 char* p
= getenv(ENV_TELNET_REDIR
);
596 input_redir
= output_redir
= atoi(p
);
597 if((p
= getenv(ENV_INPUT_REDIR
))) input_redir
= atoi(p
);
598 if((p
= getenv(ENV_OUTPUT_REDIR
))) output_redir
= atoi(p
);
600 input_redir
= output_redir
= GetPrivateProfileInt("Terminal",
601 "Telnet_Redir", 0, inifile
);
602 input_redir
= GetPrivateProfileInt("Terminal",
603 "Input_Redir", input_redir
, inifile
);
604 output_redir
= GetPrivateProfileInt("Terminal",
605 "Output_Redir", output_redir
, inifile
);
607 if ((input_redir
> 1) || (output_redir
> 1))
608 setlocale(LC_CTYPE
,"");
609 // tell isprint() to not ignore local characters, if the environment
610 // variable "LANG" has a valid value (e.g. LANG=de for german characters)
611 // and the file LOCALE.BLL is installed somewhere along the PATH.
614 // Modified not to use getopt() by Paul Brannan 12/17/98
615 bool TConfig::Process_Params(int argc
, char *argv
[]) {
617 char *optarg
= argv
[optind
];
620 while(optind
< argc
) {
621 if(argv
[optind
][0] != '-') break;
625 if(argv
[optind
][2] == 0)
626 optarg
= argv
[++optind
];
628 optarg
= &argv
[optind
][2];
633 set_string(dumpfile
, optarg
, sizeof(dumpfile
));
634 printm(0, FALSE
, MSG_DUMPFILE
, dumpfile
);
636 // added support for setting options on the command-line
637 // (Paul Brannan 7/31/98)
641 for(j
= 0; optarg
[j
] != ' ' && optarg
[j
] != '=' && optarg
[j
] != 0; j
++);
643 printm(0, FALSE
, MSG_USAGE
); // print a usage message
644 printm(0, FALSE
, MSG_USAGE_1
);
648 if(!set_value(optarg
, &optarg
[j
+1]))
649 printm(0, FALSE
, MSG_BADVAL
, optarg
);
653 printm(0, FALSE
, MSG_USAGE
); // print a usage message
654 printm(0, FALSE
, MSG_USAGE_1
);
659 set_string(host
, argv
[optind
++], sizeof(host
)-1);
660 if(!strnicmp(host
, "telnet://", 9)) {
661 // we have a URL to parse
664 for(s
= host
+9, t
= host
; *s
!= 0; *(t
++) = *(s
++));
666 for(s
= host
; *s
!= ':' && *s
!= 0; s
++);
673 port
= argv
[optind
++];
678 void TConfig::set_string(char *dest
, const char *src
, const int length
) {
680 strncpy(dest
, src
, l
);
681 // dest[length-1] = '\0';
682 // Ioannou : this messes strings - is this really needed ?
683 // The target string, dest, might not be null-terminated
684 // if the length of src is length or more.
685 // it should be dest[length] = '\0' for strings with length 1
686 // (Escape_string etc), but doesn't work with others (like host).
687 // dest is long enough to avoid this in all the tested cases
690 // Ioannou : ignore case for true or on
692 void TConfig::set_bool(bool *boolval
, const char *str
) {
693 if(!stricmp(str
, "true")) *boolval
= true;
694 else if(!stricmp(str
, "on")) *boolval
= true;
695 else *boolval
= (bool)atoi(str
);