sbbs.h 51.6 KB
Newer Older
1 2 3 4 5 6
/* Synchronet class (sbbs_t) definition and exported function prototypes */

/****************************************************************************
 * @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 21 22 23 24 25 26 27 28
 *																			*
 * 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.	*
 ****************************************************************************/

#ifndef _SBBS_H
#define _SBBS_H

/****************************/
/* Standard library headers */
/****************************/

rswindell's avatar
rswindell committed
29 30 31
/***************/
/* OS-specific */
/***************/
32
#if defined(_WIN32)			/* Windows */
33

deuce's avatar
deuce committed
34 35 36
	#define NOCRYPT     /* Stop windows.h from loading wincrypt.h */
                    /* Is windows.h REALLY necessary?!?! */
	#define WIN32_LEAN_AND_MEAN
37 38 39 40 41 42
	#include <io.h>
	#include <share.h>
	#include <windows.h>
	#include <process.h>	/* _beginthread() prototype */
	#include <direct.h>		/* _mkdir() prototype */
	#include <mmsystem.h>	/* SND_ASYNC */
43

44
	#if defined(_DEBUG) && defined(_MSC_VER)
45 46 47
		#include <crtdbg.h> /* Windows debug macros and stuff */
	#endif

48
#if defined(__cplusplus)
49
	extern "C"
50
#endif
deuce's avatar
deuce committed
51
	HINSTANCE hK32;
52

53
#elif defined(__unix__)		/* Unix-variant */
54

55
	#include <unistd.h>		/* close */
56 57 58

#endif

59 60 61 62 63 64
#ifdef _THREAD_SUID_BROKEN
extern int	thread_suid_broken;			/* NPTL is no longer broken */
#else
#define thread_suid_broken FALSE
#endif

rswindell's avatar
rswindell committed
65 66 67
/******************/
/* ANSI C Library */
/******************/
68 69 70 71
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
72
#include <fcntl.h>			/* open */
73 74 75
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
76

77
#ifndef __unix__
78 79 80 81 82

	#include <malloc.h>

#endif

83 84
#include <sys/stat.h>

deuce's avatar
deuce committed
85 86 87 88 89 90
#ifdef __unix__
	#define XP_UNIX
#else
	#define XP_PC
	#define XP_WIN
#endif
rswindell's avatar
rswindell committed
91 92 93

#if defined(JAVASCRIPT)
#include "comio.h"			/* needed for COM_HANDLE definition only */
94
#if __GNUC__ > 5
rswindell's avatar
rswindell committed
95 96 97 98
	#pragma GCC diagnostic push
	#pragma GCC diagnostic ignored "-Wmisleading-indentation"
	#pragma GCC diagnostic ignored "-Wignored-attributes"
#endif
deuce's avatar
deuce committed
99 100
#include <jsversion.h>
#include <jsapi.h>
101
#if __GNUC_ > 5
rswindell's avatar
rswindell committed
102 103
	#pragma GCC diagnostic pop
#endif
deuce's avatar
deuce committed
104
#define JS_DestroyScript(cx,script)
105

106 107
#define JSSTRING_TO_RASTRING(cx, str, ret, sizeptr, lenptr) \
{ \
108
	size_t			*JSSTSlenptr=(lenptr); \
109 110 111 112 113 114 115 116 117
	size_t			JSSTSlen; \
	size_t			JSSTSpos; \
	const jschar	*JSSTSstrval; \
	char			*JSSTStmpptr; \
\
	if(JSSTSlenptr==NULL) \
		JSSTSlenptr=&JSSTSlen; \
	if((str) != NULL) { \
		if((JSSTSstrval=JS_GetStringCharsAndLength((cx), (str), JSSTSlenptr))) { \
118 119 120
			if((*(sizeptr) < (*JSSTSlenptr+1 )) || (ret)==NULL) { \
				*(sizeptr) = *JSSTSlenptr+1; \
				if((JSSTStmpptr=(char *)realloc((ret), *(sizeptr)))==NULL) { \
121
					JS_ReportError(cx, "Error reallocating %lu bytes at %s:%d", (*JSSTSlenptr)+1, getfname(__FILE__), __LINE__); \
122
					if((ret) != NULL) free(ret); \
123 124 125 126 127 128 129 130 131 132 133 134 135
					(ret)=NULL; \
				} \
				else { \
					(ret)=JSSTStmpptr; \
				} \
			} \
			if(ret) { \
				for(JSSTSpos=0; JSSTSpos<*JSSTSlenptr; JSSTSpos++) \
					(ret)[JSSTSpos]=(char)JSSTSstrval[JSSTSpos]; \
				(ret)[*JSSTSlenptr]=0; \
			} \
		} \
	} \
deuce's avatar
deuce committed
136 137
	else { \
		if(ret) \
138
			*(ret)=0; \
deuce's avatar
deuce committed
139
	} \
140 141 142 143 144 145 146 147
}

#define JSVALUE_TO_RASTRING(cx, val, ret, sizeptr, lenptr) \
{ \
	JSString	*JSVTSstr=JS_ValueToString((cx), (val)); \
	JSSTRING_TO_RASTRING((cx), JSVTSstr, (ret), (sizeptr), (lenptr)); \
}

