Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

js_console.cpp 57.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/* js_console.cpp */

/* Synchronet JavaScript "Console" Object */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
rswindell's avatar
rswindell committed
11
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *																			*
 * 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										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"
39
#include "js_request.h"
40 41 42 43 44 45 46

#ifdef JAVASCRIPT

/*****************************/
/* Console Object Properites */
/*****************************/
enum {
47
	 CON_PROP_STATUS
48
	,CON_PROP_LNCNTR
49
	,CON_PROP_COLUMN
50
	,CON_PROP_LASTLINELEN
rswindell's avatar
rswindell committed
51
	,CON_PROP_ATTR
52 53
	,CON_PROP_TOS
	,CON_PROP_ROWS
rswindell's avatar
rswindell committed
54
	,CON_PROP_COLUMNS
rswindell's avatar
rswindell committed
55
	,CON_PROP_TABSTOP
56
	,CON_PROP_AUTOTERM
rswindell's avatar
rswindell committed
57
	,CON_PROP_TERMINAL
58 59
	,CON_PROP_TERM_TYPE
	,CON_PROP_CHARSET
60
	,CON_PROP_CTERM_VERSION
rswindell's avatar
rswindell committed
61
	,CON_PROP_WORDWRAP
62
	,CON_PROP_QUESTION
63 64
	,CON_PROP_INACTIV_WARN
	,CON_PROP_INACTIV_HANGUP
65
	,CON_PROP_TIMEOUT			/* User inactivity timeout reference */
66
	,CON_PROP_TIMELEFT_WARN		/* low timeleft warning counter */
67
	,CON_PROP_ABORTED
rswindell's avatar
rswindell committed
68 69
	,CON_PROP_ABORTABLE
	,CON_PROP_TELNET_MODE
70
	,CON_PROP_GETSTR_OFFSET
71
	,CON_PROP_CTRLKEY_PASSTHRU
72 73 74 75 76
	/* read only */
	,CON_PROP_INBUF_LEVEL
	,CON_PROP_INBUF_SPACE
	,CON_PROP_OUTBUF_LEVEL
	,CON_PROP_OUTBUF_SPACE
rswindell's avatar
rswindell committed
77 78
};

79
extern JSClass js_console_class;
80
static JSBool js_console_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
81
{
82 83
	jsval		idval;
	int32		val;
84
    jsint       tiny;
85
	JSString*	js_str;
86 87
	sbbs_t*		sbbs;

88
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, obj, &js_console_class))==NULL)
89 90
		return(JS_FALSE);

91 92
    JS_IdToValue(cx, id, &idval);
    tiny = JSVAL_TO_INT(idval);
