js_console.cpp 69.6 KB
Newer Older
1
2
3
4
5
6
/* Synchronet JavaScript "Console" Object */

/****************************************************************************
 * @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
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
 *																			*
 * 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.	*
 ****************************************************************************/

#include "sbbs.h"
23
#include "js_request.h"
24
25
26
27
28
29
30

#ifdef JAVASCRIPT

/*****************************/
/* Console Object Properites */
/*****************************/
enum {
31
	 CON_PROP_STATUS
32
	,CON_PROP_MOUSE_MODE
33
	,CON_PROP_LNCNTR
34
	,CON_PROP_COLUMN
35
	,CON_PROP_LASTLINELEN
36
	,CON_PROP_LINE_DELAY
rswindell's avatar
rswindell committed
37
	,CON_PROP_ATTR
38
	,CON_PROP_TOS
rswindell's avatar
rswindell committed
39
	,CON_PROP_ROW
40
	,CON_PROP_ROWS
rswindell's avatar
rswindell committed
41
	,CON_PROP_COLUMNS
rswindell's avatar
rswindell committed
42
	,CON_PROP_TABSTOP
43
	,CON_PROP_AUTOTERM
rswindell's avatar
rswindell committed
44
	,CON_PROP_TERMINAL
45
46
	,CON_PROP_TERM_TYPE
	,CON_PROP_CHARSET
47
	,CON_PROP_CTERM_VERSION
rswindell's avatar
rswindell committed
48
	,CON_PROP_WORDWRAP
49
	,CON_PROP_QUESTION
50
51
	,CON_PROP_INACTIV_WARN
	,CON_PROP_INACTIV_HANGUP
52
	,CON_PROP_TIMEOUT			/* User inactivity timeout reference */
53
	,CON_PROP_TIMELEFT_WARN		/* low timeleft warning counter */
54
	,CON_PROP_ABORTED
rswindell's avatar
rswindell committed
55
56
	,CON_PROP_ABORTABLE
	,CON_PROP_TELNET_MODE
57
	,CON_PROP_GETSTR_OFFSET
58
	,CON_PROP_CTRLKEY_PASSTHRU
59
60
61
62
63
	/* read only */
	,CON_PROP_INBUF_LEVEL
	,CON_PROP_INBUF_SPACE
	,CON_PROP_OUTBUF_LEVEL
	,CON_PROP_OUTBUF_SPACE
64
65
	,CON_PROP_KEYBUF_LEVEL
	,CON_PROP_KEYBUF_SPACE
66
67

	,CON_PROP_OUTPUT_RATE
rswindell's avatar
rswindell committed
68
69
};

70
extern JSClass js_console_class;
71
static JSBool js_console_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
72
{
73
74
	jsval		idval;
	int32		val;
75
    jsint       tiny;
76
	JSString*	js_str;
77
78
	sbbs_t*		sbbs;

79
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, obj, &js_console_class))==NULL)
80
81
		return(JS_FALSE);

82
83
    JS_IdToValue(cx, id, &idval);
    tiny = JSVAL_TO_INT(idval);
84
85
86
87
88

	switch(tiny) {
		case CON_PROP_STATUS:
			val=sbbs->console;
			break;
89
90
91
		case CON_PROP_MOUSE_MODE:
			val=sbbs->mouse_mode;
			break;
92
93
94
		case CON_PROP_LNCNTR:
			val=sbbs->lncntr;
			break;
95
96
97
		case CON_PROP_COLUMN:
			val=sbbs->column;
			break;
98
99
100
		case CON_PROP_LASTLINELEN:
			val=sbbs->lastlinelen;
			break;
101
102
103
		case CON_PROP_LINE_DELAY:
			val = sbbs->line_delay;
			break;
rswindell's avatar
rswindell committed
104
105
106
		case CON_PROP_ATTR:
			val=sbbs->curatr;
			break;
107
		case CON_PROP_TOS:
rswindell's avatar
rswindell committed
108
109
110
111
			val=sbbs->row == 0;
			break;
		case CON_PROP_ROW:
			val=sbbs->row;
112
113
114
115
			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
		case CON_PROP_OUTPUT_RATE:
			val = sbbs->cur_output_rate;
			break;
196
197
198
199
200
201
		case CON_PROP_KEYBUF_LEVEL:
			val = sbbs->keybuf_level();
			break;
		case CON_PROP_KEYBUF_SPACE:
			val = sbbs->keybuf_space();
			break;
202

203
204
205
206
207
208
209
210
211
		default:
			return(JS_TRUE);
	}

	*vp = INT_TO_JSVAL(val);

	return(JS_TRUE);
}