148 149
#define JSSTRING_TO_MSTRING(cx, str, ret, lenptr) \
{ \
150
	size_t			*JSSTSlenptr=(lenptr); \
151 152 153 154 155 156 157 158 159 160 161 162 163 164
	size_t			JSSTSlen; \
	size_t			JSSTSpos; \
	const jschar	*JSSTSstrval; \
\
	if(JSSTSlenptr==NULL) \
		JSSTSlenptr=&JSSTSlen; \
	(ret)=NULL; \
	if((str) != NULL) { \
		if((JSSTSstrval=JS_GetStringCharsAndLength((cx), (str), JSSTSlenptr))) { \
			if(((ret)=(char *)malloc(*JSSTSlenptr+1))) { \
				for(JSSTSpos=0; JSSTSpos<*JSSTSlenptr; JSSTSpos++) \
					(ret)[JSSTSpos]=(char)JSSTSstrval[JSSTSpos]; \
				(ret)[*JSSTSlenptr]=0; \
			} \
165
			else JS_ReportError((cx), "Error allocating %lu bytes at %s:%d", (*JSSTSlenptr)+1, getfname(__FILE__), __LINE__); \
166 167 168 169 170 171 172 173 174 175
		} \
	} \
}

#define JSVALUE_TO_MSTRING(cx, val, ret, lenptr) \
{ \
	JSString	*JSVTSstr=JS_ValueToString((cx), (val)); \
	JSSTRING_TO_MSTRING((cx), JSVTSstr, (ret), lenptr); \
}

176 177
#define JSSTRING_TO_STRBUF(cx, str, ret, bufsize, lenptr) \
{ \
178
	size_t			*JSSTSlenptr=(lenptr); \
179 180 181 182 183 184
	size_t			JSSTSlen; \
	size_t			JSSTSpos; \
	const jschar	*JSSTSstrval; \
\
	if(JSSTSlenptr==NULL) \
		JSSTSlenptr=&JSSTSlen; \
185
	if((bufsize) < 1 || (str)==NULL) \
186 187 188
		*JSSTSlenptr = 0; \
	else { \
		if((JSSTSstrval=JS_GetStringCharsAndLength((cx), (str), JSSTSlenptr))) { \
189 190
			if(*JSSTSlenptr >= (bufsize)) \
				*JSSTSlenptr = (bufsize)-1; \
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
			for(JSSTSpos=0; JSSTSpos<*JSSTSlenptr; JSSTSpos++) \
				(ret)[JSSTSpos]=(char)JSSTSstrval[JSSTSpos]; \
		} \
		else \
			*JSSTSlenptr=0; \
	} \
	(ret)[*JSSTSlenptr]=0; \
}

#define JSVALUE_TO_STRBUF(cx, val, ret, bufsize, lenptr) \
{ \
	JSString	*JSVTSstr=JS_ValueToString((cx), (val)); \
	JSSTRING_TO_STRBUF((cx), JSVTSstr, (ret), (bufsize), lenptr); \
}

206 207 208 209 210 211
#define HANDLE_PENDING(cx, p ) \
	if(JS_IsExceptionPending(cx)) { \
		if(p != NULL) \
			free(p); \
		return JS_FALSE; \
	}
212

213 214
#define JSSTRING_TO_ASTRING(cx, str, ret, maxsize, lenptr) \
{ \
215
	size_t			*JSSTSlenptr=(lenptr); \
216 217 218 219 220 221 222 223 224
	size_t			JSSTSlen; \
	size_t			JSSTSpos; \
	const jschar	*JSSTSstrval; \
\
	if(JSSTSlenptr==NULL) \
		JSSTSlenptr=&JSSTSlen; \
	(ret)=NULL; \
	if((str) != NULL) { \
		if((JSSTSstrval=JS_GetStringCharsAndLength((cx), (str), JSSTSlenptr))) { \
225 226 227
			if(*JSSTSlenptr >= (maxsize)) { \
				*JSSTSlenptr = (maxsize)-1; \
			} \
228
			if(((ret)=(char *)alloca(*JSSTSlenptr+1))) { \
229
				for(JSSTSpos=0; JSSTSpos<*JSSTSlenptr; JSSTSpos++) { \
230
					(ret)[JSSTSpos]=(char)JSSTSstrval[JSSTSpos]; \
231
				} \
232 233
				(ret)[*JSSTSlenptr]=0; \
			} \
234
			else JS_ReportError((cx), "Error allocating %lu bytes on stack at %s:%d", (*JSSTSlenptr)+1, getfname(__FILE__), __LINE__); \
235 236 237 238 239 240 241 242 243 244
		} \
	} \
}

#define JSVALUE_TO_ASTRING(cx, val, ret, maxsize, lenptr) \
{ \
	JSString	*JSVTSstr=JS_ValueToString((cx), (val)); \
	JSSTRING_TO_ASTRING((cx), JSVTSstr, (ret), (maxsize), (lenptr)); \
}

rswindell's avatar
rswindell committed
245 246
#endif

247 248 249 250
#ifdef USE_CRYPTLIB
#include <cryptlib.h>
#endif

251
/* xpdev */
252 253 254
#ifndef LINK_LIST_THREADSAFE
 #define LINK_LIST_THREADSAFE