93 94 95 96 97 98 99 100

	switch(tiny) {
		case CON_PROP_STATUS:
			val=sbbs->console;
			break;
		case CON_PROP_LNCNTR:
			val=sbbs->lncntr;
			break;
101 102 103
		case CON_PROP_COLUMN:
			val=sbbs->column;
			break;
104 105 106
		case CON_PROP_LASTLINELEN:
			val=sbbs->lastlinelen;
			break;
rswindell's avatar
rswindell committed
107 108 109
		case CON_PROP_ATTR:
			val=sbbs->curatr;
			break;
110 111 112 113 114 115
		case CON_PROP_TOS:
			val=sbbs->tos;
			break;
		case CON_PROP_ROWS:
			val=sbbs->rows;
			break;
rswindell's avatar
rswindell committed
116 117 118
		case CON_PROP_COLUMNS:
			val=sbbs->cols;
			break;
rswindell's avatar
rswindell committed
119 120 121
		case CON_PROP_TABSTOP:
			val=sbbs->tabstop;
			break;
122 123 124
		case CON_PROP_AUTOTERM:
			val=sbbs->autoterm;
			break;
rswindell's avatar
rswindell committed
125 126 127 128 129
		case CON_PROP_TERMINAL:
			if((js_str=JS_NewStringCopyZ(cx, sbbs->terminal))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
			return(JS_TRUE);
130 131 132 133 134 135 136 137 138 139
		case CON_PROP_TERM_TYPE:
			if((js_str=JS_NewStringCopyZ(cx, sbbs->term_type()))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
			return(JS_TRUE);
		case CON_PROP_CHARSET:
			if((js_str=JS_NewStringCopyZ(cx, sbbs->term_charset()))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
			return(JS_TRUE);
140 141 142
		case CON_PROP_CTERM_VERSION:
			val=sbbs->cterm_version;
			break;
143 144 145 146 147 148 149

		case CON_PROP_INACTIV_WARN:
			val=sbbs->cfg.sec_warn;
			break;
		case CON_PROP_INACTIV_HANGUP:
			val=sbbs->cfg.sec_hangup;
			break;
150
		case CON_PROP_TIMEOUT:
151
			val=(int32)sbbs->timeout;
152 153 154 155
			break;
		case CON_PROP_TIMELEFT_WARN:
			val=sbbs->timeleft_warn;
			break;
156
		case CON_PROP_ABORTED:
157 158
			*vp=BOOLEAN_TO_JSVAL(INT_TO_BOOL(sbbs->sys_status&SS_ABORT));
			return(JS_TRUE);
rswindell's avatar
rswindell committed
159
		case CON_PROP_ABORTABLE:
160 161
			*vp=BOOLEAN_TO_JSVAL(INT_TO_BOOL(sbbs->rio_abortable));
			return(JS_TRUE);
rswindell's avatar
rswindell committed
162 163 164
		case CON_PROP_TELNET_MODE:
			val=sbbs->telnet_mode;
			break;
165 166 167
		case CON_PROP_GETSTR_OFFSET:
			val=sbbs->getstr_offset;
			break;
rswindell's avatar
rswindell committed
168
		case CON_PROP_WORDWRAP:
169 170 171
			if((js_str=JS_NewStringCopyZ(cx, sbbs->wordwrap))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
rswindell's avatar
rswindell committed
172
			return(JS_TRUE);
173
		case CON_PROP_QUESTION:
174 175 176
			if((js_str=JS_NewStringCopyZ(cx, sbbs->question))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
177
			return(JS_TRUE);
178 179 180
		case CON_PROP_CTRLKEY_PASSTHRU:
			val=sbbs->cfg.ctrlkey_passthru;
			break;
181 182 183 184 185 186 187 188 189 190 191 192
		case CON_PROP_INBUF_LEVEL:
			val=RingBufFull(&sbbs->inbuf);
			break;
		case CON_PROP_INBUF_SPACE:
			val=RingBufFree(&sbbs->inbuf);
			break;
		case CON_PROP_OUTBUF_LEVEL:
			val=RingBufFull(&sbbs->outbuf);
			break;
		case CON_PROP_OUTBUF_SPACE:
			val=RingBufFree(&sbbs->outbuf);
			break;
193

194 195 196 197 198 199 200 201 202
		default:
			return(JS_TRUE);
	}

	*vp = INT_TO_JSVAL(val);

	return(JS_TRUE);
}

203
static JSBool js_console_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
204
{
205
	jsval idval;
206
	int32		val=0;
207 208
    jsint       tiny;
	sbbs_t*		sbbs;
209
	JSString*	str;
deuce's avatar
deuce committed
210
	jsrefcount	rc;
deuce's avatar
deuce committed
211
	char		*sval;
212

213
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, obj, &js_console_class))==NULL)
214 215
		return(JS_FALSE);

216 217
    JS_IdToValue(cx, id, &idval);
    tiny = JSVAL_TO_INT(idval);
218

219 220 221 222
	if(JSVAL_IS_NUMBER(*vp) || JSVAL_IS_BOOLEAN(*vp)) {
		if(!JS_ValueToInt32(cx, *vp, &val))
			return JS_FALSE;
	}
223 224 225 226 227 228 229 230

	switch(tiny) {
		case CON_PROP_STATUS:
			sbbs->console=val;
			break;
		case CON_PROP_LNCNTR:
			sbbs->lncntr=val;
			break;
231 232 233
		case CON_PROP_COLUMN:
			sbbs->column=val;
			break;
234 235 236
		case CON_PROP_LASTLINELEN:
			sbbs->lastlinelen=val;
			break;
rswindell's avatar
rswindell committed
237
		case CON_PROP_ATTR:
238
			if(JSVAL_IS_STRING(*vp)) {
deuce's avatar
deuce committed
239
				JSVALUE_TO_MSTRING(cx, *vp, sval, NULL);
deuce's avatar
deuce committed
240
				if(sval==NULL)
241
					break;
deuce's avatar
deuce committed
242
				val=attrstr(sval);
deuce's avatar
deuce committed
243
				free(sval);
244
			}
245
			rc=JS_SUSPENDREQUEST(cx);
rswindell's avatar
rswindell committed
246
			sbbs->attr(val);
247
			JS_RESUMEREQUEST(cx, rc);
rswindell's avatar
rswindell committed
248
			break;
249
		case CON_PROP_TOS:
250
			sbbs->tos = val ? true : false;
251 252
			break;
		case CON_PROP_ROWS:
rswindell's avatar
rswindell committed
253 254
			if(val >= TERM_ROWS_MIN && val <= TERM_ROWS_MAX)
				sbbs->rows=val;
255
			break;
rswindell's avatar
rswindell committed
256
		case CON_PROP_COLUMNS:
rswindell's avatar
rswindell committed
257 258 259 260 261
			if(val >= TERM_COLS_MIN && val <= TERM_COLS_MAX)
				sbbs->cols=val;
			break;
		case CON_PROP_TABSTOP:
			sbbs->tabstop=val;
rswindell's avatar
rswindell committed
262
			break;
263 264 265
		case CON_PROP_AUTOTERM:
			sbbs->autoterm=val;
			break;
rswindell's avatar
rswindell committed
266
		case CON_PROP_TERMINAL:
deuce's avatar
deuce committed
267
			JSVALUE_TO_MSTRING(cx, *vp, sval, NULL);
deuce's avatar
deuce committed
268
			if(sval==NULL)
rswindell's avatar
rswindell committed
269
				break;
deuce's avatar
deuce committed
270
			SAFECOPY(sbbs->terminal,sval);
deuce's avatar
deuce committed
271
			free(sval);
rswindell's avatar
rswindell committed
272
			break;
273 274 275
		case CON_PROP_CTERM_VERSION:
			sbbs->cterm_version = val;
			break;
276 277 278 279 280 281
		case CON_PROP_INACTIV_WARN:
			sbbs->cfg.sec_warn = (uint16_t)val;
			break;
		case CON_PROP_INACTIV_HANGUP:
			sbbs->cfg.sec_hangup = (uint16_t)val;
			break;
282 283 284 285 286 287
		case CON_PROP_TIMEOUT:
			sbbs->timeout=val;
			break;
		case CON_PROP_TIMELEFT_WARN:
			sbbs->timeleft_warn=val;
			break;
288 289 290 291 292 293
		case CON_PROP_ABORTED:
			if(val)
				sbbs->sys_status|=SS_ABORT;
			else
				sbbs->sys_status&=~SS_ABORT;
			break;
rswindell's avatar
rswindell committed
294
		case CON_PROP_ABORTABLE:
295
			sbbs->rio_abortable=val
rswindell's avatar
rswindell committed
296
				? true:false; // This is a dumb bool conversion to make BC++ happy
rswindell's avatar
rswindell committed
297 298 299 300
			break;
		case CON_PROP_TELNET_MODE:
			sbbs->telnet_mode=val;
			break;
301 302 303
		case CON_PROP_GETSTR_OFFSET:
			sbbs->getstr_offset=val;
			break;
304
		case CON_PROP_QUESTION:
deuce's avatar
deuce committed
305
			JSVALUE_TO_MSTRING(cx, *vp, sval, NULL);
deuce's avatar
deuce committed
306
			if(sval==NULL)
307
				break;
deuce's avatar
deuce committed
308
			SAFECOPY(sbbs->question,sval);
deuce's avatar
deuce committed
309
			free(sval);
310
			break;
311
		case CON_PROP_CTRLKEY_PASSTHRU:
312 313 314
			if(JSVAL_IS_STRING(*vp)) {
				char *s;

315 316
				if((str=JS_ValueToString(cx, *vp))==NULL)
					break;
deuce's avatar
deuce committed
317 318 319
				JSSTRING_TO_MSTRING(cx, str, s, NULL);
				if(s==NULL)
					break;
320
				val=str_to_bits(sbbs->cfg.ctrlkey_passthru, s);
deuce's avatar
deuce committed
321
				free(s);
322
			}
323 324
			sbbs->cfg.ctrlkey_passthru=val;
			break;
325

326 327 328 329 330 331 332
		default:
			return(JS_TRUE);
	}

	return(JS_TRUE);
}

rswindell's avatar
rswindell committed
333
#define CON_PROP_FLAGS JSPROP_ENUMERATE
334

335 336 337 338 339
static jsSyncPropertySpec js_console_properties[] = {
/*		 name				,tinyid						,flags			,ver	*/

	{	"status"			,CON_PROP_STATUS			,CON_PROP_FLAGS	,310},
	{	"line_counter"		,CON_PROP_LNCNTR 			,CON_PROP_FLAGS	,310},
340
	{	"current_column"	,CON_PROP_COLUMN			,CON_PROP_FLAGS ,315},
341
	{	"last_line_length"	,CON_PROP_LASTLINELEN		,CON_PROP_FLAGS	,317},
342 343 344 345
	{	"attributes"		,CON_PROP_ATTR				,CON_PROP_FLAGS	,310},
	{	"top_of_screen"		,CON_PROP_TOS				,CON_PROP_FLAGS	,310},
	{	"screen_rows"		,CON_PROP_ROWS				,CON_PROP_FLAGS	,310},
	{	"screen_columns"	,CON_PROP_COLUMNS			,CON_PROP_FLAGS	,311},
rswindell's avatar
rswindell committed
346
	{	"tabstop"			,CON_PROP_TABSTOP			,CON_PROP_FLAGS	,31700},
347 348
	{	"autoterm"			,CON_PROP_AUTOTERM			,CON_PROP_FLAGS	,310},
	{	"terminal"			,CON_PROP_TERMINAL			,CON_PROP_FLAGS ,311},
349 350
	{	"type"				,CON_PROP_TERM_TYPE			,JSPROP_ENUMERATE|JSPROP_READONLY ,31702},
	{	"charset"			,CON_PROP_CHARSET			,JSPROP_ENUMERATE|JSPROP_READONLY ,31702},
351
	{	"cterm_version"		,CON_PROP_CTERM_VERSION		,CON_PROP_FLAGS ,317},
352 353
	{	"inactivity_warning",CON_PROP_INACTIV_WARN		,CON_PROP_FLAGS, 31401},
	{	"inactivity_hangup"	,CON_PROP_INACTIV_HANGUP	,CON_PROP_FLAGS, 31401},
354 355 356 357 358 359 360 361 362
	{	"timeout"			,CON_PROP_TIMEOUT			,CON_PROP_FLAGS	,310},
	{	"timeleft_warning"	,CON_PROP_TIMELEFT_WARN		,CON_PROP_FLAGS	,310},
	{	"aborted"			,CON_PROP_ABORTED			,CON_PROP_FLAGS	,310},
	{	"abortable"			,CON_PROP_ABORTABLE			,CON_PROP_FLAGS	,310},
	{	"telnet_mode"		,CON_PROP_TELNET_MODE		,CON_PROP_FLAGS	,310},
	{	"wordwrap"			,CON_PROP_WORDWRAP			,JSPROP_ENUMERATE|JSPROP_READONLY ,310},
	{	"question"			,CON_PROP_QUESTION			,CON_PROP_FLAGS ,310},
	{	"getstr_offset"		,CON_PROP_GETSTR_OFFSET		,CON_PROP_FLAGS ,311},
	{	"ctrlkey_passthru"	,CON_PROP_CTRLKEY_PASSTHRU	,CON_PROP_FLAGS	,310},
363 364 365 366
	{	"input_buffer_level",CON_PROP_INBUF_LEVEL		,JSPROP_ENUMERATE|JSPROP_READONLY, 312},
	{	"input_buffer_space",CON_PROP_INBUF_SPACE		,JSPROP_ENUMERATE|JSPROP_READONLY, 312},
	{	"output_buffer_level",CON_PROP_OUTBUF_LEVEL		,JSPROP_ENUMERATE|JSPROP_READONLY, 312},
	{	"output_buffer_space",CON_PROP_OUTBUF_SPACE		,JSPROP_ENUMERATE|JSPROP_READONLY, 312},
367 368 369
	{0}
};

370
#ifdef BUILD_JSDOCS
371
static const char* con_prop_desc[] = {
372
	 "status bit-field (see <tt>CON_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)"
373 374
	,"current 0-based line counter (used for automatic screen pause)"
	,"current 0-based column counter (used to auto-increment <i>line_counter</i> when screen wraps)"
375
	,"length of last line sent to terminal (before a carriage-return or line-wrap)"
376
	,"current display attributes (set with number or string value)"
377 378 379
	,"set to <i>true</i> if the terminal cursor is already at the top of the screen"
	,"number of remote terminal screen rows (in lines)"
	,"number of remote terminal screen columns (in character cells)"
rswindell's avatar
rswindell committed
380
	,"current tab stop interval (tab size), in columns"
381
	,"bit-field of automatically detected terminal settings "
382
		"(see <tt>USER_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)"
383 384 385
	,"terminal type description, possibly supplied by client (e.g. 'ANSI')"
	,"terminal type (i.e. 'ANSI', 'RIP', 'PETSCII', or 'DUMB')"
	,"terminal character set (i.e. 'UTF-8', 'CP437', 'CBM-ASCII', or 'US-ASCII')"
386
	,"detected CTerm (SyncTERM) version as an integer > 1000 where major version is cterm_version / 1000 and minor version is cterm_version % 1000"
387 388 389 390
	,"number of seconds before displaying warning (Are you really there?) due to user/keyboard inactivity"
	,"number of seconds before disconnection due to user/keyboard inactivity"
	,"user/keyboard inactivity timeout reference value (time_t format)"
	,"number of low time-left (5 or fewer minutes remaining) warnings displayed to user"
391
	,"input/output has been aborted"
392
	,"remote output can be asynchronously aborted with Ctrl-C"
393
	,"current Telnet mode bit-field (see <tt>TELNET_MODE_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)"
394
	,"word-wrap buffer (used by getstr) - <small>READ ONLY</small>"
395
	,"current yes/no question (set by yesno and noyes)"
396
	,"cursor position offset for use with <tt>getstr(K_USEOFFSET)</tt>"
397
	,"control key pass-through bit-mask, set bits represent control key combinations "
398 399
		"<i>not</i> handled by <tt>inkey()</tt> method "
		"This may optionally be specified as a string of characters. "
deuce's avatar
deuce committed
400
		"The format of this string is [+-][@-_]. If neither plus nor minus is "
401
		"the first character, the value will be replaced by one constructed "
deuce's avatar
deuce committed
402
		"from the string. A + indicates that characters following will be "
403
		"added to the set, and a - indicates they should be removed. "
rswindell's avatar
rswindell committed
404
		"ex: <tt>console.ctrlkey_passthru=\"-UP+AB\"</tt> will clear CTRL-U and "
405
		"CTRL-P and set CTRL-A and CTRL-B."
406 407 408 409
	,"number of bytes currently in the input buffer (from the remote client) - <small>READ ONLY</small>"
	,"number of bytes available in the input buffer	- <small>READ ONLY</small>"
	,"number of bytes currently in the output buffer (from the local server) - <small>READ ONLY</small>"
	,"number of bytes available in the output buffer - <small>READ ONLY</small>"
410
	,NULL
411 412 413
};
#endif

414 415 416 417 418
/**************************/
/* Console Object Methods */
/**************************/

static JSBool
419
js_inkey(JSContext *cx, uintN argc, jsval *arglist)
420
{
421
	jsval *argv=JS_ARGV(cx, arglist);
422
	char		key[2];
423 424
	int32		mode=0;
	int32		timeout=0;
425 426
	sbbs_t*		sbbs;
    JSString*	js_str;
deuce's avatar
deuce committed
427
	jsrefcount	rc;
428

429
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
430 431
		return(JS_FALSE);

432 433
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

434 435 436 437 438 439 440 441
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&mode))
			return JS_FALSE;
	}
	if(argc>1) {
		if(!JS_ValueToInt32(cx,argv[1],&timeout))
			return JS_FALSE;
	}
