echocfg.c 97.5 KB
Newer Older
1
/* FidoNet configuration utility 											*/
2 3 4 5 6

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8 9 10 11 12 13 14 15 16 17 18 19 20
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/
21 22 23

/* Portions written by Allen Christiansen 1994-1996 						*/

24
#include <stdio.h>
25

26
#undef JAVASCRIPT
27

rswindell's avatar
rswindell committed
28 29 30
/* XPDEV Headers */
#include "gen_defs.h"

31 32
#define __COLORS
#include "ciolib.h"
33
#include "uifc.h"
34
#include "scfgdefs.h"
35
#include "sbbsecho.h"
36 37
#include "sockwrap.h"
#include "str_util.h"
38 39 40

char **opt;

rswindell's avatar
rswindell committed
41
sbbsecho_cfg_t cfg;
42 43
uifcapi_t uifc;

44 45 46
void bail(int code)
{

47 48
	if(uifc.bail!=NULL)
		uifc.bail();
49 50 51
	exit(code);
}

52
/* These correlate with the LOG_* definitions in syslog.h/gen_defs.h */
rswindell's avatar
rswindell committed
53
static char* logLevelStringList[]
54
	= {"Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Informational", "Debugging", NULL};
55

rswindell's avatar
rswindell committed
56 57 58 59 60 61 62
void global_settings(void)
{
	static int global_opt;

	while(1) {
		int i = 0;
		char str[128];
63
		char tmp[128];
rswindell's avatar
rswindell committed
64
		char duration[64];
65
		sprintf(opt[i++], "%-30s %s", "Mailer Type"
rswindell's avatar
rswindell committed
66
			,cfg.flo_mailer ? "Binkley/FLO":"ArcMail/Attach");
67 68
		sprintf(opt[i++], "%-30s %s", "Log Level", logLevelStringList[cfg.log_level]);
		sprintf(opt[i++], "%-30s %s", "Log Timestamp Format", cfg.logtime);
69 70 71 72 73 74 75 76
		if(cfg.max_log_size) {
			SAFEPRINTF2(str, "%s bytes, keep %lu"
				,byte_count_to_str(cfg.max_log_size, tmp, sizeof(tmp))
				,cfg.max_logs_kept);
		} else {
			SAFECOPY(str, "Unlimited");
		}
		sprintf(opt[i++], "%-30s %s", "Maximum Log File Size", str);
77 78 79
		sprintf(opt[i++], "%-30s %s", "Strict Packet Passwords", cfg.strict_packet_passwords ? "Enabled" : "Disabled");
		sprintf(opt[i++], "%-30s %u", "Config File Backups", cfg.cfgfile_backups);
		sprintf(opt[i++], "%-30s %s bytes", "Minimum Free Disk Space"
80
			, byte_count_to_str(cfg.min_free_diskspace, str, sizeof(str)));
81

82
		snprintf(opt[i++],MAX_OPLN-1,"%-30s %-3.3s","Strip Incoming Soft CRs "
83
			,cfg.strip_soft_cr ? "Yes":"No");
84
		snprintf(opt[i++],MAX_OPLN-1,"%-30s %-3.3s","Strip Outgoing Line Feeds "
85
			,cfg.strip_lf ? "Yes":"No");
86 87
		snprintf(opt[i++],MAX_OPLN-1,"%-30s %-3.3s","Auto-detect UTF-8 Messages "
			,cfg.auto_utf8 ? "Yes":"No");
88 89
		snprintf(opt[i++],MAX_OPLN-1,"%-30s %-3.3s","Use Outboxes for Mail Files "
			,cfg.use_outboxes ? "Yes":"No");
90

91
		sprintf(opt[i++], "%-30s %s", "BSY Mutex File Timeout", duration_to_vstr(cfg.bsy_timeout, duration, sizeof(duration)));
92
		if(cfg.flo_mailer) {
93 94 95 96 97 98
			sprintf(opt[i++], "%-30s %s", "BSO Lock Attempt Delay", duration_to_vstr(cfg.bso_lock_delay, duration, sizeof(duration)));
			sprintf(opt[i++], "%-30s %lu", "BSO Lock Attempt Limit", cfg.bso_lock_attempts);
			sprintf(opt[i++], "%-30s %s", "BinkP Capabilities", cfg.binkp_caps);
			sprintf(opt[i++], "%-30s %s", "BinkP Sysop Name", cfg.binkp_sysop);
			sprintf(opt[i++], "%-30s %s", "BinkP Authentication", cfg.binkp_plainAuthOnly ? "Plain Only" : "Plain or CRAM-MD5");
			sprintf(opt[i++], "%-30s %s", "BinkP Encryption", !cfg.binkp_plainTextOnly && !cfg.binkp_plainAuthOnly ? "Supported" : "Unsupported");
99
		}
rswindell's avatar
rswindell committed
100 101 102 103 104 105 106 107 108
		opt[i][0] = 0;
		uifc.helpbuf=
			"~ Global Settings ~\n"
			"\n"
			"`Mailer Type` should normally be set to `Binkley/FLO` to enable SBBSecho's\n"
			"    \"Binkley-Style Outbound\" operating mode (a.k.a. `BSO` or `FLO` mode).\n"
			"    If you are using an `Attach`, `ArcMail`, or `FrontDoor` style FidoNet\n"
			"    mailer, then set this setting to `ArcMail/Attach`, but know that most\n"
			"    modern FidoNet mailers are Binkley-Style and therefore that mode of\n"
109
			"    operation in SBBSecho is much more widely tested and supported.\n"
rswindell's avatar
rswindell committed
110 111 112 113 114 115 116 117 118 119 120 121 122
			"\n"
			"`Log Level` should normally be set to `Informational` but if you're\n"
			"    experiencing problems with SBBSecho and would like more verbose log\n"
			"    output, set this to `Debugging`. If you want less verbose logging,\n"
			"    set to higher-severity levels to reduce the number of log messages.\n"
			"\n"
			"`Log Timestmap Format` defines the format of the date/time-stamps added\n"
			"    along with each log message to the log file (e.g. sbbsecho.log).\n"
			"    The timestamp format is defined using standard C `strftime` notation.\n"
			"    The default format is: `" DEFAULT_LOG_TIME_FMT "`\n"
			"    For SBBSecho v2 timestamp format, use `%m/%d/%y %H:%M:%S`\n"
			"\n"
			"`Strict Packet Passwords`, when enabled, requires that Packet Passwords\n"
123 124
			"    must match the password for the linked node from which the packet\n"
			"    was received, even if that linked node has no password configured.\n"
rswindell's avatar
rswindell committed
125 126 127 128
			"    If you wish to revert to the SBBSecho v2 behavior with less strict\n"
			"    enforcement of matching packet passwords, disable this option.\n"
			"    Default: Enabled\n"
			"\n"
129 130 131 132
			"`Config File Backups` determines the number of automatic backups of your\n"
			"    SBBSecho configuration file (e.g. `sbbsecho.ini`) that will be\n"
			"    maintained by FidoNet Config (`echocfg`) and SBBSecho AreaFix.\n"
			"\n"
133 134 135 136 137
			"`Minimum Free Disk Space` determines the minimum amount of free disk\n"
			"    space for SBBSecho to run.  SBBSecho will just exit with an error\n"
			"    message (and an error level of 1) if the minimum amount of free\n"
			"    space is not found in directories into which SBBSecho may write.\n"
			"\n"
138 139 140 141 142 143 144 145
			"`Strip Incoming Soft CRs` instructs SBBSecho to remove any \"Soft\"\n"
			"    Carriage Return (ASCII 141) characters from the text of `imported`\n"
			"    EchoMail and NetMail messages.\n"
			"\n"
			"`Strip Outgoing Line Feeds` instructs SBBSecho to remove any Line Feed\n"
			"    (ASCII 10) characters from the body text of `exported` EchoMail and\n"
			"    NetMail messages.\n"
			"\n"
146 147 148 149 150
			"`Auto-detect UTF-8 Messages` instructs SBBSecho to treat incoming\n"
			"    messages which lack a CHRS/CHARSET control line and contain valid\n"
			"    UTF-8 character sequences in the message text, as UTF-8 encoded\n"
			"    messages.\n"
			"\n"
151 152 153 154 155 156 157 158
			"`Use Outboxes for Mail Files` instructs SBBSecho to place outbound\n"
			"    NetMail and EchoMail files into the configured `Outbox Directory`\n"
			"    of the relevant linked node. If the linked node has no configured\n"
			"    outbox, then outbound mail files for that node are placed in the\n"
			"    normal outbound directory hierarchy.  The BinkIT mailer will\n"
			"    send files from configured outboxes in addition to the normal\n"
			"    outbound directories, even when this option is set to `No`.\n"
			"\n"
rswindell's avatar
rswindell committed
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
			"`BSY Mutex File Timeout` determines the maximum age of an existing\n"
			"    mutex file (`*.bsy`) before SBBSecho will act as though the mutex\n"
			"    file was not present.  This setting applies to the global\n"
			"    `sbbsecho.bsy` file as well as the BSO lock (`*.bsy`) files for\n"
			"    individual nodes.\n"
			"    Default: 12 hours\n"
			"\n"
			"`BSO Lock Attempt Delay` determines the amount of time between BSO\n"
			"    node lock attempts (via `*.bsy` files in the relevant outbound\n"
			"    directory).\n"
			"    Default: 10 seconds\n"
			"\n"
			"`BSO Lock Attempt Limit` determines the maximum number of BSO node lock\n"
			"    attempts before SBBSecho will give-up and move on to another node\n"
			"    to process mail.  This value multiplied by the `BSO Lock Attempt\n"
			"    Delay` should be much less than the `BSY Mutex File Timeout` value.\n"
			"    Default: 60 attempts\n"
			"\n"
177 178 179 180 181
			"`BinkP Capabilities` may be used to over-ride the default BinkP node\n"
			"    capabilities sent during a `BinkIT` mailer session (via the NDL\n"
			"    command). Default capabilities value is '115200,TCP,BINKP'\n"
			"\n"
			"`BinkP Sysop` may be used to over-ride the default BinkP sysop name\n"
182
			"    sent during a `BinkIT` mailer session (via the ZYZ command).\n"
183
			"    Default sysop name is that set in `SCFG->System->Operator`\n"
184 185 186 187 188
			"\n"
			"`BinkP Authentication` may be set to `Plain Only` if you wish to disable\n"
			"    CRAM-MD5 authentication for both inbound and outbound sessions.\n"
		    "    Note: CRAM-MD5 authentication is required for encrypted sessions.\n"
			"    Default: Plain or CRAM-MD5\n"
189 190 191 192
			"\n"
			"`BinkP Encryption` may be set to `Supported` (the default) only when\n"
			"    BinkP Authentication is set to Plain or CRAM-MD5.\n"
			"    Default: Supported\n"
rswindell's avatar
rswindell committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
			;

		int key = uifc.list(WIN_BOT|WIN_L2R|WIN_ACT|WIN_SAV, 0, 0, 0, &global_opt,0, "Global Settings", opt);

		switch(key) {

			case -1:
				return;

			case 0:
				cfg.flo_mailer = !cfg.flo_mailer;
				break;

			case 1:
	uifc.helpbuf=
	"~ Log Level ~\n"
	"\n"
	"Select the minimum severity of log entries to be logged to the log file.\n"
	"The default/normal setting is `Informational`.";
				int i = cfg.log_level;
				i = uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0,"Log Level",logLevelStringList);
				if(i>=0 && i<=LOG_DEBUG)
					cfg.log_level=i;
				break;

			case 2:
				uifc.input(WIN_MID|WIN_SAV,0,0
					,"Log Timestamp Format", cfg.logtime, sizeof(cfg.logtime)-1, K_EDIT);
				break;

			case 3:
224 225 226 227 228 229 230 231 232
				byte_count_to_str(cfg.max_log_size, str, sizeof(str));
				if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Maximum Log File Size (in bytes, 0=unlimited)", str, 10, K_EDIT|K_UPPER) > 0) {
					cfg.max_log_size = parse_byte_count(str, 1);
					if(cfg.max_log_size) {
						SAFEPRINTF(str, "%lu", cfg.max_logs_kept);
						if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Maximum Number of old Log Files to Keep", str, 5, K_EDIT|K_NUMBER) > 0)
							cfg.max_logs_kept = strtoul(str, NULL, 10);
					}
				}
rswindell's avatar
rswindell committed
233 234 235
				break;

			case 4:
236 237 238 239
				cfg.strict_packet_passwords = !cfg.strict_packet_passwords;
				break;

			case 5:
240 241 242 243 244
				sprintf(str, "%u", cfg.cfgfile_backups);
				if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Configuration File Backups", str, 5, K_EDIT|K_NUMBER) > 0)
					cfg.cfgfile_backups = atoi(str);
				break;

245
			case 6:
246
				byte_count_to_str(cfg.min_free_diskspace, str, sizeof(str));
247
				if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Minimum Free Disk Space (in bytes)", str, 10, K_EDIT|K_UPPER) > 0)
248 249 250
					cfg.min_free_diskspace = parse_byte_count(str, 1);
				break;

251
			case 7:
252 253 254 255 256 257 258 259 260
			{
				int k = !cfg.strip_soft_cr;
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Strip Soft Carriage Returns from Incoming Messages",uifcYesNoOpts)) {
					case 0:	cfg.strip_soft_cr = true;	break;
					case 1:	cfg.strip_soft_cr = false;	break;
				}
				break;
			}