#endif
255
#include "genwrap.h"
rswindell's avatar
rswindell committed
256
#include "semfile.h"
257
#include "netwrap.h"
258 259
#include "dirwrap.h"
#include "filewrap.h"
260
#include "datewrap.h"
261
#include "sockwrap.h"
deuce's avatar
deuce committed
262
#include "multisock.h"
263
#include "eventwrap.h"
264
#include "link_list.h"
265
#include "msg_queue.h"
266
#include "xpdatetime.h"
267
#include "unicode_defs.h"
268

269 270 271 272 273 274 275 276
/***********************/
/* Synchronet-specific */
/***********************/
#include "startup.h"
#ifdef __cplusplus
	#include "threadwrap.h"	/* pthread_mutex_t */
#endif

277 278 279
#include "smblib.h"
#include "ars_defs.h"
#include "scfglib.h"
280
#include "scfgsave.h"
281 282 283 284 285
#include "userdat.h"
#include "riodefs.h"
#include "cmdshell.h"
#include "ringbuf.h"    /* RingBuf definition */
#include "client.h"		/* client_t definition */
286 287
#include "crc16.h"
#include "crc32.h"
288
#include "telnet.h"
289
#include "nopen.h"
290
#include "text.h"
291 292 293 294 295 296 297
#include "str_util.h"
#include "date_str.h"
#include "load_cfg.h"
#include "getstats.h"
#include "msgdate.h"
#include "getmail.h"
#include "msg_id.h"
298

Deucе's avatar
Deucе committed
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
#if defined(JAVASCRIPT)
enum js_event_type {
	JS_EVENT_SOCKET_READABLE_ONCE,
	JS_EVENT_SOCKET_READABLE,
	JS_EVENT_SOCKET_WRITABLE_ONCE,
	JS_EVENT_SOCKET_WRITABLE,
	JS_EVENT_SOCKET_CONNECT,
	JS_EVENT_INTERVAL,
	JS_EVENT_TIMEOUT,
	JS_EVENT_CONSOLE_INPUT_ONCE,
	JS_EVENT_CONSOLE_INPUT
};

struct js_event_interval {
	uint64_t last;	// The tick the last event should have triggered at
	uint64_t period;
};

struct js_event_timeout {
	uint64_t end;	// Time the timeout expires
};

struct js_event_connect {
	SOCKET sv[2];
	SOCKET sock;
};

struct js_event_list {
	struct js_event_list *prev;
	struct js_event_list *next;
	JSFunction *cb;
	JSObject *cx;
	union {
		SOCKET	sock;
		struct js_event_connect connect;
		struct js_event_interval interval;
		struct js_event_timeout timeout;
	} data;
	int32 id;
	enum js_event_type type;
};

struct js_runq_entry {
	JSFunction *func;
	JSObject *cx;
	struct js_runq_entry *next;
};

struct js_listener_entry {
	char *name;
	JSFunction *func;
	int32 id;
	struct js_listener_entry *next;
};

typedef struct js_callback {
	struct js_event_list	*events;
	struct js_runq_entry    *rq_head;
	struct js_runq_entry    *rq_tail;
	struct js_listener_entry *listeners;
	volatile BOOL*	terminated;
	struct js_callback	*parent_cb;
	uint32_t		counter;
	uint32_t		limit;
	uint32_t		yield_interval;
	uint32_t		gc_interval;
	uint32_t		gc_attempts;
	uint32_t		offline_counter;
	int32			next_eid;
	BOOL			auto_terminate;
	BOOL			keepGoing;
	BOOL			bg;
	BOOL			events_supported;
} js_callback_t;
#endif

375
/* Synchronet Node Instance class definition */
376
#if defined(__cplusplus) && defined(JAVASCRIPT)
377 378 379 380 381 382 383 384 385

struct mouse_hotspot {		// Mouse hot-spot
	char	cmd[128];
	long	y;
	long	minx;
	long	maxx;
	bool	hungry;
};

386 387 388 389 390
class sbbs_t
{

public:

deuce's avatar
deuce committed
391
	sbbs_t(ushort node_num, union xp_sockaddr *addr, size_t addr_len, const char* host_name, SOCKET
392
		,scfg_t*, char* text[], client_t* client_info, bool is_event_thread = false);
393 394
	~sbbs_t();

395 396
	bbs_startup_t*	startup;

397
	bool	init(void);
398
	BOOL	terminated;
399 400 401 402

	client_t client;
	SOCKET	client_socket;
	SOCKET	client_socket_dup;
deuce's avatar
deuce committed
403
	union xp_sockaddr	client_addr;
404
	char	client_name[128];
rswindell's avatar
rswindell committed
405
	char	client_ident[128];
deuce's avatar
deuce committed
406 407
	char	client_ipaddr[INET6_ADDRSTRLEN];
	char	local_addr[INET6_ADDRSTRLEN];
408
#ifdef USE_CRYPTLIB
409
	CRYPT_SESSION	ssh_session;
410
#endif
deuce's avatar
deuce committed
411
	int		session_channel;
412
	bool	ssh_mode;
413
	SOCKET	passthru_socket;
414
	bool	passthru_socket_active;
415
	void	passthru_socket_activate(bool);
416
    bool	passthru_thread_running;
417 418 419