442
	rc=JS_SUSPENDREQUEST(cx);
443
	key[0]=sbbs->inkey(mode,timeout);
444
	JS_RESUMEREQUEST(cx, rc);
445 446
	key[1]=0;

447 448 449
	if((js_str = JS_NewStringCopyZ(cx, key))==NULL)
		return(JS_FALSE);

450
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
451 452 453 454
    return(JS_TRUE);
}

static JSBool
455
js_getkey(JSContext *cx, uintN argc, jsval *arglist)
456
{
457
	jsval *argv=JS_ARGV(cx, arglist);
458
	char		key[2];
459
	int32		mode=0;
460 461
	sbbs_t*		sbbs;
    JSString*	js_str;
deuce's avatar
deuce committed
462
	jsrefcount	rc;
463

464
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
465 466
		return(JS_FALSE);

467 468
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

469 470 471 472
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&mode))
			return JS_FALSE;
	}
473
	rc=JS_SUSPENDREQUEST(cx);
474
	key[0]=sbbs->getkey(mode);
475
	JS_RESUMEREQUEST(cx, rc);
476 477
	key[1]=0;

478 479 480
	if((js_str = JS_NewStringCopyZ(cx, key))==NULL)
		return(JS_FALSE);

481
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
482 483 484
    return(JS_TRUE);
}

