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
39 // Turn off the "forcing value to bool 'true' or 'false'" warning
41 #pragma warning(disable: 4800)
44 // This is the ini variable that is used for everybody
48 // set all default values
54 default_config
[0] = '\0';
55 strcpy(printer_name
, "LPT1");
62 eightbit_ansi
= FALSE
;
64 disable_break
= FALSE
;
67 preserve_colors
= FALSE
;
69 lock_linewrap
= FALSE
;
74 keyboard_paste
= FALSE
;
97 strcpy(escape_key
, "]");
98 strcpy(scrollback_key
, "[");
99 strcpy(dial_key
, "\\");
100 strcpy(default_config
, "ANSI");
101 strcpy(term
, "ansi");
103 strcpy(scroll_mode
, "DUMP");
115 TConfig::~TConfig() {
117 for(int j
= 0; j
< alias_total
; j
++) delete[] aliases
[j
];
182 MAX_INI_VARS
// must be last
185 struct ini_variable
{
186 const char *name
; // variable name
187 const char *section
; // name of ini file section the variable is in
188 enum ini_data_type data_type
; // type of data
189 void *ini_data
; // pointer to data
190 int max_size
; // max size if string
193 // Note: default values are set in the constructor, TConfig()
194 ini_variable ini_varlist
[MAX_INI_VARS
];
206 MAX_INI_GROUPS
// Must be last
209 char *ini_groups
[MAX_INI_GROUPS
];
211 void TConfig::init_varlist() {
212 static const ini_variable static_ini_varlist
[MAX_INI_VARS
] = {
213 {"Inifile", NULL
, INI_STRING
, &inifile
, sizeof(inifile
)},
214 {"Keyfile", "Keyboard", INI_STRING
, &keyfile
, sizeof(keyfile
)},
215 {"Dumpfile", "Terminal", INI_STRING
, &dumpfile
, sizeof(dumpfile
)},
216 {"Default_Config","Keyboard", INI_STRING
, &default_config
, sizeof(default_config
)},
217 {"Term", "Terminal", INI_STRING
, &term
, sizeof(term
)},
218 {"Input_Redir", "Terminal", INI_INT
, &input_redir
, 0},
219 {"Output_Redir","Terminal", INI_INT
, &output_redir
, 0},
220 {"Strip_Redir", "Terminal", INI_BOOL
, &strip_redir
, 0},
221 {"Destructive_Backspace","Terminal",INI_BOOL
, &dstrbksp
, 0},
222 {"EightBit_Ansi","Terminal", INI_BOOL
, &eightbit_ansi
, 0},
223 {"VT100_Mode", "Terminal", INI_BOOL
, &vt100_mode
, 0},
224 {"Disable_Break","Terminal", INI_BOOL
, &disable_break
, 0},
225 {"Speaker_Beep","Terminal", INI_BOOL
, &speaker_beep
, 0},
226 {"Beep", "Terminal", INI_BOOL
, &do_beep
, 0},
227 {"Preserve_Colors","Terminal", INI_BOOL
, &preserve_colors
, 0},
228 {"Wrap_Line", "Terminal", INI_BOOL
, &wrapline
, 0},
229 {"Lock_linewrap","Terminal", INI_BOOL
, &lock_linewrap
, 0},
230 {"Fast_Write", "Terminal", INI_BOOL
, &fast_write
, 0},
231 {"Term_Width", "Terminal", INI_INT
, &term_width
, 0},
232 {"Term_Height", "Terminal", INI_INT
, &term_height
, 0},
233 {"Window_Width","Terminal", INI_INT
, &window_width
, 0},
234 {"Window_Height","Terminal", INI_INT
, &window_height
, 0},
235 {"Wide_Enable", "Terminal", INI_BOOL
, &wide_enable
, 0},
236 {"Ctrlbreak_as_Ctrlc","Keyboard", INI_BOOL
, &ctrlbreak_as_ctrlc
, 0},
237 {"Buffer_Size", "Terminal", INI_INT
, &buffer_size
, 0},
238 {"Set_Title", "Terminal", INI_BOOL
, &set_title
, 0},
239 {"Blink_bg", "Colors", INI_INT
, &blink_bg
, 0},
240 {"Blink_fg", "Colors", INI_INT
, &blink_fg
, 0},
241 {"Underline_bg","Colors", INI_INT
, &underline_bg
, 0},
242 {"Underline_fg","Colors", INI_INT
, &underline_fg
, 0},
243 {"UlBlink_bg", "Colors", INI_INT
, &ulblink_bg
, 0},
244 {"UlBlink_fg", "Colors", INI_INT
, &ulblink_fg
, 0},
245 {"Normal_bg", "Colors", INI_INT
, &normal_bg
, 0},
246 {"Normal_fg", "Colors", INI_INT
, &normal_fg
, 0},
247 {"Scroll_bg", "Colors", INI_INT
, &scroll_bg
, 0},
248 {"Scroll_fg", "Colors", INI_INT
, &scroll_fg
, 0},
249 {"Status_bg", "Colors", INI_INT
, &status_bg
, 0},
250 {"Status_fg", "Colors", INI_INT
, &status_fg
, 0},
251 {"Enable_Mouse","Mouse", INI_BOOL
, &enable_mouse
, 0},
252 {"Printer_Name","Printer", INI_STRING
, &printer_name
, sizeof(printer_name
)},
253 {"Escape_Key", "Keyboard", INI_STRING
, &escape_key
, 1},
254 {"Scrollback_Key","Keyboard", INI_STRING
, &scrollback_key
, 1},
255 {"Dial_Key", "Keyboard", INI_STRING
, &dial_key
, 1},
256 {"Alt_Erase", "Keyboard", INI_BOOL
, &alt_erase
, 0},
257 {"Keyboard_Paste","Keyboard", INI_BOOL
, &keyboard_paste
, 0},
258 {"Scroll_Mode", "Scrollback", INI_STRING
, &scroll_mode
, sizeof(scroll_mode
)},
259 {"Scroll_Size", "Scrollback", INI_INT
, &scroll_size
, 0},
260 {"Scroll_Enable","Scrollback", INI_BOOL
, &scroll_enable
, 0},
261 {"Scriptname", "Scripting", INI_STRING
, &scriptname
, sizeof(scriptname
)},
262 {"Script_enable","Scripting", INI_BOOL
, &script_enable
, 0},
263 {"Netpipe", "Pipes", INI_STRING
, &netpipe
, sizeof(netpipe
)},
264 {"Iopipe", "Pipes", INI_STRING
, &iopipe
, sizeof(iopipe
)}
267 static const char *static_ini_groups
[MAX_INI_GROUPS
] = {
278 memcpy(ini_varlist
, static_ini_varlist
, sizeof(ini_varlist
));
279 memcpy(ini_groups
, static_ini_groups
, sizeof(ini_groups
));
282 void TConfig::init(char *dirname
, char *execname
) {
283 // Copy temporary dirname to permanent startdir
284 strncpy(startdir
, dirname
, sizeof(startdir
));
285 startdir
[sizeof(startdir
) - 1] = 0;
287 // Copy temp execname to permanent exename (Thomas Briggs 12/7/98)
288 strncpy(exename
, execname
, sizeof(exename
));
289 exename
[sizeof(exename
) - 1] = 0;
291 // Initialize INI file
295 // Note that this must be done early, so error messages will be printed
299 // Initialize aliases (Paul Brannan 1/1/99)
302 // Make sure the file that we're trying to work with exists
303 int iResult
= access(inifile
, 04);
305 // Thomas Briggs 9/14/98
307 // Tell the user what file we are reading
308 // We cannot print any messages before initializing telnet_redir
309 printm(0, FALSE
, MSG_CONFIG
, inifile
);
311 // Tell the user that the file doesn't exist, but later read the
312 // file anyway simply to populate the defaults
313 printm(0, FALSE
, MSG_NOINI
, inifile
);
315 init_vars(); // Initialize misc. vars
316 keyfile_init(); // Initialize keyfile
319 // Alias support (Paul Brannan 1/1/99)
320 void TConfig::init_aliases() {
324 // Find the correct buffer size
325 // FIX ME!! some implementations of Mingw32 don't have a
326 // GetPrivateProfileSecionNames function. What do we do about this?
329 int size
=1024, Result
= 0;
331 buffer
= new char[size
];
332 Result
= GetPrivateProfileSectionNames(buffer
, size
, inifile
);
333 if(Result
< size
- 2) break;
342 // Find the maximum number of aliases
345 for(tmp
= buffer
; *tmp
!= 0; tmp
+= strlen(tmp
) + 1)
348 aliases
= new char*[max
];
350 // Load the aliases into an array
351 for(tmp
= buffer
; *tmp
!= 0; tmp
+= strlen(tmp
) + 1) {
353 for(int j
= 0; j
< MAX_INI_GROUPS
; j
++) {
354 if(!stricmp(ini_groups
[j
], tmp
)) flag
= 1;
357 aliases
[alias_total
] = new char[strlen(tmp
)+1];
358 strcpy(aliases
[alias_total
], tmp
);
366 void TConfig::print_aliases() {
367 for(int j
= 0; j
< alias_total
; j
++) {
369 set_string(alias_name
, aliases
[j
], sizeof(alias_name
));
370 for(unsigned int i
= strlen(alias_name
); i
< sizeof(alias_name
) - 1; i
++)
372 alias_name
[sizeof(alias_name
) - 1] = 0;
374 if((j
% 4) == 3) printit("\n");
379 bool find_alias(const char *alias_name
) {
383 void TConfig::print_vars() {
385 for(j
= 0; j
< MAX_INI_VARS
; j
++) {
386 if(print_value(ini_varlist
[j
].name
) > 40) printit("\n");
387 else if(j
% 2) printit("\n");
390 if(j
% 2) printit("\n");
393 // Paul Brannan 9/3/98
394 void TConfig::print_vars(char *s
) {
395 if(!strnicmp(s
, "all", 3)) { // Print out all vars
400 // See if the group exists
402 for(j
= 0; j
< MAX_INI_GROUPS
; j
++)
403 if(!stricmp(ini_groups
[j
], s
)) break;
404 // If not, print out the value of the variable by that name
405 if(j
== MAX_INI_GROUPS
) {
411 // Print out the vars in the given group
413 for(j
= 0; j
< MAX_INI_VARS
; j
++) {
414 if(ini_varlist
[j
].section
== NULL
) continue;
415 if(!stricmp(ini_varlist
[j
].section
, s
)) {
416 if(print_value(ini_varlist
[j
].name
) > 40) printit("\n");
417 else if(count
% 2) printit("\n");
422 if(count
% 2) printit("\n");
425 // Paul Brannan 9/3/98
426 void TConfig::print_groups() {
427 for(int j
= 0; j
< MAX_INI_GROUPS
; j
++) {
429 set_string(group_name
, ini_groups
[j
], sizeof(group_name
));
430 for(unsigned int i
= strlen(group_name
); i
< sizeof(group_name
) - 1; i
++)
432 group_name
[sizeof(group_name
) - 1] = 0;
434 if((j
% 4) == 3) printit("\n");
439 // Ioannou : The index in the while causes segfaults if there is no match
440 // changes to for(), and strcmp to stricmp (prompt gives rong names)
442 bool TConfig::set_value(const char *var
, const char *value
) {
444 //while(strcmp(var, ini_varlist[j].name) && j < MAX_INI_VARS) j++;
445 for (int j
= 0; j
< MAX_INI_VARS
; j
++)
447 if (stricmp(var
, ini_varlist
[j
].name
) == 0)
449 switch(ini_varlist
[j
].data_type
) {
451 set_string((char *)ini_varlist
[j
].ini_data
, value
,
452 ini_varlist
[j
].max_size
);
455 *(int *)ini_varlist
[j
].ini_data
= atoi(value
);
458 set_bool((bool *)ini_varlist
[j
].ini_data
, value
);
468 int TConfig::print_value(const char *var
) {
470 //while(strcmp(var, ini_varlist[j].name) && j < MAX_INI_VARS) j++;
472 for (int j
= 0; j
< MAX_INI_VARS
; j
++)
474 if (stricmp(var
, ini_varlist
[j
].name
) == 0)
477 set_string(var_name
, var
, sizeof(var_name
));
478 for(unsigned int i
= strlen(var_name
); i
< sizeof(var_name
) - 1; i
++)
480 var_name
[sizeof(var_name
) - 1] = 0;
481 Result
= sizeof(var_name
);
485 Result
= Result
/ 8 + 8;
487 switch(ini_varlist
[j
].data_type
) {
489 printit((char *)ini_varlist
[j
].ini_data
);
490 Result
+= strlen((char *)ini_varlist
[j
].ini_data
);
493 char buffer
[20]; // this may not be safe
494 // Ioannou : Paul this was _itoa, but Borland needs itoa !!
495 itoa(*(int *)ini_varlist
[j
].ini_data
, buffer
, 10);
497 Result
+= strlen(buffer
);
500 if(*(bool *)ini_varlist
[j
].ini_data
== true) {
515 void TConfig::init_vars() {
517 for(int j
= 0; j
< MAX_INI_VARS
; j
++) {
518 if(ini_varlist
[j
].section
!= NULL
) {
519 GetPrivateProfileString(ini_varlist
[j
].section
, ini_varlist
[j
].name
, "",
520 buffer
, sizeof(buffer
), inifile
);
521 if(*buffer
!= 0) set_value(ini_varlist
[j
].name
, buffer
);
526 void TConfig::inifile_init() {
527 // B. K. Oxley 9/16/98
528 char* env_telnet_ini
= getenv (ENV_TELNET_INI
);
529 if (env_telnet_ini
&& *env_telnet_ini
) {
530 strncpy (inifile
, env_telnet_ini
, sizeof(inifile
));
534 strcpy(inifile
, startdir
);
535 if (sizeof(inifile
) >= strlen(inifile
)+strlen("telnet.ini")) {
536 strcat(inifile
,"telnet.ini"); // add the default filename to the path
538 // if there is not enough room set the path to nothing
543 void TConfig::keyfile_init() {
544 // check to see if there is a key config file environment variable.
546 if ((k
= getenv(ENV_TELNET_CFG
)) == NULL
){
547 // if there is no environment variable
548 GetPrivateProfileString("Keyboard", "Keyfile", "", keyfile
,
549 sizeof(keyfile
), inifile
);
550 if(keyfile
== 0 || *keyfile
== 0) {
551 // and there is no profile string
552 strcpy(keyfile
, startdir
);
553 if (sizeof(keyfile
) >= strlen(keyfile
)+strlen("telnet.cfg")) {
556 strcat(keyfile
,"telnet.cfg"); // add the default filename to the path
557 if(stat(keyfile
, &buf
) != 0) {
558 char *s
= keyfile
+ strlen(keyfile
) - strlen("telnet.cfg");
559 strcpy(s
, "keys.cfg");
562 // if there is not enough room set the path to nothing
566 // Vassili Bourdo (vassili_bourdo@softhome.net)
568 // check that keyfile really exists
569 if( access(keyfile
,04) == -1 ) {
571 char pathbuf
[MAX_PATH
], *fn
;
572 //substitute keyfile path with startdir path
573 if((fn
= strrchr(keyfile
,'\\'))) strcpy(keyfile
,fn
);
574 strcat(strcpy(pathbuf
,startdir
),keyfile
);
575 //check that startdir\keyfile does exist
576 if( access(pathbuf
,04) == -1 ) {
578 //so, look for it in all paths
579 _searchenv(keyfile
, "PATH", pathbuf
);
580 if( *pathbuf
== 0 ) //no luck - revert it to INI file value
581 GetPrivateProfileString("Keyboard", "Keyfile", "",
582 keyfile
, sizeof(keyfile
), inifile
);
584 strcpy(keyfile
, pathbuf
);
591 // set the keyfile to the value of the environment variable
592 strncpy(keyfile
, k
, sizeof(keyfile
));
596 void TConfig::redir_init() {
597 // check to see if the environment variable 'TELNET_REDIR' is not 0;
598 char* p
= getenv(ENV_TELNET_REDIR
);
600 input_redir
= output_redir
= atoi(p
);
601 if((p
= getenv(ENV_INPUT_REDIR
))) input_redir
= atoi(p
);
602 if((p
= getenv(ENV_OUTPUT_REDIR
))) output_redir
= atoi(p
);
604 input_redir
= output_redir
= GetPrivateProfileInt("Terminal",
605 "Telnet_Redir", 0, inifile
);
606 input_redir
= GetPrivateProfileInt("Terminal",
607 "Input_Redir", input_redir
, inifile
);
608 output_redir
= GetPrivateProfileInt("Terminal",
609 "Output_Redir", output_redir
, inifile
);
611 if ((input_redir
> 1) || (output_redir
> 1))
612 setlocale(LC_CTYPE
,"");
613 // tell isprint() to not ignore local characters, if the environment
614 // variable "LANG" has a valid value (e.g. LANG=de for german characters)
615 // and the file LOCALE.BLL is installed somewhere along the PATH.
618 // Modified not to use getopt() by Paul Brannan 12/17/98
619 bool TConfig::Process_Params(int argc
, char *argv
[]) {
621 char *optarg
= argv
[optind
];
624 while(optind
< argc
) {
625 if(argv
[optind
][0] != '-') break;
629 if(argv
[optind
][2] == 0)
630 optarg
= argv
[++optind
];
632 optarg
= &argv
[optind
][2];
637 set_string(dumpfile
, optarg
, sizeof(dumpfile
));
638 printm(0, FALSE
, MSG_DUMPFILE
, dumpfile
);
640 // added support for setting options on the command-line
641 // (Paul Brannan 7/31/98)
645 for(j
= 0; optarg
[j
] != ' ' && optarg
[j
] != '=' && optarg
[j
] != 0; j
++);
647 printm(0, FALSE
, MSG_USAGE
); // print a usage message
648 printm(0, FALSE
, MSG_USAGE_1
);
652 if(!set_value(optarg
, &optarg
[j
+1]))
653 printm(0, FALSE
, MSG_BADVAL
, optarg
);
657 printm(0, FALSE
, MSG_USAGE
); // print a usage message
658 printm(0, FALSE
, MSG_USAGE_1
);
663 set_string(host
, argv
[optind
++], sizeof(host
)-1);
664 if(!strnicmp(host
, "telnet://", 9)) {
665 // we have a URL to parse
668 for(s
= host
+9, t
= host
; *s
!= 0; *(t
++) = *(s
++));
670 for(s
= host
; *s
!= ':' && *s
!= 0; s
++);
677 port
= argv
[optind
++];
682 void TConfig::set_string(char *dest
, const char *src
, const int length
) {
684 strncpy(dest
, src
, l
);
685 // dest[length-1] = '\0';
686 // Ioannou : this messes strings - is this really needed ?
687 // The target string, dest, might not be null-terminated
688 // if the length of src is length or more.
689 // it should be dest[length] = '\0' for strings with length 1
690 // (Escape_string etc), but doesn't work with others (like host).
691 // dest is long enough to avoid this in all the tested cases
694 // Ioannou : ignore case for true or on
696 void TConfig::set_bool(bool *boolval
, const char *str
) {
697 if(!stricmp(str
, "true")) *boolval
= true;
698 else if(!stricmp(str
, "on")) *boolval
= true;
699 else *boolval
= (bool)atoi(str
);