	scfg_t	cfg;

420 421 422 423 424 425 426 427 428
	enum ansiState {
		 ansiState_none		// No sequence
		,ansiState_esc		// Escape
		,ansiState_csi		// CSI
		,ansiState_final	// Final byte
		,ansiState_string	// APS, DCS, PM, or OSC
		,ansiState_sos		// SOS
		,ansiState_sos_esc	// ESC inside SOS
	} outchar_esc;			// track ANSI escape seq output
429 430 431 432 433 434

	int 	rioctl(ushort action); // remote i/o control
	bool	rio_abortable;

    RingBuf	inbuf;
    RingBuf	outbuf;
435
	bool	WaitForOutbufEmpty(int timeout) { return WaitForEvent(outbuf.empty_event, timeout) == WAIT_OBJECT_0; }
436
	HANDLE	input_thread;
437
	pthread_mutex_t	input_thread_mutex;
438
	bool	input_thread_mutex_created;
439
	pthread_mutex_t	ssh_mutex;
440
	bool	ssh_mutex_created;
441

442 443 444 445
	#define OUTCOM_RETRY_DELAY		80		// milliseconds
	#define OUTCOM_RETRY_ATTEMPTS	1000	// 80 seconds
	int 	_outcom(uchar ch); 	   // send character, without retry (on buffer flow condition)
	int		outcom(uchar ch, int max_attempts = OUTCOM_RETRY_ATTEMPTS);		// send character, with retry
446
	int 	incom(unsigned long timeout=0);		   // receive character
447

448
	void	spymsg(const char *msg);		// send message to active spies
449

450
	int		putcom(const char *str, size_t len=0);  // Send string
451 452
	void	hangup(void);		   // Hangup modem

453 454
	uchar	telnet_local_option[0x100];
	uchar	telnet_remote_option[0x100];
rswindell's avatar
rswindell committed
455
	void	send_telnet_cmd(uchar cmd, uchar opt);
456
	bool	request_telnet_opt(uchar cmd, uchar opt, unsigned waitforack=0);
457

458 459 460
	uchar	telnet_cmd[64];
	uint	telnet_cmdlen;
	ulong	telnet_cmds_received;
461
	ulong	telnet_mode;
rswindell's avatar
rswindell committed
462
	/* 	input_thread() writes to these variables: */
463
	uchar	telnet_last_rxch;
464
	char	telnet_location[128];
rswindell's avatar
rswindell committed
465
	char	telnet_terminal[TELNET_TERM_MAXLEN+1];
466
	long 	telnet_rows;
rswindell's avatar
rswindell committed
467 468 469
	long	telnet_cols;
	long	telnet_speed;

470
	xpevent_t	telnet_ack_event;
471

472
	time_t	event_time;				// Time of next exclusive event
473
	const char*	event_code;				// Internal code of next exclusive event
474
	bool	is_event_thread;
475 476
	bool	event_thread_running;
    bool	output_thread_running;
477
    bool	input_thread_running;
478
	bool	terminate_output_thread;
479

480 481 482
	JSRuntime*		js_runtime;
	JSContext*		js_cx;
	JSObject*		js_glob;
483 484 485
	JSRuntime*		js_hotkey_runtime;
	JSContext*		js_hotkey_cx;
	JSObject*		js_hotkey_glob;
486
	js_callback_t	js_callback;
487
	long			js_execfile(const char *fname, const char* startup_dir, JSObject* scope = NULL, JSContext* cx = NULL, JSObject* glob = NULL);
488
	long			js_execxtrn(const char *fname, const char* startup_dir);
489
	JSContext*		js_init(JSRuntime**, JSObject**, const char* desc);
490
	void			js_cleanup(void);
491
	bool			js_create_user_objects(JSContext*, JSObject* glob);
492

493
	char	syspage_semfile[MAX_PATH+1];	/* Sysop page semaphore file */
494 495 496 497 498
	char 	menu_dir[128];	/* Over-ride default menu dir */
	char 	menu_file[128]; /* Over-ride menu file */

	user_t	useron; 		/* User currently online */
	node_t	thisnode;		/* Node information */
499 500 501 502 503 504
	smb_t	smb;			/* Currently active message base */
	link_list_t smb_list;
#define SMB_STACK_PUSH	true
#define SMB_STACK_POP	false
	int 	smb_stack(smb_t* smb, bool push);

505
	char	rlogin_name[LEN_ALIAS+1];
506
	char	rlogin_pass[LEN_PASS+1];
507
	char	rlogin_term[TELNET_TERM_MAXLEN+1];	/* RLogin passed terminal type/speed (e.g. "xterm/57600") */
508 509 510 511 512 513 514 515

	uint	temp_dirnum;

	FILE	*nodefile_fp,
			*node_ext_fp,
			*logfile_fp;

	int 	nodefile;		/* File handle for node.dab */
516
	pthread_mutex_t	nodefile_mutex;
517
	int		node_ext;		/* File handle for node.exb */
518 519
	size_t	batup_total();
	size_t	batdn_total();
520 521 522 523