261
			case 8:
262 263 264 265 266 267 268 269 270
			{
				int k = !cfg.strip_lf;
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Strip Line Feeds from Outgoing Messages",uifcYesNoOpts)) {
					case 0:	cfg.strip_lf = true;	break;
					case 1:	cfg.strip_lf = false;	break;
				}
				break;
			}
271
			case 9:
272 273 274 275 276 277 278 279 280
			{
				int k = !cfg.auto_utf8;
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Auto-detect incoming UTF-8 encoded messages",uifcYesNoOpts)) {
					case 0:	cfg.auto_utf8 = true;	break;
					case 1:	cfg.auto_utf8 = false;	break;
				}
				break;
			}
281
			case 10:
282 283 284 285 286 287 288 289 290
			{
				int k = !cfg.use_outboxes;
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Use Outboxes for Outbound NetMail and EchoMail",uifcYesNoOpts)) {
					case 0:	cfg.use_outboxes = true;	break;
					case 1:	cfg.use_outboxes = false;	break;
				}
				break;
			}
291
			case 11:
rswindell's avatar
rswindell committed
292 293 294 295 296
				duration_to_vstr(cfg.bsy_timeout, duration, sizeof(duration));
				if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "BSY Mutex File Timeout", duration, 10, K_EDIT) > 0)
					cfg.bsy_timeout = (ulong)parse_duration(duration);
				break;