rswindell's avatar
rswindell committed
485 486 487 488 489 490 491 492
static JSBool
js_getbyte(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval *argv=JS_ARGV(cx, arglist);
	int32		timeout=0;
	sbbs_t*		sbbs;
	jsrefcount	rc;

493
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
rswindell's avatar
rswindell committed
494 495
		return JS_FALSE;

496 497
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

rswindell's avatar
rswindell committed
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0], &timeout))
			return JS_FALSE;
	}
	rc=JS_SUSPENDREQUEST(cx);
	int32 byte = sbbs->incom(timeout);
	JS_RESUMEREQUEST(cx, rc);

	if(byte != NOINP)
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(byte));
    return JS_TRUE;
}

static JSBool
js_putbyte(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval *argv=JS_ARGV(cx, arglist);
	int32		byte=0;
	sbbs_t*		sbbs;
	jsrefcount	rc;

519
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
rswindell's avatar
rswindell committed
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
		return JS_FALSE;

	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0], &byte))
			return JS_FALSE;
	}
	rc=JS_SUSPENDREQUEST(cx);
	int result = sbbs->outcom(byte);
	JS_RESUMEREQUEST(cx, rc);

	JS_SET_RVAL(cx, arglist, result == 0 ? JSVAL_TRUE : JSVAL_FALSE);
    return JS_TRUE ;
}