	/*********************************/
	/* Color Configuration Variables */
	/*********************************/
524 525
	char 	*text[TOTAL_TEXT];			/* Text from ctrl\text.dat */
	char 	*text_sav[TOTAL_TEXT];		/* Text from ctrl\text.dat */
526 527 528 529 530
	char	yes_key(void) { return toupper(text[YNQP][0]); }
	char	no_key(void) { return toupper(text[YNQP][1]); }
	char	quit_key(void) { return toupper(text[YNQP][2]); }
	char	all_key(void) { return toupper(text[AllKey][0]); }
	char	list_key(void) { return toupper(text[ListKey][0]); }
531

532
	char 	dszlog[127];	/* DSZLOG environment variable */
533
    int     keybuftop,keybufbot;    /* Keyboard input buffer pointers (for ungetkey) */
534
	char    keybuf[KEY_BUFSIZE];    /* Keyboard input buffer */
535 536
	size_t	keybuf_space(void);
	size_t	keybuf_level(void);
537 538

	ushort	node_connection;
539
	char	connection[LEN_MODEM+1];	/* Connection Description */
540 541 542 543 544
	ulong	cur_rate;		/* Current Connection (DCE) Rate */
	ulong	cur_cps;		/* Current Average Transfer CPS */
	ulong	dte_rate;		/* Current COM Port (DTE) Rate */
	time_t 	timeout;		/* User inactivity timeout reference */
	ulong 	timeleft_warn;	/* low timeleft warning flag */
rswindell's avatar
rswindell committed
545 546
	uint	curatr; 		/* Current Text Attributes Always */
	uint	attr_stack[64];	/* Saved attributes (stack) */
547
	int 	attr_sp;		/* Attribute stack pointer */
548
	long 	lncntr; 		/* Line Counter - for PAUSE */
549
	bool	msghdr_tos;		/* Message header was displayed at Top of Screen */
rswindell's avatar
rswindell committed
550
	long	row;			/* Current row */
551 552
	long 	rows;			/* Current number of Rows for User */
	long	cols;			/* Current number of Columns for User */
553
	long	column;			/* Current column counter (for line counter) */
rswindell's avatar
rswindell committed
554
	long	tabstop;		/* Current symmetric-tabstop (size) */
555
	long	lastlinelen;	/* The previously displayed line length */
556
	long 	autoterm;		/* Auto-detected terminal type */
rswindell's avatar
rswindell committed
557
	char	terminal[TELNET_TERM_MAXLEN+1];	// <- answer() writes to this
558
	long	cterm_version;	/* (MajorVer*1000) + MinorVer */
559
	link_list_t savedlines;
560 561
	char 	lbuf[LINE_BUFSIZE+1];/* Temp storage for each line output */
	int		lbuflen;		/* Number of characters in line buffer */
rswindell's avatar
rswindell committed
562
	uint	latr;			/* Starting attribute of line buffer */
563 564
	ulong	console;		/* Defines current Console settings */
	char 	wordwrap[81];	/* Word wrap buffer */
565
	time_t	now,			/* Used to store current time in Unix format */
566
			last_sysop_auth,/* Time sysop was last authenticated */
567
			answertime, 	/* Time call was answered */
568 569
			logontime,		/* Time user logged on */
			starttime,		/* Time stamp to use for time left calcs */
570
			ns_time,		/* File new-scan time */
571 572 573 574
			last_ns_time;	/* Most recent new-file-scan this call */
	uchar 	action;			/* Current action of user */
	long 	online; 		/* Remote/Local or not online */
	long 	sys_status; 	/* System Status */
575
	subscan_t	*subscan;	/* User sub configuration/scan info */
576

577
	int64_t	logon_ulb,		/* Upload Bytes This Call */
578 579
			logon_dlb,		/* Download Bytes This Call */
			logon_uls,		/* Uploads This Call */
580 581
			logon_dls;		/* Downloads This Call */
	ulong	logon_posts,	/* Posts This Call */
582 583
			logon_emails,	/* Emails This Call */
			logon_fbacks;	/* Feedbacks This Call */
584
	uchar	logon_ml;		/* Security level of the user upon logon */
585 586 587 588

	uint 	main_cmds;		/* Number of Main Commands this call */
	uint 	xfer_cmds;		/* Number of Xfer Commands this call */
	ulong	posts_read; 	/* Number of Posts read this call */
589
	bool 	autohang;		/* Used for auto-hangup after transfer */
590 591 592
	size_t 	logcol; 		/* Current column of log file */
	uint 	criterrs; 		/* Critical error counter */

593 594 595 596 597 598
	uint 	curgrp; 		/* Current group */
	uint	*cursub;		/* Current sub-board for each group */
	uint	curlib; 		/* Current library */
	uint	*curdir;		/* Current directory for each library */
	uint 	*usrgrp;		/* Real group numbers */
	uint	usrgrps;		/* Number groups this user has access to */
599
	uint	usrgrp_total;	/* Total number of groups */
600 601
	uint 	*usrlib;		/* Real library numbers */
	uint	usrlibs;		/* Number of libs this user can access */
602
	uint	usrlib_total;	/* Total number of libraries */
603 604 605 606
	uint 	**usrsub;		/* Real sub numbers */
	uint	*usrsubs;		/* Num of subs with access for each grp */
	uint 	**usrdir;		/* Real dir numbers */
	uint	*usrdirs;		/* Num of dirs with access for each lib */
607 608 609
	uint	cursubnum;		/* For ARS */
	uint	curdirnum;		/* For ARS */
	ulong 	timeleft;		/* Number of seconds user has left online */
610

611 612 613 614 615 616 617 618
	char 	*comspec;		/* Pointer to environment variable COMSPEC */
	char 	cid[LEN_CID+1]; /* Caller ID (IP Address) of current caller */
	char 	*noaccess_str;	/* Why access was denied via ARS */
	long 	noaccess_val;	/* Value of parameter not met in ARS */
	int		errorlevel; 	/* Error level of external program */