297
			case 12:
rswindell's avatar
rswindell committed
298 299 300 301 302
				duration_to_vstr(cfg.bso_lock_delay, duration, sizeof(duration));
				if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Delay Between BSO Lock Attempts", duration, 10, K_EDIT) > 0)
					cfg.bso_lock_delay = (ulong)parse_duration(duration);
				break;

303
			case 13:
304
				sprintf(str, "%lu", cfg.bso_lock_attempts);
rswindell's avatar
rswindell committed
305 306 307 308
				if(uifc.input(WIN_MID|WIN_SAV, 0, 0, "Maximum BSO Lock Attempts", str, 5, K_EDIT|K_NUMBER) > 0)
					cfg.bso_lock_attempts = atoi(str);
				break;

309
			case 14:
310
				uifc.input(WIN_MID|WIN_SAV,0,0
311
					,"BinkP Capabilities (BinkIT)", cfg.binkp_caps, sizeof(cfg.binkp_caps)-1, K_EDIT);
312 313
				break;

314
			case 15:
315
				uifc.input(WIN_MID|WIN_SAV,0,0
316
					,"BinkP Sysop Name (BinkIT)", cfg.binkp_sysop, sizeof(cfg.binkp_sysop)-1, K_EDIT);
317
				break;
318

319
			case 16:
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
			{
				int k = !cfg.binkp_plainAuthOnly;
				strcpy(opt[0], "Plain-Password Only");
				strcpy(opt[1], "Plain-Password or CRAM-MD5");
				opt[2][0] = 0;
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"BinkP Authentication",opt)) {
					case 0:
						cfg.binkp_plainAuthOnly = true;
						break;
					case 1:
						cfg.binkp_plainAuthOnly = false;
						break;
				}
				break;
			}
336

337
			case 17:
338 339 340 341 342
			{
				if(cfg.binkp_plainAuthOnly) {
					uifc.msg("CRAM-MD5 authentication/encryption has been disabled globally");
					break;
				}
343
				int k = cfg.binkp_plainTextOnly;
344 345 346
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"BinkP Encryption Supported",uifcYesNoOpts)) {
					case 0:
347
						cfg.binkp_plainTextOnly = false;
348 349
						break;
					case 1:
350
						cfg.binkp_plainTextOnly = true;
351 352 353 354
						break;
				}
				break;
			}
rswindell's avatar
rswindell committed
355 356 357 358
		}
	}
}

359 360 361
static bool new_node(unsigned new_nodenum)
{
	nodecfg_t* nodecfg = realloc(cfg.nodecfg, sizeof(nodecfg_t)*(cfg.nodecfgs+1));
rswindell's avatar
rswindell committed
362

363 364 365 366 367 368 369 370 371
	if(nodecfg == NULL)
		return false;

	cfg.nodecfg = nodecfg;
	for(unsigned int i=cfg.nodecfgs; i > new_nodenum; i--)
		memcpy(&cfg.nodecfg[i], &cfg.nodecfg[i-1], sizeof(nodecfg_t));

	cfg.nodecfgs++;
	memset(&cfg.nodecfg[new_nodenum], 0, sizeof(nodecfg_t));
372
	cfg.nodecfg[new_nodenum].binkp_allowPlainText = true;
373
	cfg.nodecfg[new_nodenum].binkp_port = IPPORT_BINKP;
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
	return true;
}

static bool new_arcdef(unsigned new_arcnum)
{
	arcdef_t * arcdef = realloc(cfg.arcdef, sizeof(arcdef_t)*(cfg.arcdefs+1));

	if(arcdef == NULL)
		return false;

	cfg.arcdef = arcdef;

	for(unsigned j=cfg.arcdefs;j>new_arcnum;j--)
		memcpy(&cfg.arcdef[j],&cfg.arcdef[j-1], sizeof(arcdef_t));
	cfg.arcdefs++;
	memset(&cfg.arcdef[new_arcnum], 0, sizeof(arcdef_t));
	return true;
}