212
static JSBool js_console_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
213
{
214
	jsval idval;
215
	int32		val=0;
216
217
    jsint       tiny;
	sbbs_t*		sbbs;
218
	JSString*	str;
deuce's avatar
deuce committed
219
	jsrefcount	rc;
deuce's avatar
deuce committed
220
	char		*sval;
221

222
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, obj, &js_console_class))==NULL)
223
224
		return(JS_FALSE);

225
226
    JS_IdToValue(cx, id, &idval);
    tiny = JSVAL_TO_INT(idval);
227

228
229
230
231
	if(JSVAL_IS_NUMBER(*vp) || JSVAL_IS_BOOLEAN(*vp)) {
		if(!JS_ValueToInt32(cx, *vp, &val))
			return JS_FALSE;
	}
232
233
234
235
236

	switch(tiny) {
		case CON_PROP_STATUS:
			sbbs->console=val;
			break;
237
		case CON_PROP_MOUSE_MODE:
238
239
			if(*vp == JSVAL_TRUE)
				val = MOUSE_MODE_ON;
240
241
			sbbs->set_mouse(val);
			break;
242
243
244
		case CON_PROP_LNCNTR:
			sbbs->lncntr=val;
			break;
245
246
247
		case CON_PROP_COLUMN:
			sbbs->column=val;
			break;
248
249
250
		case CON_PROP_LASTLINELEN:
			sbbs->lastlinelen=val;
			break;
251
252
253
		case CON_PROP_LINE_DELAY:
			sbbs->line_delay = val;
			break;
rswindell's avatar
rswindell committed
254
		case CON_PROP_ATTR:
255
			if(JSVAL_IS_STRING(*vp)) {
deuce's avatar
deuce committed
256
				JSVALUE_TO_MSTRING(cx, *vp, sval, NULL);
deuce's avatar
deuce committed
257
				if(sval==NULL)
258
					break;
deuce's avatar
deuce committed
259
				val=attrstr(sval);
deuce's avatar
deuce committed
260
				free(sval);
261
			}
262
			rc=JS_SUSPENDREQUEST(cx);
rswindell's avatar
rswindell committed
263
			sbbs->attr(val);
264
			JS_RESUMEREQUEST(cx, rc);
rswindell's avatar
rswindell committed
265
			break;
rswindell's avatar
rswindell committed
266
267
268
		case CON_PROP_ROW:
			if(val >= 0 && val < TERM_ROWS_MAX)
				sbbs->row = val;
269
270
			break;
		case CON_PROP_ROWS:
rswindell's avatar
rswindell committed
271
272
			if(val >= TERM_ROWS_MIN && val <= TERM_ROWS_MAX)
				sbbs->rows=val;
273
			break;
rswindell's avatar
rswindell committed
274
		case CON_PROP_COLUMNS:
rswindell's avatar
rswindell committed
275
276
277
278
279
			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
280
			break;
281
282
283
		case CON_PROP_AUTOTERM:
			sbbs->autoterm=val;
			break;
rswindell's avatar
rswindell committed
284
		case CON_PROP_TERMINAL:
deuce's avatar
deuce committed
285
			JSVALUE_TO_MSTRING(cx, *vp, sval, NULL);
deuce's avatar
deuce committed
286
			if(sval==NULL)
rswindell's avatar
rswindell committed
287
				break;
deuce's avatar
deuce committed
288
			SAFECOPY(sbbs->terminal,sval);
deuce's avatar
deuce committed
289
			free(sval);
rswindell's avatar
rswindell committed
290
			break;
291
292
293
		case CON_PROP_CTERM_VERSION:
			sbbs->cterm_version = val;
			break;
294
295
296
297
298
299
		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;
300
301
302
303
304
305
		case CON_PROP_TIMEOUT:
			sbbs->timeout=val;
			break;
		case CON_PROP_TIMELEFT_WARN:
			sbbs->timeleft_warn=val;
			break;
306
307
308
309
310
311
		case CON_PROP_ABORTED:
			if(val)
				sbbs->sys_status|=SS_ABORT;
			else
				sbbs->sys_status&=~SS_ABORT;
			break;
rswindell's avatar
rswindell committed
312
		case CON_PROP_ABORTABLE:
313
			sbbs->rio_abortable=val
rswindell's avatar
rswindell committed
314
				? true:false; // This is a dumb bool conversion to make BC++ happy
rswindell's avatar
rswindell committed
315
316
317
318
			break;
		case CON_PROP_TELNET_MODE:
			sbbs->telnet_mode=val;
			break;
319
320
321
		case CON_PROP_GETSTR_OFFSET:
			sbbs->getstr_offset=val;
			break;
322
		case CON_PROP_QUESTION:
deuce's avatar
deuce committed
323
			JSVALUE_TO_MSTRING(cx, *vp, sval, NULL);
deuce's avatar
deuce committed
324
			if(sval==NULL)
325
				break;
deuce's avatar
deuce committed
326
			SAFECOPY(sbbs->question,sval);
deuce's avatar
deuce committed
327
			free(sval);
328
			break;
329
		case CON_PROP_CTRLKEY_PASSTHRU:
330
331
332
			if(JSVAL_IS_STRING(*vp)) {
				char *s;

333
334
				if((str=JS_ValueToString(cx, *vp))==NULL)
					break;
deuce's avatar
deuce committed
335
336
337
				JSSTRING_TO_MSTRING(cx, str, s, NULL);
				if(s==NULL)
					break;
338
				val=str_to_bits(sbbs->cfg.ctrlkey_passthru, s);
deuce's avatar
deuce committed
339
				free(s);
340
			}
341
342
			sbbs->cfg.ctrlkey_passthru=val;
			break;
343
344
345
		case CON_PROP_OUTPUT_RATE:
			sbbs->set_output_rate((enum sbbs_t::output_rate)val);
			break;
346

347
348
349
350
351
352
353
		default:
			return(JS_TRUE);
	}

	return(JS_TRUE);
}