rswindell's avatar
rswindell committed
535
static JSBool
536
js_handle_ctrlkey(JSContext *cx, uintN argc, jsval *arglist)
rswindell's avatar
rswindell committed
537
{
538
	jsval *argv=JS_ARGV(cx, arglist);
539
	char		key;
rswindell's avatar
rswindell committed
540
	int32		mode=0;
rswindell's avatar
rswindell committed
541
	sbbs_t*		sbbs;
deuce's avatar
deuce committed
542
	jsrefcount	rc;
deuce's avatar
deuce committed
543
	char		*keystr;
rswindell's avatar
rswindell committed
544

545
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
rswindell's avatar
rswindell committed
546 547
		return(JS_FALSE);

548 549
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

550 551 552
	if(JSVAL_IS_INT(argv[0]))
		key=(char)JSVAL_TO_INT(argv[0]);
	else {
deuce's avatar
deuce committed
553
		JSVALUE_TO_ASTRING(cx, argv[0], keystr, 2, NULL);
deuce's avatar
deuce committed
554
		if(keystr==NULL)
555
			return(JS_FALSE);
deuce's avatar
deuce committed
556
		key=keystr[0];
557
	}
rswindell's avatar
rswindell committed
558

559 560 561 562
	if(argc>1) {
		if(!JS_ValueToInt32(cx, argv[1], &mode))
			return JS_FALSE;
	}
rswindell's avatar
rswindell committed
563

564
	rc=JS_SUSPENDREQUEST(cx);
565
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->handle_ctrlkey(key,mode)==0));
566
	JS_RESUMEREQUEST(cx, rc);