static bool new_list(unsigned new_listnum)
{
	echolist_t *listcfg = realloc(cfg.listcfg, sizeof(echolist_t)*(cfg.listcfgs+1));

	if(listcfg == NULL)
		return false;
	cfg.listcfg = listcfg;
	for(unsigned j=cfg.listcfgs;j>new_listnum;j--)
		memcpy(&cfg.listcfg[j],&cfg.listcfg[j-1], sizeof(echolist_t));
	cfg.listcfgs++;
	memset(&cfg.listcfg[new_listnum],0,sizeof(echolist_t));
	return true;
}

407 408 409 410 411 412 413 414 415 416 417 418 419
static bool new_domain(unsigned new_domnum)
{
	struct fido_domain* new_list = realloc(cfg.domain_list, sizeof(struct fido_domain) * (cfg.domain_count + 1));
	if(new_list == NULL)
		return false;
	cfg.domain_list = new_list;
	for(unsigned i = cfg.domain_count; i > new_domnum; i--)
		memcpy(&cfg.domain_list[i], &cfg.domain_list[i-1], sizeof(struct fido_domain));
	cfg.domain_count++;
	memset(&cfg.domain_list[new_domnum], 0, sizeof(struct fido_domain));
	return true;
}

420 421 422 423 424 425 426 427 428 429 430 431 432
static bool new_robot(unsigned new_botnum)
{
	struct robot* new_list = realloc(cfg.robot_list, sizeof(struct robot) * (cfg.robot_count + 1));
	if(new_list == NULL)
		return false;
	cfg.robot_list = new_list;
	for(unsigned i = cfg.robot_count; i > new_botnum; i--)
		memcpy(&cfg.robot_list[i], &cfg.robot_list[i-1], sizeof(struct robot));
	cfg.robot_count++;
	memset(&cfg.robot_list[new_botnum], 0, sizeof(struct robot));
	return true;
}

433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
static char* int_list(int* list, unsigned count)
{
	static char str[128];

	str[0]=0;
	for(unsigned i = 0; i < count; i++) {
		if(i)
			sprintf(str + strlen(str), ",%d", *(list + i));
		else
			sprintf(str, "%d", *list);
	}

	return str;
}

void binkp_settings(nodecfg_t* node)
{
450
	static int cur;
451 452 453 454 455 456 457

	while(1) {
		char str[128];
		int i = 0;
		sprintf(opt[i++], "%-20s %s", "Host", node->binkp_host);
		sprintf(opt[i++], "%-20s %u", "Port", node->binkp_port);
		sprintf(opt[i++], "%-20s %s", "Poll", node->binkp_poll ? "Yes" : "No");
458 459
		char* auth = "Plain Only";
		char* crypt = "Unsupported";
460
		if(!cfg.binkp_plainAuthOnly && !node->binkp_plainAuthOnly) {
461
			if(!cfg.binkp_plainTextOnly)
462
				crypt = node->binkp_allowPlainText ? "Supported" : "Required";
463 464 465 466 467 468 469
			if(node->binkp_allowPlainAuth) 
				auth = "Plain or CRAM-MD5";
			else
				auth = "CRAM-MD5 Only";
		}
		sprintf(opt[i++], "%-20s %s", "Authentication", auth);
		sprintf(opt[i++], "%-20s %s", "Encryption", crypt);
470
		sprintf(opt[i++], "%-20s %s", "Implicit TLS", node->binkp_tls ? "Yes" : "No");
471 472 473 474
		sprintf(opt[i++], "%-20s %s", "Source Address", node->binkp_src);
		opt[i][0]=0;
		char title[128];
		SAFEPRINTF(title, "%s BinkP Settings", faddrtoa(&node->addr));
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
		uifc.helpbuf=
			"~ BinkP Settings ~\n"
			"\nThese settings are used by the Synchronet `BinkIT` BinkP/BSO mailer.\n"
			"\n"
			"`Host` defines the TCP/IP address or host name with which to connect for\n"
			"    sessions with this linked node.  If the host is not set, then a\n"
			"    DNS-based look-up will be attempted (e.g. the IP address for\n"
			"    `1:103/705` would be looked-up via host name `f705.n103.z1.binkp.net`).\n"
			"    Nodelist-based look-ups are also supported.\n"
			"\n"
			"`Port` defines the TCP port used by this linked node for BinkP sessions.\n"
			"    The default BinkP TCP port is `24554`.\n"
			"\n"
			"`Poll` defines whether or not to periodically poll this linked node.\n"
			"\n"
490 491 492
			"`Authentication` determines what types of authentication will be supported\n"
			"    during both inbound and outbound sessions with this linked node.\n"
			"    The supported BinkP-auth methods are `Plain-Password` and `CRAM-MD5`.\n"
493 494
			"    Note: For `incoming` connections, CRAM-MD5 will be supported unless\n"
			"    CRAM-MD5 authentication has been `globally` disabled.\n"
495
			"\n"
496 497 498 499 500
			"`Encryption` determines whether unencrypted data transfers will be\n"
			"    supported or required when communicating with this linked node.\n"
			"    With this setting set to `Required`, ~only~ BinkD-style-encrypted BinkP\n"
			"    sessions will be supported.\n"
			"    CRAM-MD5 authentication `must` be used when encrypting BinkP sessions.\n"
501
			"\n"
502 503 504
			"`Implicit TLS` defines whether or not to use `BINKPS` when connecting\n"
			"    (outbound) with this linked node.\n"
			"\n"
505 506 507 508
			"`Source Address` allows you to override the source FTN address used\n"
			"    with outgoing BinkP mailer sessions with this linked node.\n"
			"    Normally, this setting is left blank (not set).\n"
			;
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
		int k = uifc.list(WIN_RHT|WIN_BOT|WIN_SAV|WIN_ACT,0,0,0,&cur,0, title, opt);
		if(k < 0)
			break;
		switch(k) {
			case 0:
				uifc.input(WIN_MID|WIN_SAV,0,0
					,"Host name or IP address", node->binkp_host, sizeof(node->binkp_host)-1, K_EDIT);
				break;
			case 1:
				sprintf(str, "%u", node->binkp_port);
				if(uifc.input(WIN_MID|WIN_SAV,0,0
					,"TCP Port Number (e.g. 24554)", str, 5, K_EDIT|K_NUMBER) > 0) {
					node->binkp_port = atoi(str);
					uifc.changes = TRUE;
				}
				break;
			case 2:
				k = !node->binkp_poll;
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Poll This Node Periodically for Inbound Files/Mail",uifcYesNoOpts)) {
					case 0:	node->binkp_poll = true;	uifc.changes=TRUE; break;
					case 1:	node->binkp_poll = false;	uifc.changes=TRUE; break;
				}
				break;
			case 3:
534
				if(cfg.binkp_plainAuthOnly) {
535
					uifc.msg("CRAM-MD5 authentication/ has been disabled globally");
536 537
					break;
				}
538 539 540 541 542
				k = node->binkp_plainAuthOnly ? 0 : (1 + !node->binkp_allowPlainAuth);
				strcpy(opt[0], "Plain-Password Only");
				strcpy(opt[1], "Plain-Password or CRAM-MD5");
				strcpy(opt[2], "CRAM-MD5 Only");
				opt[3][0] = 0;
543
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
					,"Authentication",opt)) {
					case 0:	
						node->binkp_plainAuthOnly = true;
						node->binkp_allowPlainAuth = true;
						node->binkp_allowPlainText = true;
						uifc.changes=TRUE;
						break;
					case 1:
						node->binkp_allowPlainAuth = true;
						node->binkp_plainAuthOnly = false;
						node->binkp_allowPlainText = true;
						uifc.changes=TRUE;
						break;
					case 2:
						node->binkp_allowPlainAuth = false;
						node->binkp_plainAuthOnly = false;
						uifc.changes=TRUE;
						break;
562 563 564
				}
				break;
			case 4:
565
				if(cfg.binkp_plainTextOnly) {
566 567 568
					uifc.msg("BinkP encryption has been disabled globally");
					break;
				}
569 570 571 572
				if(cfg.binkp_plainAuthOnly) {
					uifc.msg("CRAM-MD5 authentication/encryption has been disabled globally");
					break;
				}
573 574 575
				k = !node->binkp_allowPlainText;
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Allow Plain-Text (Unencrypted) Sessions",uifcYesNoOpts)) {
576 577 578 579 580 581 582 583 584 585 586
					case 0:
						node->binkp_allowPlainText = true;
						node->binkp_allowPlainAuth = true;
						uifc.changes=TRUE;
						break;
					case 1:
						node->binkp_allowPlainText = false;
						node->binkp_allowPlainAuth = false;
						node->binkp_plainAuthOnly = false;
						uifc.changes=TRUE;
						break;
587 588 589
				}
				break;
			case 5:
590 591 592 593 594 595 596 597
				k = !node->binkp_tls;
				switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
					,"Use BINKPS (Implicit TLS) Connections with This Node",uifcYesNoOpts)) {
					case 0:	node->binkp_tls = true;		uifc.changes=TRUE; break;
					case 1:	node->binkp_tls = false;	uifc.changes=TRUE; break;
				}
				break;
			case 6:
598 599 600 601 602 603 604 605 606 607 608 609 610
				uifc.helpbuf=
				"~ Source Address ~\n\n"
				"This is the FidoNet style address to use as the source address when\n"
				"conducting BinkP sessions with this linked node.";
				uifc.input(WIN_MID|WIN_SAV,0,0
					,"Source Node Address (optional)"
					,node->binkp_src
					,sizeof(node->binkp_src)-1, K_EDIT);
				break;
		}
	}
}