rswindell's avatar
rswindell committed
354
#define CON_PROP_FLAGS JSPROP_ENUMERATE
355

356
357
358
359
static jsSyncPropertySpec js_console_properties[] = {
/*		 name				,tinyid						,flags			,ver	*/

	{	"status"			,CON_PROP_STATUS			,CON_PROP_FLAGS	,310},
360
	{	"mouse_mode"		,CON_PROP_MOUSE_MODE		,CON_PROP_FLAGS, 31800},
361
	{	"line_counter"		,CON_PROP_LNCNTR 			,CON_PROP_FLAGS	,310},
rswindell's avatar
rswindell committed
362
	{	"current_row"		,CON_PROP_ROW				,CON_PROP_FLAGS ,31800},
363
	{	"current_column"	,CON_PROP_COLUMN			,CON_PROP_FLAGS ,315},
364
	{	"last_line_length"	,CON_PROP_LASTLINELEN		,CON_PROP_FLAGS	,317},
365
	{	"line_delay"		,CON_PROP_LINE_DELAY		,CON_PROP_FLAGS	,320},
366
	{	"attributes"		,CON_PROP_ATTR				,CON_PROP_FLAGS	,310},
rswindell's avatar
rswindell committed
367
	{	"top_of_screen"		,CON_PROP_TOS				,JSPROP_ENUMERATE|JSPROP_READONLY	,310},
368
369
	{	"screen_rows"		,CON_PROP_ROWS				,CON_PROP_FLAGS	,310},
	{	"screen_columns"	,CON_PROP_COLUMNS			,CON_PROP_FLAGS	,311},
rswindell's avatar
rswindell committed
370
	{	"tabstop"			,CON_PROP_TABSTOP			,CON_PROP_FLAGS	,31700},
371
372
	{	"autoterm"			,CON_PROP_AUTOTERM			,CON_PROP_FLAGS	,310},
	{	"terminal"			,CON_PROP_TERMINAL			,CON_PROP_FLAGS ,311},
373
374
	{	"type"				,CON_PROP_TERM_TYPE			,JSPROP_ENUMERATE|JSPROP_READONLY ,31702},
	{	"charset"			,CON_PROP_CHARSET			,JSPROP_ENUMERATE|JSPROP_READONLY ,31702},
375
	{	"cterm_version"		,CON_PROP_CTERM_VERSION		,CON_PROP_FLAGS ,317},
376
377
	{	"inactivity_warning",CON_PROP_INACTIV_WARN		,CON_PROP_FLAGS, 31401},
	{	"inactivity_hangup"	,CON_PROP_INACTIV_HANGUP	,CON_PROP_FLAGS, 31401},
378
379
380
381
382
383
384
385
386
	{	"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},
387
388
389
390
	{	"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},
391
	{	"output_rate"		,CON_PROP_OUTPUT_RATE		,JSPROP_ENUMERATE, 31702},
392
393
	{	"keyboard_buffer_level",CON_PROP_KEYBUF_LEVEL	,JSPROP_ENUMERATE|JSPROP_READONLY, 31800},
	{	"keyboard_buffer_space",CON_PROP_KEYBUF_SPACE	,JSPROP_ENUMERATE|JSPROP_READONLY, 31800},
394
395
396
	{0}
};

397
#ifdef BUILD_JSDOCS
398
static const char* con_prop_desc[] = {
399
	 "status bit-field (see <tt>CON_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)"
400
401
	,"mouse mode bit-field (see <tt>MOUSE_MODE_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions, "
		"set to <tt>true</tt> for default enabled mode, <tt>false</tt> to disable)"
402
	,"current 0-based line counter (used for automatic screen pause)"
rswindell's avatar
rswindell committed
403
	,"current 0-based row counter"
404
	,"current 0-based column counter (used to auto-increment <i>line_counter</i> when screen wraps)"
405
	,"length of last line sent to terminal (before a carriage-return or line-wrap)"
406
	,"duration of delay (in milliseconds) before each line-feed character is sent to the terminal"
407
	,"current display attributes (set with number or string value)"
rswindell's avatar
rswindell committed
408
	,"set to <i>true</i> if the terminal cursor is already at the top of the screen - <small>READ ONLY</small>"
409
410
	,"number of remote terminal screen rows (in lines)"
	,"number of remote terminal screen columns (in character cells)"
rswindell's avatar
rswindell committed
411
	,"current tab stop interval (tab size), in columns"
412
	,"bit-field of automatically detected terminal settings "
413
		"(see <tt>USER_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)"
414
415
416
	,"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')"
417
	,"detected CTerm (SyncTERM) version as an integer > 1000 where major version is cterm_version / 1000 and minor version is cterm_version % 1000"
418
419
420
421
	,"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"
422
	,"input/output has been aborted"
423
	,"remote output can be asynchronously aborted with Ctrl-C"
424
	,"current Telnet mode bit-field (see <tt>TELNET_MODE_*</tt> in <tt>sbbsdefs.js</tt> for bit definitions)"
425
	,"word-wrap buffer (used by getstr) - <small>READ ONLY</small>"
426
	,"current yes/no question (set by yesno and noyes)"
427
	,"cursor position offset for use with <tt>getstr(K_USEOFFSET)</tt>"
428
	,"control key pass-through bit-mask, set bits represent control key combinations "
429
430
		"<i>not</i> handled by <tt>inkey()</tt> method "
		"This may optionally be specified as a string of characters. "
deuce's avatar
deuce committed
431
		"The format of this string is [+-][@-_]. If neither plus nor minus is "
432
		"the first character, the value will be replaced by one constructed "
deuce's avatar
deuce committed
433
		"from the string. A + indicates that characters following will be "
434
		"added to the set, and a - indicates they should be removed. "
rswindell's avatar
rswindell committed
435
		"ex: <tt>console.ctrlkey_passthru=\"-UP+AB\"</tt> will clear CTRL-U and "
436
		"CTRL-P and set CTRL-A and CTRL-B."
437
438
439
440
	,"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>"
441
	,"emulated serial data output rate, in bits-per-second (0 = unlimited)"
442
443
	,"number of characters current in the keyboard input buffer (from <tt>ungetstr</tt>) - <small>READ ONLY</small>"
	,"number of characters spaces available in the keyboard input buffer - <small>READ ONLY</small>"
444
	,NULL
445
446
447
};
#endif

448
449
450
451
452
/**************************/
/* Console Object Methods */
/**************************/

static JSBool
453
js_inkey(JSContext *cx, uintN argc, jsval *arglist)
454
{
455
	jsval *argv=JS_ARGV(cx, arglist);
456
	char		key[2];
457
	int			ch;
458
459
	int32		mode=0;
	int32		timeout=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
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
468

469
470
471
472
473
474
475
476
	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;
	}
477
	rc=JS_SUSPENDREQUEST(cx);
478
479
480
481
482
483
484
485
	ch = sbbs->inkey(mode,timeout);
	if(ch != NOINP) {
		key[0]=ch;
		key[1]=0;
		if((js_str = JS_NewStringCopyZ(cx, key))==NULL)
			return(JS_FALSE);
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
	}
486
	JS_RESUMEREQUEST(cx, rc);
487
488
489
490
    return(JS_TRUE);
}

static JSBool
491
js_getkey(JSContext *cx, uintN argc, jsval *arglist)
492
{
493
	jsval *argv=JS_ARGV(cx, arglist);
494
	char		key[2];
495
	int32		mode=0;
496
497
	sbbs_t*		sbbs;
    JSString*	js_str;
deuce's avatar
deuce committed
498
	jsrefcount	rc;
499

500
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
501
502
		return(JS_FALSE);

503
504
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

505
506
507
508
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&mode))
			return JS_FALSE;
	}