	csi_t	main_csi;		/* Main Command Shell Image */

619
	smbmsg_t*	current_msg;	/* For message header @-codes */
rswindell's avatar
rswindell committed
620 621 622
	const char*	current_msg_subj;
	const char*	current_msg_from;
	const char*	current_msg_to;
623
	file_t*	current_file;	
624

625 626 627
			/* Global command shell variables */
	uint	global_str_vars;
	char **	global_str_var;
rswindell's avatar
rswindell committed
628
	uint32_t *	global_str_var_name;
629
	uint	global_int_vars;
deuce's avatar
deuce committed
630
	int32_t *	global_int_var;
rswindell's avatar
rswindell committed
631
	uint32_t *	global_int_var_name;
632 633
	char *	sysvar_p[MAX_SYSVARS];
	uint	sysvar_pi;
deuce's avatar
deuce committed
634
	int32_t	sysvar_l[MAX_SYSVARS];
635 636 637
	uint	sysvar_li;

    /* ansi_term.cpp */
638 639
	const char*	ansi(int atr);			/* Returns ansi escape sequence for atr */
	char*	ansi(int atr, int curatr, char* str);
640 641 642 643
    bool	ansi_gotoxy(int x, int y);
	bool	ansi_getxy(int* x, int* y);
	bool	ansi_save(void);
	bool	ansi_restore(void);
644
	void	ansi_getlines(void);
645 646 647 648 649 650 651
	enum ansi_mouse_mode {
		ANSI_MOUSE_X10	= 9,
		ANSI_MOUSE_NORM	= 1000,
		ANSI_MOUSE_BTN	= 1002,
		ANSI_MOUSE_ANY	= 1003,
		ANSI_MOUSE_EXT	= 1006
	};
rswindell's avatar
rswindell committed
652
	int		ansi_mouse(enum ansi_mouse_mode, bool enable);
653 654 655 656

			/* Command Shell Methods */
	int		exec(csi_t *csi);
	int		exec_function(csi_t *csi);
657
	int		exec_misc(csi_t *csi, const char *path);
rswindell's avatar
rswindell committed
658 659 660
	int		exec_net(csi_t *csi);
	int		exec_msg(csi_t *csi);
	int		exec_file(csi_t *csi);
661
	long	exec_bin(const char *mod, csi_t *csi, const char* startup_dir=NULL);
662 663
	void	clearvars(csi_t *bin);
	void	freevars(csi_t *bin);
deuce's avatar
deuce committed
664 665
	char**	getstrvar(csi_t *bin, uint32_t name);
	int32_t*	getintvar(csi_t *bin, uint32_t name);
666 667
	char*	copystrvar(csi_t *csi, char *p, char *str);
	void	skipto(csi_t *csi, uchar inst);
668
	bool	ftp_cmd(csi_t* csi, SOCKET ctrl_sock, const char* cmdsrc, char* rsp);
rswindell's avatar
rswindell committed
669
	bool	ftp_put(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest);
670 671 672
	bool	ftp_get(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest, bool dir=false);
	SOCKET	ftp_data_sock(csi_t* csi, SOCKET ctrl_sock, SOCKADDR_IN*);

673 674 675
	bool	select_shell(void);
	bool	select_editor(void);

676 677 678
	void	sys_info(void);
	void	user_info(void);
	void	xfer_policy(void);
679 680

	void	xfer_prot_menu(enum XFER_TYPE);
681 682
	void	node_stats(uint node_num);
	void	sys_stats(void);
683
	void	logonlist(const char* args = "");
684
	bool	spy(uint node_num);
685 686 687

	void	reset_logon_vars(void);

688
	uint	finduser(const char* str, bool silent_failure = false);
689 690 691 692 693 694 695 696 697

	int 	sub_op(uint subnum);

	int		dir_op(uint dirnum);

	void	getmsgptrs(void);
	void	putmsgptrs(void);
	void	getusrsubs(void);
	void	getusrdirs(void);
698 699
	uint	getusrsub(uint subnum);
	uint	getusrgrp(uint subnum);
700 701
	uint	getusrdir(uint dirnum);
	uint	getusrlib(uint dirnum);
702

703
	uint	userdatdupe(uint usernumber, uint offset, uint datlen, char *dat
704
				,bool del=false, bool next=false);
705
	ulong	gettimeleft(bool handle_out_of_time=true);
706 707 708
	bool	gettimeleft_inside;

	/* str.cpp */
709
	char*	server_host_name(void);
710 711
	char*	timestr(time_t);
	char*	datestr(time_t);
712
    char	timestr_output[60];
713
	char	datestr_output[60];
714
	char*	age_of_posted_item(char* buf, size_t max, time_t);
715
	void	userlist(long mode);
716
	size_t	gettmplt(char *outstr, const char *tmplt, long mode);
717
	void	sif(char *fname, char *answers, long len);	/* Synchronet Interface File */
718 719 720 721
	void	sof(char *fname, char *answers, long len);
	void	create_sif_dat(char *siffile, char *datfile);
	void	read_sif_dat(char *siffile, char *datfile);
	void	printnodedat(uint number, node_t* node);
deuce's avatar
deuce committed
722
	bool	inputnstime32(time32_t *dt);
723
	bool	inputnstime(time_t *dt);
724
	bool	chkpass(char *pass, user_t* user, bool unique);
725
	char *	cmdstr(const char *instr, const char *fpath, const char *fspec, char *outstr, long mode = EX_UNSPECIFIED);
726 727 728 729
	char	cmdstr_output[512];