611 612 613
int main(int argc, char **argv)
{
	char str[256],*p;
614
	int i,j,k,x,dflt,nodeop=0,nodeopbar=0,packop=0,listop=0;
615 616 617
	echolist_t savlistcfg;
	nodecfg_t savnodecfg;
	arcdef_t savarcdef;
618
	struct fido_domain savedomain;
619
	struct robot saverobot;
620
	BOOL door_mode=FALSE;
621
	int		ciolib_mode=CIOLIB_MODE_AUTO;
rswindell's avatar
rswindell committed
622 623 624
	unsigned int u;
	char	sysop_aliases[256];
	sbbsecho_cfg_t orig_cfg;
625

626 627 628
	ZERO_VAR(savlistcfg);
	ZERO_VAR(savnodecfg);
	ZERO_VAR(savarcdef);
629
	ZERO_VAR(savedomain);
630

631 632
	fprintf(stderr,"\nSynchronet FidoNet Configuration  Version %u.%02u  " COPYRIGHT_NOTICE
		"\n\n",SBBSECHO_VERSION_MAJOR, SBBSECHO_VERSION_MINOR);
633

rswindell's avatar
rswindell committed
634
	memset(&cfg,0,sizeof(cfg));
635 636 637 638
	str[0]=0;
	for(i=1;i<argc;i++) {
		if(argv[i][0]=='-')
			switch(toupper(argv[i][1])) {
639
                case 'D':
rswindell's avatar
rswindell committed
640
					printf("NOTICE: The -d option is deprecated, use -id instead\n");
641 642 643 644 645 646 647 648 649
					SLEEP(2000);
                    door_mode=TRUE;
                    break;
                case 'L':
                    uifc.scrn_len=atoi(argv[i]+2);
                    break;
                case 'E':
                    uifc.esc_delay=atoi(argv[i]+2);
                    break;
650
				case 'I':
651 652 653 654 655 656 657 658
					switch(toupper(argv[i][2])) {
						case 'A':
							ciolib_mode=CIOLIB_MODE_ANSI;
							break;
						case 'C':
							ciolib_mode=CIOLIB_MODE_CURSES;
							break;
						case 0:
rswindell's avatar
rswindell committed
659
							printf("NOTICE: The -i option is deprecated, use -if instead\n");
660
							SLEEP(2000);
661
							// fall-through
662 663 664
						case 'F':
							ciolib_mode=CIOLIB_MODE_CURSES_IBM;
							break;
665 666 667
						case 'I':
							ciolib_mode=CIOLIB_MODE_CURSES_ASCII;
							break;
668 669 670 671 672 673 674 675 676 677 678 679
						case 'X':
							ciolib_mode=CIOLIB_MODE_X;
							break;
						case 'W':
							ciolib_mode=CIOLIB_MODE_CONIO;
							break;
						case 'D':
		                    door_mode=TRUE;
		                    break;
						default:
							goto USAGE;
					}
680
					break;
681 682 683
				case 'K':	/* Keyboard-only mode (no mouse support) */
					uifc.mode |= UIFC_NOMOUSE;
					break;
684 685 686 687 688 689
		        case 'M':   /* Monochrome mode */
        			uifc.mode|=UIFC_MONO;
                    break;
                case 'C':
        			uifc.mode|=UIFC_COLOR;
                    break;
690 691
                case 'V':
                    textmode(atoi(argv[i]+2));
692
                    break;
693 694
                default:
					USAGE:
rswindell's avatar
rswindell committed
695
                    printf("usage: echocfg [path/to/sbbsecho.ini] [options]"
696
                        "\n\noptions:\n\n"
rswindell's avatar
rswindell committed
697 698 699 700 701
						"-k  =  keyboard mode only (no mouse support)\n"
                        "-c  =  force color mode\n"
						"-m  =  force monochrome mode\n"
                        "-e# =  set escape delay to #msec\n"
						"-iX =  set interface mode to X (default=auto) where X is one of:\n"
702
#ifdef __unix__
rswindell's avatar
rswindell committed
703 704 705
						"       X = X11 mode\n"
						"       C = Curses mode\n"
						"       F = Curses mode with forced IBM charset\n"
706
						"       I = Curses mode with forced ASCII charset\n"
707
#else
rswindell's avatar
rswindell committed
708
						"       W = Win32 native mode\n"
709
#endif
rswindell's avatar
rswindell committed
710 711 712 713
						"       A = ANSI mode\n"
						"       D = standard input/output/door mode\n"
                        "-v# =  set video mode to # (default=auto)\n"
                        "-l# =  set screen lines to # (default=auto-detect)\n"
714 715
                        );
        			exit(0);
716 717
		}
		else
718
			SAFECOPY(str,argv[i]);
719 720
	}
	if(str[0]==0) {
721
		SAFECOPY(cfg.cfgfile, get_ctrl_dir(/* warn: */true));
722 723 724 725
		backslash(cfg.cfgfile);
		SAFECAT(cfg.cfgfile, "sbbsecho.ini");
	} else {
		SAFECOPY(cfg.cfgfile,str);
726
	}
727

rswindell's avatar
rswindell committed
728 729 730 731 732
	if(!sbbsecho_read_ini(&cfg)) {
		fprintf(stderr, "ERROR %d (%s) reading %s\n", errno, strerror(errno), cfg.cfgfile);
		exit(1);
	}
	orig_cfg = cfg;
733

734
	// savnum=0;
rswindell's avatar
rswindell committed
735
	if((opt=(char **)malloc(sizeof(char *)*1000))==NULL) {
736
		puts("memory allocation error\n");
rswindell's avatar
rswindell committed
737
		exit(1);
738
	}
rswindell's avatar
rswindell committed
739 740
	for(i=0;i<1000;i++)
		if((opt[i]=(char *)malloc(MAX_OPLN+1))==NULL) {
741
			puts("memory allocation error\n");
rswindell's avatar
rswindell committed
742
			exit(1);
743
		}
744
	uifc.size=sizeof(uifc);
745 746 747 748 749 750 751 752
	if(!door_mode) {
		i=initciolib(ciolib_mode);
		if(i!=0) {
    		printf("ciolib library init returned error %d\n",i);
    		exit(1);
		}
    	i=uifcini32(&uifc);  /* curses/conio/X/ANSI */
	}
753
	else
754
    	i=uifcinix(&uifc);  /* stdio */
755 756 757 758 759 760

	if(i!=0) {
		printf("uifc library init returned error %d\n",i);
		exit(1);
	}

rswindell's avatar
rswindell committed
761
	uifc.timedisplay = NULL;
762
	sprintf(str,"Synchronet FidoNet Config v%u.%02u",SBBSECHO_VERSION_MAJOR, SBBSECHO_VERSION_MINOR);
763
	uifc.scrn(str);
rswindell's avatar
rswindell committed
764 765 766 767
	p=cfg.cfgfile;
	if(strlen(p) + strlen(str) + 4 > uifc.scrn_width)
		p=getfname(cfg.cfgfile);
	uifc.printf(uifc.scrn_width-(strlen(p)+1),1,uifc.bclr|(uifc.cclr<<4),p);
768

769 770 771 772 773 774
	if(cfg.used_include && uifc.deny("%s uses !include, continue read only", getfname(p))) {
		uifc.pop("Exiting");
		uifc.bail();
		exit(0);
	}

rswindell's avatar
rswindell committed
775 776 777 778 779
	/* Remember current menu item selections using these vars: */
	int netmail_opt = 0;
	int echomail_opt = 0;
	int path_opt = 0;
	int node_opt = 0;
780
	int node_bar = 0;
rswindell's avatar
rswindell committed
781
	int archive_opt = 0;
782
	int archive_bar = 0;
rswindell's avatar
rswindell committed
783
	int echolist_opt = 0;
784
	int echolist_bar = 0;
785
	int domain_opt = 0;
786
	int domain_bar = 0;
787 788
	int robot_opt = 0;
	int robot_bar = 0;
789 790
	dflt=0;
	while(1) {
rswindell's avatar
rswindell committed
791 792
		if(memcmp(&cfg, &orig_cfg, sizeof(cfg)) != 0)
			uifc.changes = TRUE;
793
		uifc.helpbuf=
794
	"~ FidoNet Configuration ~\n\n"
rswindell's avatar
rswindell committed
795
	"This program allows you to easily configure the Synchronet BBS\n"
796 797 798
	"FidoNet-style EchoMail program known as `SBBSecho` and the FidoNet/BinkP\n"
	"mailer known as `BinkIT`.  Alternatively, you may edit the configuration\n"
	"file (e.g. `ctrl/sbbsecho.ini`) using an ASCII/plain-text editor.\n"
rswindell's avatar
rswindell committed
799 800
	"\n"
	"For detailed documentation, see `http://wiki.synchro.net/util:sbbsecho`\n"
801
	"                            and `http://wiki.synchro.net/module:binkit`\n"
rswindell's avatar
rswindell committed
802
	"\n"
803
	"The `Global Settings` sub-menu is where FidoNet configuration settings\n"
rswindell's avatar
rswindell committed
804
	"are located which are neither NetMail nor EchoMail specific, but more\n"
805
	"general to the operation of the tosser (SBBSecho) and mailer (BinkIT).\n"
rswindell's avatar
rswindell committed
806 807 808 809 810 811 812
	"\n"
	"The `Linked Nodes` sub-menu is where you configure your FidoNet-style\n"
	"links: other FidoNet-style nodes/systems you regularly connect with\n"
	"to exchange mail/files.\n"
	"\n"
	"The `Archive Types` sub-menu is where you configure your archive\n"
	"programs (a.k.a. \"packers\") used for the packing and unpacking of\n"
813
	"EchoMail bundle files (usually in 'PKZIP' format).\n"
rswindell's avatar
rswindell committed
814 815 816 817 818 819 820 821 822 823
	"\n"
	"The `NetMail Settings` sub-menu is where you configure settings specific\n"
	"to NetMail (private one-on-one networked mail).\n"
	"\n"
	"The `EchoMail Settings` sub-menu is where you configure settings specific\n"
	"to EchoMail (public group discussions in topical message areas, echoes).\n"
	"\n"
	"The `Paths and Filenames` sub-menu is where you configure your system's\n"
	"directory and file paths used by SBBSecho.\n"
	"\n"
824 825 826
	"The `Robots` sub-menu is where NetMail Robots (e.g. TickFix) are\n"
	"configured.\n"
	"\n"
827 828 829 830
	"The `Domains` sub-menu is where FidoNet-style domains (the '@domain'\n"
	"of 5D FTN address) are mapped to zone numbers, DNS suffixes, NodeLists\n"
	"and BSO root directories for use by the BinkIT mailer.\n"
	"\n"
rswindell's avatar
rswindell committed
831 832 833
	"The `EchoLists` sub-menu is for configuring additional (optional)\n"
	"lists of FidoNet-style message areas (echoes) in `BACKBONE.NA` file\n"
	"format.  These lists, if configured, are used in addition to your main\n"
rswindell's avatar
rswindell committed
834
	"`Area File` (e.g. areas.bbs) for advanced AreaFix/AreaMgr operations."
rswindell's avatar
rswindell committed
835
	;
836
		i=0;
837 838 839 840 841 842 843 844 845
		sprintf(opt[i++],"Global Settings");
		sprintf(opt[i++],"Linked Nodes");
		sprintf(opt[i++],"Archive Types");
		sprintf(opt[i++],"NetMail Settings");
		sprintf(opt[i++],"EchoMail Settings");
		sprintf(opt[i++],"Paths and Filenames");
		sprintf(opt[i++],"Robots");
		sprintf(opt[i++],"Domains");
		sprintf(opt[i++],"EchoLists");
846
		if(uifc.changes && !cfg.used_include)
rswindell's avatar
rswindell committed
847
			snprintf(opt[i++],MAX_OPLN-1,"Save Changes to %s", getfname(cfg.cfgfile));
rswindell's avatar
rswindell committed
848
		opt[i][0]=0;
rswindell's avatar
rswindell committed
849
		switch(uifc.list(WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC,0,0,0,&dflt,0
850
			,"Configure FidoNet",opt)) {
851

852
			case 0:
rswindell's avatar
rswindell committed
853
				global_settings();
854
				break;
855

856 857 858
			case 1:
				i=0;
				while(1) {
rswindell's avatar
rswindell committed
859
					uifc.helpbuf=
rswindell's avatar
rswindell committed
860 861 862 863 864
	"~ Linked Nodes ~\n\n"
	"From this menu you can configure the settings for your linked\n"
	"FidoNet-style nodes (uplinks and downlinks).\n"
	"\n"
	"A single node configuration can represent one node or a collection\n"
865 866 867 868
	"of nodes, by using the `ALL` wildcard word.\n"
	"\n"
	"The hexadecimal numbers in parentheses are provided as an aide when\n"
	"correlating FidoNet files and BSO directories with node numbers."
rswindell's avatar
rswindell committed
869 870
	;

rswindell's avatar
rswindell committed
871 872
					for(u=0;u<cfg.nodecfgs;u++) {
						char hexaddr[16] = "";
873 874 875 876 877 878 879
						if(cfg.nodecfg[u].addr.zone != 0xffff) {
							if(!faddr_contains_wildcard(&cfg.nodecfg[u].addr))
								sprintf(hexaddr, "(%04hx%04hx)", cfg.nodecfg[u].addr.net,cfg.nodecfg[u].addr.node);
							else
								sprintf(hexaddr, "(.%03X)", cfg.nodecfg[u].addr.zone);
						}
						snprintf(opt[u], MAX_OPLN-1, "%-16s %-10s  %s"
rswindell's avatar
rswindell committed
880 881 882
							,faddrtoa(&cfg.nodecfg[u].addr), hexaddr
							,cfg.nodecfg[u].name[0] ? cfg.nodecfg[u].name : cfg.nodecfg[u].comment);
					}
883
					opt[u][0]=0;
rswindell's avatar
rswindell committed
884
					int mode = WIN_SAV | WIN_INS | WIN_DEL | WIN_ACT
885
						| WIN_INSACT | WIN_DELACT | WIN_XTR;
886 887
					if(cfg.nodecfgs)
						mode |= WIN_COPY | WIN_CUT;
888
					if (savnodecfg.addr.zone)
889
						mode |= WIN_PASTE | WIN_PASTEXTR;
890
					i=uifc.list(mode,0,0,0,&node_opt,&node_bar,"Linked Nodes",opt);
891 892
					if(i==-1)
						break;
893 894 895
					int msk = i&MSK_ON;
					i &= MSK_OFF;
					if (msk == MSK_INS) {
896 897
						str[0]=0;
	uifc.helpbuf=
rswindell's avatar
rswindell committed
898 899 900 901
	"~ Address ~\n\n"
	"This is the FidoNet style address of the node you wish to add (3D or 4D).\n"
	"The `ALL` wildcard may be usd for portions of the address.\n"
	;
rswindell's avatar
rswindell committed
902
						if(uifc.input(WIN_MID|WIN_SAV,0,0
903 904 905
							,"Node Address (ALL wildcard allowed)",str
							,25,K_EDIT)<1)
							continue;
906
						if(!new_node(i)) {
907
							printf("\nMemory Allocation Error\n");
rswindell's avatar
rswindell committed
908
							exit(1);
909
						}
rswindell's avatar
rswindell committed
910 911
						cfg.nodecfg[i].addr=atofaddr(str);
						uifc.changes=TRUE;
rswindell's avatar
rswindell committed
912
						continue;
913
					}
914

915
					if (msk == MSK_DEL || msk == MSK_CUT) {
916 917
						if(msk == MSK_CUT)
							memcpy(&savnodecfg, &cfg.nodecfg[i], sizeof(nodecfg_t));
918 919 920
						cfg.nodecfgs--;
						if(cfg.nodecfgs<=0) {
							cfg.nodecfgs=0;
rswindell's avatar
rswindell committed
921
							continue;
922
						}
923 924
						for(u=i;u<cfg.nodecfgs;u++)
							memcpy(&cfg.nodecfg[u],&cfg.nodecfg[u+1]
925
								,sizeof(nodecfg_t));
rswindell's avatar
rswindell committed
926
						uifc.changes=TRUE;
rswindell's avatar
rswindell committed
927
						continue;
928
					}
929
					if (msk == MSK_COPY) {
930
						memcpy(&savnodecfg,&cfg.nodecfg[i],sizeof(nodecfg_t));
rswindell's avatar
rswindell committed
931
						continue;
932
					}
933 934 935
					if (msk == MSK_PASTE) {
						if(!new_node(i))
							continue;
936
						memcpy(&cfg.nodecfg[i],&savnodecfg,sizeof(nodecfg_t));
rswindell's avatar
rswindell committed
937
						uifc.changes=TRUE;
rswindell's avatar
rswindell committed
938
						continue;
939
					}
940 941
					while(1) {
	uifc.helpbuf=
rswindell's avatar
rswindell committed
942 943 944 945 946 947 948 949
	"~ Linked Node Settings ~\n"
	"\n"
	"`Address` is the FidoNet-style address in the Zone:Net/Node (3D) or\n"
	"    Zone:Net/Node.Point (4D) format. The wildcard word '`ALL`' may be used\n"
	"    in place of one of the fields to create a node configuration which\n"
	"    will apply to *all* nodes matching that address pattern.\n"
	"    e.g. '`1:ALL`' matches all nodes within FidoNet Zone 1.\n"
	"\n"
950
	"`Name` is name of the system operator of the configured node. This is used\n"
rswindell's avatar
rswindell committed
951 952
	"    as the destination name for AreaFix Notification NetMail messages.\n"
	"\n"
rswindell's avatar
rswindell committed
953
	"`Comment` is a note to yourself about this node. Setting this to the\n"
rswindell's avatar
rswindell committed
954 955
	"    BBS name or official FidoNet title corresponding with the configured\n"
	"    node can be a helpful reminder to yourself later.\n"
rswindell's avatar
rswindell committed
956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
	"\n"
	"`Archive Type` is the name of an archive type corresponding with one of\n"
	"    your configured archive types or '`None`'.  This archive type will\n"
	"    be used when creating EchoMail bundles or if `None`, raw/uncompressed\n"
	"    EchoMail packets will be sent to this node.\n"
	"    This setting may be managed by the node using AreaFix requests.\n"
	"\n"
	"`Packet Type` is the type of outbound packet generated for this node.\n"
	"    Incoming packet types are automatically detected from among the list\n"
	"    of supported packet types (`2`, `2.2`, `2e`, and `2+`).\n"
	"    The default outbound packet type is `2+`.\n"
	"\n"
	"`Packet Password` is an optional password that may be added to outbound\n"
	"    packets for this node.  Incoming packet passwords are compared with\n"
	"    this password value.  If this password is blank/empty and `Strict\n"
	"    Packet Passwords` are enabled, then incoming packets from this node\n"
	"    must also have no password.  Packet passwords are case insensitive.\n"
	"    This setting may be managed by the node using AreaFix requests.\n"
	"\n"
975 976 977 978
	"`Session Password` is the password that will be used for authenticated\n"
	"    BinkP sessions with this node. Session passwords are case sensitive.\n"
	"    This password is only used by BinkIT (if you choose to use it).\n"
	"\n"
rswindell's avatar
rswindell committed
979
	"`TIC File Password` is an optional password that may be configured here\n"
rswindell's avatar
rswindell committed
980
	"    (and in your `sbbsecho.ini` file) for use by `tickit.js` when creating\n"
rswindell's avatar
rswindell committed
981 982 983
	"    or authenticating `.TIC` files.\n"
	"    This setting may be managed by the node using AreaFix requests.\n"
	"\n"
rswindell's avatar
rswindell committed
984 985
	"`AreaFix Support` is a toggle that determines whether or not this node\n"
	"    may send AreaFix NetMail requests to your system to perform remote\n"
986
	"    area and account management.\n"
rswindell's avatar
rswindell committed
987 988 989
	"\n"
	"`AreaFix Password` is an optional password used to authenticate inbound\n"
	"    AreaFix NetMail requests (Remote Area Management) from this node.\n"
rswindell's avatar
rswindell committed
990 991 992
	"    AreaFix Passwords are case insensitive.\n"
	"    This setting may be managed by the node using AreaFix requests.\n"
	"\n"
rswindell's avatar
rswindell committed
993
	"`EchoList Keys` is a list of keys which enable AreaFix access to one or\n"
rswindell's avatar
rswindell committed
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
	"    more additional EchoLists.\n"
	"\n"
	"`Status` is the default mode for sending mail to this node: `Normal`, `Hold`\n"
	"    (wait for pickup) or `Crash` (immediate).\n"
	"\n"
	"`Direct` determines whether to connect to this node directly (whenever\n"
	"    possible) when sending mail to this node.\n"
	"\n"
	"`Passive` is used to temporarily disable (pause) the packing and sending\n"
	"    of EchoMail for this node.  The opposite of Passive is `Active`.\n"
	"    This setting may be managed by the node using AreaFix requests.\n"
	"\n"
	"`Send Notify List` is used to flag nodes that you want notified via\n"
	"    NetMail of their current AreaFix settings whenever SBBSecho is run\n"
	"    with the '`G`' option.\n"
	"\n"
	"`Uplink for Message Groups` is an optional list of Message Groups (short\n"
	"    names) for which this node is a hub/uplink for your system.  This\n"
	"    setting is used in combination with the `Auto Add Sub-boards` feature\n"
	"    to auto-link hubs with the newly added areas in your Area File.\n"
	"\n"
rswindell's avatar
rswindell committed
1015 1016 1017 1018 1019 1020
	"`Local Address` is an optional local system address (AKA) to use when\n"
	"    sending packets to this node.  When a Local Address is not specified\n"
	"    SBBSecho will automatically choose the local address that matches\n"
	"    the destination address (zone and net number) the closest\n"
	"    (Best Match).\n"
	"\n"
rswindell's avatar
rswindell committed
1021 1022 </