509
	rc=JS_SUSPENDREQUEST(cx);
510
	key[0]=sbbs->getkey(mode);
511
	JS_RESUMEREQUEST(cx, rc);
512
513
	key[1]=0;

514
515
516
	if((js_str = JS_NewStringCopyZ(cx, key))==NULL)
		return(JS_FALSE);

517
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
518
519
520
    return(JS_TRUE);
}

rswindell's avatar
rswindell committed
521
522
523
524
525
526
527
528
static JSBool
js_getbyte(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval *argv=JS_ARGV(cx, arglist);
	int32		timeout=0;
	sbbs_t*		sbbs;
	jsrefcount	rc;

529
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
rswindell's avatar
rswindell committed
530
531
		return JS_FALSE;

532
533
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

rswindell's avatar
rswindell committed
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
	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;

555
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
rswindell's avatar
rswindell committed
556
557
558
559
560
561
562
563
564
565
566
567
568
569
		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
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
static JSBool
js_add_hotspot(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval *argv=JS_ARGV(cx, arglist);
	sbbs_t*		sbbs;

	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

	if(argc < 1) {
		JS_ReportError(cx, "Invalid number of arguments to function");
		return JS_FALSE;
	}

	JSString*	js_str = JS_ValueToString(cx, argv[0]);
	if(js_str == NULL)
		return JS_FALSE;
589
	bool hungry = true;
rswindell's avatar
rswindell committed
590
591
592
593
	int32 min_x = -1;
	int32 max_x = -1;
	int32 y = -1;
	uintN argn = 1;
594
595
596
597
	if(argc > argn && JSVAL_IS_BOOLEAN(argv[argn])) {
		hungry = JSVAL_TO_BOOLEAN(argv[argn]);
		argn++;
	}
rswindell's avatar
rswindell committed
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
	if(argc > argn) {
		if(!JS_ValueToInt32(cx,argv[argn], &min_x))
			return JS_FALSE;
		argn++;
	}
	if(argc > argn) {
		if(!JS_ValueToInt32(cx,argv[argn], &max_x))
			return JS_FALSE;
		argn++;
	}
	if(argc > argn) {
		if(!JS_ValueToInt32(cx,argv[argn], &y))
			return JS_FALSE;
		argn++;
	}
	char* p = NULL;
	JSSTRING_TO_MSTRING(cx, js_str, p, NULL);
	if(p == NULL)
		return JS_FALSE;
617
	sbbs->add_hotspot(p, hungry, min_x, max_x, y);
rswindell's avatar
rswindell committed
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
	free(p);
    return JS_TRUE;
}

static JSBool js_scroll_hotspots(JSContext *cx, uintN argc, jsval *arglist)
{
	jsval *argv=JS_ARGV(cx, arglist);
	sbbs_t*		sbbs;

	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

	int32 rows = 1;
	if(argc > 0 && !JS_ValueToInt32(cx,argv[0], &rows))
		return JS_FALSE;
	sbbs->scroll_hotspots(rows);
    return JS_TRUE;
}

static JSBool js_clear_hotspots(JSContext *cx, uintN argc, jsval *arglist)
{
	sbbs_t*		sbbs;

	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

	sbbs->clear_hotspots();
    return JS_TRUE;
}
rswindell's avatar
rswindell committed
651

rswindell's avatar
rswindell committed
652
static JSBool
653
js_handle_ctrlkey(JSContext *cx, uintN argc, jsval *arglist)
rswindell's avatar
rswindell committed
654
{
655
	jsval *argv=JS_ARGV(cx, arglist);
656
	char		key;
rswindell's avatar
rswindell committed
657
	int32		mode=0;
rswindell's avatar
rswindell committed
658
	sbbs_t*		sbbs;
deuce's avatar
deuce committed
659
	jsrefcount	rc;
deuce's avatar
deuce committed
660
	char		*keystr;
rswindell's avatar
rswindell committed
661

662
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
rswindell's avatar
rswindell committed
663
664
		return(JS_FALSE);

665
666
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

667
668
669
	if(JSVAL_IS_INT(argv[0]))
		key=(char)JSVAL_TO_INT(argv[0]);
	else {
deuce's avatar
deuce committed
670
		JSVALUE_TO_ASTRING(cx, argv[0], keystr, 2, NULL);
deuce's avatar
deuce committed
671
		if(keystr==NULL)
672
			return(JS_FALSE);
deuce's avatar
deuce committed
673
		key=keystr[0];
674
	}
rswindell's avatar
rswindell committed
675

676
677
678
679
	if(argc>1) {
		if(!JS_ValueToInt32(cx, argv[1], &mode))
			return JS_FALSE;
	}
rswindell's avatar
rswindell committed
680

681
	rc=JS_SUSPENDREQUEST(cx);
682
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->handle_ctrlkey(key,mode)==0));
683
	JS_RESUMEREQUEST(cx, rc);