rswindell's avatar
rswindell committed
567 568 569
    return(JS_TRUE);
}

570
static JSBool
571
js_getstr(JSContext *cx, uintN argc, jsval *arglist)
572
{
573
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
574
	char		*p,*p2;
575
	int32		mode=0;
576
	uintN		i;
577
	int32		maxlen=0;
578 579
	sbbs_t*		sbbs;
    JSString*	js_str=NULL;
deuce's avatar
deuce committed
580
	jsrefcount	rc;
581
	str_list_t	history = NULL;
582

583
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
584 585
		return(JS_FALSE);

586 587
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

588
	for(i=0;i<argc;i++) {
589
		if(JSVAL_IS_NUMBER(argv[i])) {
590
			if(!maxlen) {
591
				if(!JS_ValueToInt32(cx,argv[i],&maxlen))
592 593 594
					return JS_FALSE;
			}
			else {
595
				if(!JS_ValueToInt32(cx,argv[i],&mode))
596 597
					return JS_FALSE;
			}
598
		}
599
		else if(JSVAL_IS_STRING(argv[i])) {
600 601 602 603
			js_str = JS_ValueToString(cx, argv[i]);
			if (!js_str)
			    return(JS_FALSE);
		}
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
		else if(JSVAL_IS_OBJECT(argv[i])) {
			JSObject* array = JSVAL_TO_OBJECT(argv[i]);
			jsuint len=0;
			if(!JS_GetArrayLength(cx, array, &len))
				return JS_FALSE;
			history = (str_list_t)alloca(sizeof(char*) * (len + 1));
			memset(history, 0, sizeof(char*) * (len + 1));
			for(jsuint j=0; j < len; j++) {
				jsval		val;
				if(!JS_GetElement(cx, array, j, &val))
					break;
				JSString* hist = JS_ValueToString(cx, val);
				if (hist == NULL)
					return JS_FALSE;
				char* cstr = NULL;
				JSSTRING_TO_ASTRING(cx, hist, cstr, (uint)(maxlen ? maxlen : 80), NULL);
				if(cstr == NULL)
					return JS_FALSE;
				history[j] = cstr;
			}
		}
625 626 627 628 629 630 631
	}

	if(!maxlen) maxlen=128;

	if((p=(char *)calloc(1,maxlen+1))==NULL)
		return(JS_FALSE);

deuce's avatar
deuce committed
632
	if(js_str!=NULL) {
deuce's avatar
deuce committed
633
		JSSTRING_TO_MSTRING(cx, js_str, p2, NULL);
634 635
		if(p2==NULL) {
			free(p);
deuce's avatar
deuce committed
636
			return JS_FALSE;
637
		}
deuce's avatar
deuce committed
638
		sprintf(p,"%.*s",(int)maxlen,p2);
deuce's avatar
deuce committed
639
		free(p2);
deuce's avatar
deuce committed
640
	}
641

642
	rc=JS_SUSPENDREQUEST(cx);
643
	sbbs->getstr(p, maxlen, mode, history);
644
	JS_RESUMEREQUEST(cx, rc);
645 646 647 648 649

	js_str = JS_NewStringCopyZ(cx, p);

	free(p);

650 651 652
	if(js_str==NULL)
		return(JS_FALSE);

653
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
654 655 656 657
    return(JS_TRUE);
}