	void	subinfo(uint subnum);
	void	dirinfo(uint dirnum);
730
	bool	trashcan(const char *insearch, const char *name);
731 732
	void	time_bank(void);
	void	change_user(void);
733 734 735

	/* writemsg.cpp */
	void	automsg(void);
736
	bool	writemsg(const char *str, const char *top, char *subj, long mode, uint subnum
737
				,const char *to, const char* from, const char** editor=NULL, const char** charset=NULL);
738
	char*	quotes_fname(int xedit, char* buf, size_t len);
739
	char*	msg_tmp_fname(int xedit, char* fname, size_t len);
740
	char	putmsg(const char *str, long mode, long org_cols = 0, JSObject* obj = NULL);
741
	char	putmsgfrag(const char* str, long& mode, long org_cols = 0, JSObject* obj = NULL);
742
	bool	msgabort(bool clear = false);
743
	void	clearabort() { sys_status &= ~SS_ABORT; }
744 745
	bool	email(int usernumber, const char *top = NULL, const char *title = NULL
				, long mode = WM_NONE, smb_t* resmb = NULL, smbmsg_t* remsg = NULL);
746
	bool	forwardmsg(smb_t*, smbmsg_t*, const char* to, const char* subject = NULL, const char* comment = NULL);
747
	void	removeline(char *str, char *str2, char num, char skip);
748
	ulong	msgeditor(char *buf, const char *top, char *title);
749
	bool	editfile(char *path, bool msg=false);
rswindell's avatar
rswindell committed
750
	ushort	chmsgattr(smbmsg_t);
751
	bool	quotemsg(smb_t*, smbmsg_t*, bool tails = false);
752
	bool	editmsg(smb_t*, smbmsg_t*);
753
	void	editor_inf(int xeditnum, const char *to, const char* from, const char *subj, long mode
754
				,uint subnum, const char* tagfile);
755
	bool	copyfattach(uint to, uint from, const char* subj);
756
	bool	movemsg(smbmsg_t* msg, uint subnum);
757 758
	int		process_edited_text(char* buf, FILE* stream, long mode, unsigned* lines, unsigned maxlines);
	int		process_edited_file(const char* src, const char* dest, long mode, unsigned* lines, unsigned maxlines);
759
	void	editor_info_to_msg(smbmsg_t*, const char* editor, const char* charset);
760
	char	editor_details[128];
761

762
	/* postmsg.cpp */
763
	bool	postmsg(uint subnum, long wm_mode = WM_NONE, smb_t* resmb = NULL, smbmsg_t* remsg = NULL);
764

765 766 767
	/* mail.cpp */
	int		delmail(uint usernumber,int which);
	void	telluser(smbmsg_t* msg);
768
	void	delallmail(uint usernumber, int which, bool permanent=true, long lm_mode = 0);
769 770

	/* getmsg.cpp */
771
	int		loadmsg(smbmsg_t *msg, ulong number);
rswindell's avatar
rswindell committed
772
	void	show_msgattr(smbmsg_t*);
773
	void	show_msghdr(smb_t*, smbmsg_t*, const char *subj = NULL, const char* from = NULL, const char* to = NULL);
rswindell's avatar
rswindell committed
774 775
	bool	show_msg(smb_t*, smbmsg_t*, long p_mode = 0, post_t* post = NULL);
	bool	msgtotxt(smb_t*, smbmsg_t*, const char *fname, bool header = true, ulong gettxt_mode = GETMSGTXT_ALL);
776 777
	const char* msghdr_text(const smbmsg_t*, uint index);
	char	msghdr_utf8_text[128];
rswindell's avatar
rswindell committed
778 779
	const char* msghdr_field(const smbmsg_t*, const char* str, char* buf = NULL, bool can_utf8 = false);
	char	msgghdr_field_cp437_str[128];
780 781 782
	ulong	getlastmsg(uint subnum, uint32_t *ptr, time_t *t);
	time_t	getmsgtime(uint subnum, ulong ptr);
	ulong	getmsgnum(uint subnum, time_t t);
783
	void	download_msg_attachments(smb_t*, smbmsg_t*, bool del);
784 785

	/* readmail.cpp */
rswindell's avatar
rswindell committed
786
	void	readmail(uint usernumber, int which, long lm_mode = 0);
787
	bool	readmail_inside;
788
	long	searchmail(mail_t*, long start, long msgss, int which, const char *search, const char* order);
789 790

	/* bulkmail.cpp */
791 792
	bool	bulkmail(uchar *ar);
	int		bulkmailhdr(smb_t*, smbmsg_t*, uint usernum);
793 794