rswindell's avatar
rswindell committed
684
685
686
    return(JS_TRUE);
}

687
static JSBool
688
js_getstr(JSContext *cx, uintN argc, jsval *arglist)
689
{
690
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
691
	char		*p,*p2;
692
	int32		mode=0;
693
	uintN		i;
694
	int32		maxlen=0;
695
696
	sbbs_t*		sbbs;
    JSString*	js_str=NULL;
deuce's avatar
deuce committed
697
	jsrefcount	rc;
698
	str_list_t	history = NULL;
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(!maxlen) {
708
				if(!JS_ValueToInt32(cx,argv[i],&maxlen))
709
710
711
					return JS_FALSE;
			}
			else {
712
				if(!JS_ValueToInt32(cx,argv[i],&mode))
713
714
					return JS_FALSE;
			}
715
		}
716
		else if(JSVAL_IS_STRING(argv[i])) {
717
718
719
720
			js_str = JS_ValueToString(cx, argv[i]);
			if (!js_str)
			    return(JS_FALSE);
		}
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
		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;
			}
		}
742
743
744
745
746
747
748
	}

	if(!maxlen) maxlen=128;

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

deuce's avatar
deuce committed
749
	if(js_str!=NULL) {
deuce's avatar
deuce committed
750
		JSSTRING_TO_MSTRING(cx, js_str, p2, NULL);
751
752
		if(p2==NULL) {
			free(p);
deuce's avatar
deuce committed
753
			return JS_FALSE;
754
		}
deuce's avatar
deuce committed
755
		sprintf(p,"%.*s",(int)maxlen,p2);
deuce's avatar
deuce committed
756
		free(p2);
deuce's avatar
deuce committed
757
	}