static JSBool
658
js_getnum(JSContext *cx, uintN argc, jsval *arglist)
659
{
660
	jsval *argv=JS_ARGV(cx, arglist);
661
	uint32_t	maxnum=~0;
662
	int32_t		dflt=0;
663
	sbbs_t*		sbbs;
deuce's avatar
deuce committed
664
	jsrefcount	rc;
665

666
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
667 668
		return(JS_FALSE);

669 670
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

671 672 673 674 675
	if(argc && JSVAL_IS_NUMBER(argv[0])) {
		if(!JS_ValueToInt32(cx,argv[0],(int32*)&maxnum))
			return JS_FALSE;
	}
	if(argc>1 && JSVAL_IS_NUMBER(argv[1])) {
676
		if(!JS_ValueToInt32(cx,argv[1],&dflt))
677 678
			return JS_FALSE;
	}
679

680
	rc=JS_SUSPENDREQUEST(cx);
681
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(sbbs->getnum(maxnum,dflt)));
682
	JS_RESUMEREQUEST(cx, rc);
683 684 685 686
    return(JS_TRUE);
}

static JSBool
687
js_getkeys(JSContext *cx, uintN argc, jsval *arglist)
688
{
689
	jsval *argv=JS_ARGV(cx, arglist);
690 691
	char		key[2];
	uintN		i;
692
	int32		val;
693 694
	uint32		maxnum = 0;
	long		mode = K_UPPER;
695 696
	sbbs_t*		sbbs;
    JSString*	js_str=NULL;
697
	char*		cstr=NULL;
deuce's avatar
deuce committed
698
	jsrefcount	rc;
699

700
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
701 702
		return(JS_FALSE);

703 704
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

705
	for(i=0;i<argc;i++) {
706
		if(JSVAL_IS_NUMBER(argv[i])) {
707
			if(!JS_ValueToInt32(cx, argv[i], &val))
708
				return JS_FALSE;
709 710 711 712
			if(maxnum == 0)
				maxnum = val;
			else
				mode = val;
713 714 715 716
			continue;
		}
		if(JSVAL_IS_STRING(argv[i])) {
			js_str = JS_ValueToString(cx, argv[i]);
717 718 719
			JSSTRING_TO_MSTRING(cx, js_str, cstr, NULL);
			if(cstr==NULL)
				return JS_FALSE;
720 721 722
		}
	}

723 724 725
	if(maxnum == 0)
		maxnum = ~0;

726
	rc=JS_SUSPENDREQUEST(cx);
727
	val=sbbs->getkeys(cstr, maxnum, mode);
728
	FREE_AND_NULL(cstr);
729
	JS_RESUMEREQUEST(cx, rc);
730 731

	if(val==-1) {			// abort
732
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(0));
733 734
	} else if(val<0) {		// number
		val&=~0x80000000;
735
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(val));
736 737 738
	} else {				// key
		key[0]=(uchar)val;
		key[1]=0;
739 740
		if((js_str = JS_NewStringCopyZ(cx, key))==NULL)
			return(JS_FALSE);
741
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
742 743 744 745 746 747
	}

    return(JS_TRUE);
}