	/* con_out.cpp */
rswindell's avatar
rswindell committed
795
	size_t	bstrlen(const char *str, long mode = 0);
rswindell's avatar
rswindell committed
796
	int		bputs(const char *str, long mode = 0);	/* BBS puts function */
797
	int		bputs(long mode, const char* str) { return bputs(str, mode); }
798
	int		rputs(const char *str, size_t len=0);	/* BBS raw puts function */
799
	int		rputs(long mode, const char* str) { return rputs(str, mode); }
800 801 802
	int		bprintf(const char *fmt, ...)			/* BBS printf function */
#if defined(__GNUC__)   // Catch printf-format errors
    __attribute__ ((format (printf, 2, 3)));		// 1 is 'this'
rswindell's avatar
rswindell committed
803 804 805 806 807
#endif
	;
	int		bprintf(long mode, const char *fmt, ...)
#if defined(__GNUC__)   // Catch printf-format errors
    __attribute__ ((format (printf, 3, 4)));		// 1 is 'this', 2 is 'mode'
808 809 810 811 812
#endif
	;
	int		rprintf(const char *fmt, ...)			/* BBS raw printf function */
#if defined(__GNUC__)   // Catch printf-format errors
    __attribute__ ((format (printf, 2, 3)));		// 1 is 'this'
813 814 815 816 817
#endif
	;
	int		comprintf(const char *fmt, ...)			/* BBS direct-comm printf function */
#if defined(__GNUC__)   // Catch printf-format errors
    __attribute__ ((format (printf, 2, 3)));		// 1 is 'this'
818 819
#endif
	;
820
	void	backspace(int count=1);			/* Output destructive backspace(s) via outchar */
821
	int		outchar(char ch);				/* Output a char - check echo and emu.  */
822
	int		outchar(enum unicode_codepoint, char cp437_fallback);
823
	int		outchar(enum unicode_codepoint, const char* cp437_fallback = NULL);
rswindell's avatar
rswindell committed
824
	void	inc_row(int count);
825
	void	inc_column(int count);
Rob Swindell's avatar
Rob Swindell committed
826
	void	center(const char *str, unsigned int columns = 0);
rswindell's avatar
rswindell committed
827
	void	wide(const char*);
rswindell's avatar
rswindell committed
828
	void	clearscreen(long term);
829 830
	void	clearline(void);
	void	cleartoeol(void);
rswindell's avatar
rswindell committed
831
	void	cleartoeos(void);
832 833 834 835 836
	void	cursor_home(void);
	void	cursor_up(int count=1);
	void	cursor_down(int count=1);
	void	cursor_left(int count=1);
	void	cursor_right(int count=1);
837
	bool	cursor_xy(int x, int y);
838
	bool	cursor_getxy(int* x, int* y);
839 840 841
	void	carriage_return(int count=1);
	void	line_feed(int count=1);
	void	newline(int count=1);
842 843 844
	void	cond_newline() { if(column > 0) newline(); }
	void	cond_blankline() { if(column > 0) newline(); if(lastlinelen) newline(); }
	void	cond_contline() { if(column > 0 && cols < TERM_COLS_DEFAULT) bputs(text[LongLineContinuationPrefix]); }
845
	long	term_supports(long cmp_flags=0);
846 847
	const char* term_type(long term_supports = -1);
	const char* term_charset(long term_supports = -1);
848
	bool	update_nodeterm(void);
849
	int		backfill(const char* str, float pct, int full_attr, int empty_attr);
850
	void	progress(const char* str, int count, int total, int interval = 500);
851
	double	last_progress = 0;
852 853
	bool	saveline(void);
	bool	restoreline(void);
854
	int		petscii_to_ansibbs(unsigned char);
rswindell's avatar
rswindell committed
855
	size_t	print_utf8_as_cp437(const char*, size_t);
856 857
	int		attr(int);				/* Change text color/attributes */
	void	ctrl_a(char);			/* Performs Ctrl-Ax attribute changes */
858
	char*	auto_utf8(const char*, long& mode);
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
	enum output_rate {
		output_rate_unlimited,
		output_rate_300 = 300,
		output_rate_600 = 600,
		output_rate_1200 = 1200,
		output_rate_2400 = 2400,
		output_rate_4800 = 4800,
		output_rate_9600 = 9600,
		output_rate_19200 = 19200,
		output_rate_38400 = 38400,
		output_rate_57600 = 57600,
		output_rate_76800 = 76800,
		output_rate_115200 = 115200,
	} cur_output_rate;
	void	set_output_rate(enum output_rate);
874 875

	/* getstr.cpp */
876
	size_t	getstr_offset;
877
	size_t	getstr(char *str, size_t length, long mode, const str_list_t history = NULL);
878
	long	getnum(ulong max, ulong dflt=0);
879
	void	insert_indicator(void);
880 881

	/* getkey.cpp */
882
	char	getkey(long mode = K_NONE);
883
	long	getkeys(const char *str, ulong max, long mode = K_UPPER);
884
	void	ungetkey(char ch, bool insert = false);		/* Places 'ch' into the input buffer    */
rswindell's avatar
rswindell committed
885
	void	ungetstr(const char* str, bool insert = false);
886
	char	question[MAX_TEXTDAT_ITEM_LEN+1];
887 888
	bool	yesno(const char *str, long mode = 0);
	bool	noyes(const char *str, long mode = 0);
rswindell's avatar
rswindell committed
889
	bool	pause_inside;
890
	void	pause(void);