758

759
	rc=JS_SUSPENDREQUEST(cx);
760
	sbbs->getstr(p, maxlen, mode, history);
761
	JS_RESUMEREQUEST(cx, rc);
762
763
764
765
766

	js_str = JS_NewStringCopyZ(cx, p);

	free(p);

767
768
769
	if(js_str==NULL)
		return(JS_FALSE);

770
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
771
772
773
774
    return(JS_TRUE);
}

static JSBool
775
js_getnum(JSContext *cx, uintN argc, jsval *arglist)
776
{
777
	jsval *argv=JS_ARGV(cx, arglist);
778
	uint32_t	maxnum=~0;
779
	int32		dflt=0;
780
	sbbs_t*		sbbs;
deuce's avatar
deuce committed
781
	jsrefcount	rc;
782

783
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
784
785
		return(JS_FALSE);

786
787
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

788
789
790
791
792
	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])) {
793
		if(!JS_ValueToInt32(cx,argv[1],&dflt))
794
795
			return JS_FALSE;
	}
796

797
	rc=JS_SUSPENDREQUEST(cx);
798
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(sbbs->getnum(maxnum,dflt)));
799
	JS_RESUMEREQUEST(cx, rc);
800
801
802
803
    return(JS_TRUE);
}

static JSBool
804
js_getkeys(JSContext *cx, uintN argc, jsval *arglist)
805
{
806
	jsval *argv=JS_ARGV(cx, arglist);
807
808
	char		key[2];
	uintN		i;
809
	int32		val;
810
811
	uint32		maxnum = ~0;
	bool		maxnum_specified = false;
812
	long		mode = K_UPPER;
813
814
	sbbs_t*		sbbs;
    JSString*	js_str=NULL;
815
	char*		cstr=NULL;
deuce's avatar
deuce committed
816
	jsrefcount	rc;
817

818
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
819
820
		return(JS_FALSE);

821
822
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

823
	for(i=0;i<argc;i++) {
824
		if(JSVAL_IS_NUMBER(argv[i])) {
825
826
			if(!JS_ValueToInt32(cx, argv[i], &val)) {
				free(cstr);
827
				return JS_FALSE;
828
			}
829
830
			if(!maxnum_specified) {
				maxnum_specified = true;
831
				maxnum = val;
832
			} else
833
				mode = val;
834
835
836
837
			continue;
		}
		if(JSVAL_IS_STRING(argv[i])) {
			js_str = JS_ValueToString(cx, argv[i]);
838
			free(cstr);
839
840
841
			JSSTRING_TO_MSTRING(cx, js_str, cstr, NULL);
			if(cstr==NULL)
				return JS_FALSE;
842
843
844
		}
	}

845
	rc=JS_SUSPENDREQUEST(cx);
846
	val=sbbs->getkeys(cstr, maxnum, mode);
847
	free(cstr);
848
	JS_RESUMEREQUEST(cx, rc);
849
850

	if(val==-1) {			// abort
851
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(0));
852
853
	} else if(val<0) {		// number
		val&=~0x80000000;
854
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(val));
855
856
857
	} else {				// key
		key[0]=(uchar)val;
		key[1]=0;
858
859
		if((js_str = JS_NewStringCopyZ(cx, key))==NULL)
			return(JS_FALSE);
860
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
861
862
863
864
865
866
	}

    return(JS_TRUE);
}