static JSBool
748
js_gettemplate(JSContext *cx, uintN argc, jsval *arglist)
749
{
750
	jsval *argv=JS_ARGV(cx, arglist);
751
	char		str[128];
752
	int32		mode=0;
753 754 755 756
	uintN		i;
	sbbs_t*		sbbs;
    JSString*	js_str=NULL;
    JSString*	js_fmt=NULL;
deuce's avatar
deuce committed
757 758
	jsrefcount	rc;
	char*		cstr;
759

760
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
761 762
		return(JS_FALSE);

763 764
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

765 766 767 768 769 770
	for(i=0;i<argc;i++) {
		if(JSVAL_IS_STRING(argv[i])) {
			if(js_fmt==NULL)
				js_fmt = JS_ValueToString(cx, argv[i]);
			else
				js_str = JS_ValueToString(cx, argv[i]);
771 772 773 774
		} else if(JSVAL_IS_NUMBER(argv[i])) {
			if(!JS_ValueToInt32(cx,argv[i],(int32*)&mode))
				return JS_FALSE;
		}
775 776 777 778 779 780 781
	}

	if(js_fmt==NULL)
		return(JS_FALSE);

	if(js_str==NULL)
		str[0]=0;
deuce's avatar
deuce committed
782
	else {
deuce's avatar
deuce committed
783
		JSSTRING_TO_STRBUF(cx, js_str, str, sizeof(str), NULL);
deuce's avatar
deuce committed
784
	}
785

deuce's avatar
deuce committed
786 787 788
	JSSTRING_TO_MSTRING(cx, js_fmt, cstr, NULL);
	if(cstr==NULL)
		return JS_FALSE;
789
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
790
	sbbs->gettmplt(str,cstr,mode);
deuce's avatar
deuce committed
791
	free(cstr);
792
	JS_RESUMEREQUEST(cx, rc);
793 794 795 796

	if((js_str=JS_NewStringCopyZ(cx, str))==NULL)
		return(JS_FALSE);

797
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
798 799 800 801
    return(JS_TRUE);
}

static JSBool
802
js_ungetstr(JSContext *cx, uintN argc, jsval *arglist)
803
{
804
	jsval *argv=JS_ARGV(cx, arglist);
805
	char*		p;
deuce's avatar
deuce committed
806
	char*		op;
807 808
	sbbs_t*		sbbs;
    JSString*	js_str;
deuce's avatar
deuce committed
809
	jsrefcount	rc;
810

811
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
812
		return(JS_FALSE);
813

814 815
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

816 817 818
	if((js_str=JS_ValueToString(cx, argv[0]))==NULL)
		return(JS_FALSE);

deuce's avatar
deuce committed
819 820 821
	JSSTRING_TO_MSTRING(cx, js_str, op, NULL);
	if(op==NULL)
		return JS_FALSE;
822

deuce's avatar
deuce committed
823
	p=op;
824
	rc=JS_SUSPENDREQUEST(cx);
825 826
	while(p && *p)
		sbbs->ungetkey(*(p++));
deuce's avatar
deuce committed
827
	free(op);
828
	JS_RESUMEREQUEST(cx, rc);
829 830 831 832
    return(JS_TRUE);
}

static JSBool
833
js_yesno(JSContext *cx, uintN argc, jsval *arglist)
834
{
835
	jsval *argv=JS_ARGV(cx, arglist);
836 837
	sbbs_t*		sbbs;
    JSString*	js_str;