static JSBool
867
js_gettemplate(JSContext *cx, uintN argc, jsval *arglist)
868
{
869
	jsval *argv=JS_ARGV(cx, arglist);
870
	char		str[128];
871
	int32		mode=0;
872
873
874
875
	uintN		i;
	sbbs_t*		sbbs;
    JSString*	js_str=NULL;
    JSString*	js_fmt=NULL;
deuce's avatar
deuce committed
876
877
	jsrefcount	rc;
	char*		cstr;
878

879
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
880
881
		return(JS_FALSE);

882
883
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

884
885
886
887
888
889
	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]);
890
891
892
893
		} else if(JSVAL_IS_NUMBER(argv[i])) {
			if(!JS_ValueToInt32(cx,argv[i],(int32*)&mode))
				return JS_FALSE;
		}
894
895
896
897
898
899
900
	}

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

	if(js_str==NULL)
		str[0]=0;
deuce's avatar
deuce committed
901
	else {
deuce's avatar
deuce committed
902
		JSSTRING_TO_STRBUF(cx, js_str, str, sizeof(str), NULL);
deuce's avatar
deuce committed
903
	}
904

deuce's avatar
deuce committed
905
906
907
	JSSTRING_TO_MSTRING(cx, js_fmt, cstr, NULL);
	if(cstr==NULL)
		return JS_FALSE;
908
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
909
	sbbs->gettmplt(str,cstr,mode);
deuce's avatar
deuce committed
910
	free(cstr);
911
	JS_RESUMEREQUEST(cx, rc);
912
913
914
915

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

916
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
917
918
919
920
    return(JS_TRUE);
}

static JSBool
921
js_ungetstr(JSContext *cx, uintN argc, jsval *arglist)
922
{
923
	jsval *argv=JS_ARGV(cx, arglist);
924
	char*		p;
deuce's avatar
deuce committed
925
	char*		op;
926
927
	sbbs_t*		sbbs;
    JSString*	js_str;
deuce's avatar
deuce committed
928
	jsrefcount	rc;
929

930
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
931
		return(JS_FALSE);
932

933
934
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

935
936
937
	if((js_str=JS_ValueToString(cx, argv[0]))==NULL)
		return(JS_FALSE);

deuce's avatar
deuce committed
938
939
940
	JSSTRING_TO_MSTRING(cx, js_str, op, NULL);
	if(op==NULL)
		return JS_FALSE;
941

deuce's avatar
deuce committed
942
	p=op;
943
	rc=JS_SUSPENDREQUEST(cx);
944
945
	while(p && *p)
		sbbs->ungetkey(*(p++));
deuce's avatar
deuce committed
946
	free(op);
947
	JS_RESUMEREQUEST(cx, rc);
948
949
950
951
    return(JS_TRUE);
}

static JSBool
952
js_yesno(JSContext *cx, uintN argc, jsval *arglist)
953
{
954
	jsval *argv=JS_ARGV(cx, arglist);
955
956
	sbbs_t*		sbbs;
    JSString*	js_str;
deuce's avatar
deuce committed
957
	char*		cstr;
958
	int32		mode = P_NONE;
deuce's avatar
deuce committed
959
	jsrefcount	rc;
960

961
	if((sbbs=(sbbs_t*)js_GetClassPrivate(cx, JS_THIS_OBJECT(cx, arglist), &js_console_class))==NULL)
962
		return(JS_FALSE);
963

964
965
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

966
967
968
	if((js_str=JS_ValueToString(cx, argv[0]))==NULL)
		return(JS_FALSE);

deuce's avatar
deuce committed
969
970
971
	JSSTRING_TO_MSTRING(cx, js_str, cstr, NULL);
	if(cstr==NULL)
		return JS_FALSE;
972
	if(argc > 1 && JSVAL_IS_NUMBER(argv[1])) {
973