--- sbbs/src/sbbs3/js_console.cpp 2018/04/24 16:41:23 1.1 +++ sbbs/src/sbbs3/js_console.cpp 2018/04/24 16:42:57 1.1.1.2 @@ -2,13 +2,13 @@ /* Synchronet JavaScript "Console" Object */ -/* $Id: js_console.cpp,v 1.1 2018/04/24 16:41:23 root Exp $ */ +/* $Id: js_console.cpp,v 1.1.1.2 2018/04/24 16:42:57 root Exp $ */ /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -36,6 +36,7 @@ ****************************************************************************/ #include "sbbs.h" +#include "js_request.h" #ifdef JAVASCRIPT @@ -45,6 +46,7 @@ enum { CON_PROP_STATUS ,CON_PROP_LNCNTR + ,CON_PROP_COLUMN ,CON_PROP_ATTR ,CON_PROP_TOS ,CON_PROP_ROWS @@ -53,8 +55,10 @@ enum { ,CON_PROP_TERMINAL ,CON_PROP_WORDWRAP ,CON_PROP_QUESTION + ,CON_PROP_INACTIV_WARN + ,CON_PROP_INACTIV_HANGUP ,CON_PROP_TIMEOUT /* User inactivity timeout reference */ - ,CON_PROP_TIMELEFT_WARN /* low timeleft warning flag */ + ,CON_PROP_TIMELEFT_WARN /* low timeleft warning counter */ ,CON_PROP_ABORTED ,CON_PROP_ABORTABLE ,CON_PROP_TELNET_MODE @@ -86,6 +90,9 @@ static JSBool js_console_get(JSContext * case CON_PROP_LNCNTR: val=sbbs->lncntr; break; + case CON_PROP_COLUMN: + val=sbbs->column; + break; case CON_PROP_ATTR: val=sbbs->curatr; break; @@ -106,6 +113,13 @@ static JSBool js_console_get(JSContext * return(JS_FALSE); *vp = STRING_TO_JSVAL(js_str); return(JS_TRUE); + + case CON_PROP_INACTIV_WARN: + val=sbbs->cfg.sec_warn; + break; + case CON_PROP_INACTIV_HANGUP: + val=sbbs->cfg.sec_hangup; + break; case CON_PROP_TIMEOUT: val=sbbs->timeout; break; @@ -149,6 +163,7 @@ static JSBool js_console_get(JSContext * case CON_PROP_OUTBUF_SPACE: val=RingBufFree(&sbbs->outbuf); break; + default: return(JS_TRUE); } @@ -164,6 +179,7 @@ static JSBool js_console_set(JSContext * jsint tiny; sbbs_t* sbbs; JSString* str; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -180,13 +196,18 @@ static JSBool js_console_set(JSContext * case CON_PROP_LNCNTR: sbbs->lncntr=val; break; + case CON_PROP_COLUMN: + sbbs->column=val; + break; case CON_PROP_ATTR: if(JSVAL_IS_STRING(*vp)) { if((str=JS_ValueToString(cx, *vp))==NULL) break; val=attrstr(JS_GetStringBytes(str)); } + rc=JS_SUSPENDREQUEST(cx); sbbs->attr(val); + JS_RESUMEREQUEST(cx, rc); break; case CON_PROP_TOS: sbbs->tos=val; @@ -205,6 +226,12 @@ static JSBool js_console_set(JSContext * break; SAFECOPY(sbbs->terminal,JS_GetStringBytes(str)); break; + 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; case CON_PROP_TIMEOUT: sbbs->timeout=val; break; @@ -267,6 +294,7 @@ static JSBool js_console_set(JSContext * } sbbs->cfg.ctrlkey_passthru=val; break; + default: return(JS_TRUE); } @@ -281,12 +309,15 @@ static jsSyncPropertySpec js_console_pro { "status" ,CON_PROP_STATUS ,CON_PROP_FLAGS ,310}, { "line_counter" ,CON_PROP_LNCNTR ,CON_PROP_FLAGS ,310}, + { "current_column" ,CON_PROP_COLUMN ,CON_PROP_FLAGS ,315}, { "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}, { "autoterm" ,CON_PROP_AUTOTERM ,CON_PROP_FLAGS ,310}, { "terminal" ,CON_PROP_TERMINAL ,CON_PROP_FLAGS ,311}, + { "inactivity_warning",CON_PROP_INACTIV_WARN ,CON_PROP_FLAGS, 31401}, + { "inactivity_hangup" ,CON_PROP_INACTIV_HANGUP ,CON_PROP_FLAGS, 31401}, { "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}, @@ -306,19 +337,22 @@ static jsSyncPropertySpec js_console_pro #ifdef BUILD_JSDOCS static char* con_prop_desc[] = { "status bitfield (see CON_* in sbbsdefs.js for bit definitions)" - ,"current line counter (used for automatic screen pause)" + ,"current 0-based line counter (used for automatic screen pause)" + ,"current 0-based column counter (used to auto-increment line_counter when screen wraps)" ,"current display attributes (set with number or string value)" - ,"set to 1 if the terminal cursor is already at the top of the screen" - ,"number of terminal screen rows (in lines)" - ,"number of terminal screen columns (in character cells)" + ,"set to true 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)" ,"bitfield of automatically detected terminal settings " "(see USER_* in sbbsdefs.js for bit definitions)" ,"terminal type description (e.g. 'ANSI')" - ,"user inactivity timeout reference" - ,"low timeleft warning flag" + ,"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" ,"input/output has been aborted" - ,"output can be aborted with Ctrl-C" - ,"current telnet mode bitfield (see TELNET_MODE_* in sbbsdefs.js for bit definitions)" + ,"remote output can be asynchronously aborted with Ctrl-C" + ,"current Telnet mode bitfield (see TELNET_MODE_* in sbbsdefs.js for bit definitions)" ,"word-wrap buffer (used by getstr) - READ ONLY" ,"current yes/no question (set by yesno and noyes)" ,"cursor position offset for use with getstr(K_USEOFFSET)" @@ -351,6 +385,7 @@ js_inkey(JSContext *cx, JSObject *obj, u int32 timeout=0; sbbs_t* sbbs; JSString* js_str; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -359,7 +394,9 @@ js_inkey(JSContext *cx, JSObject *obj, u JS_ValueToInt32(cx,argv[0],&mode); if(argc>1) JS_ValueToInt32(cx,argv[1],&timeout); + rc=JS_SUSPENDREQUEST(cx); key[0]=sbbs->inkey(mode,timeout); + JS_RESUMEREQUEST(cx, rc); key[1]=0; if((js_str = JS_NewStringCopyZ(cx, key))==NULL) @@ -376,13 +413,16 @@ js_getkey(JSContext *cx, JSObject *obj, int32 mode=0; sbbs_t* sbbs; JSString* js_str; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); if(argc) JS_ValueToInt32(cx,argv[0],&mode); + rc=JS_SUSPENDREQUEST(cx); key[0]=sbbs->getkey(mode); + JS_RESUMEREQUEST(cx, rc); key[1]=0; if((js_str = JS_NewStringCopyZ(cx, key))==NULL) @@ -399,6 +439,7 @@ js_handle_ctrlkey(JSContext *cx, JSObjec int32 mode=0; sbbs_t* sbbs; JSString* js_str; + jsrefcount rc; *rval = JSVAL_FALSE; @@ -416,7 +457,9 @@ js_handle_ctrlkey(JSContext *cx, JSObjec if(argc>1) JS_ValueToInt32(cx, argv[1], &mode); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(sbbs->handle_ctrlkey(key,mode)==0); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -429,6 +472,7 @@ js_getstr(JSContext *cx, JSObject *obj, size_t maxlen=0; sbbs_t* sbbs; JSString* js_str=NULL; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -456,7 +500,9 @@ js_getstr(JSContext *cx, JSObject *obj, if(js_str!=NULL) sprintf(p,"%.*s",(int)maxlen,JS_GetStringBytes(js_str)); + rc=JS_SUSPENDREQUEST(cx); sbbs->getstr(p,maxlen,mode); + JS_RESUMEREQUEST(cx, rc); js_str = JS_NewStringCopyZ(cx, p); @@ -473,15 +519,21 @@ static JSBool js_getnum(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { ulong maxnum=~0; + ulong dflt=0; sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); if(argc && JSVAL_IS_NUMBER(argv[0])) JS_ValueToInt32(cx,argv[0],(int32*)&maxnum); + if(argc>1 && JSVAL_IS_NUMBER(argv[1])) + JS_ValueToInt32(cx,argv[1],(int32*)&dflt); - *rval = INT_TO_JSVAL(sbbs->getnum(maxnum)); + rc=JS_SUSPENDREQUEST(cx); + *rval = INT_TO_JSVAL(sbbs->getnum(maxnum,dflt)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -494,6 +546,8 @@ js_getkeys(JSContext *cx, JSObject *obj, ulong maxnum=~0; sbbs_t* sbbs; JSString* js_str=NULL; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -510,7 +564,10 @@ js_getkeys(JSContext *cx, JSObject *obj, if(js_str==NULL) return(JS_FALSE); - val=sbbs->getkeys(JS_GetStringBytes(js_str),maxnum); + cstr=JS_GetStringBytes(js_str); + rc=JS_SUSPENDREQUEST(cx); + val=sbbs->getkeys(cstr,maxnum); + JS_RESUMEREQUEST(cx, rc); if(val==-1) { // abort *rval = INT_TO_JSVAL(0); @@ -537,6 +594,8 @@ js_gettemplate(JSContext *cx, JSObject * sbbs_t* sbbs; JSString* js_str=NULL; JSString* js_fmt=NULL; + jsrefcount rc; + char* cstr; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -559,7 +618,10 @@ js_gettemplate(JSContext *cx, JSObject * else SAFECOPY(str,JS_GetStringBytes(js_str)); - sbbs->gettmplt(str,JS_GetStringBytes(js_fmt),mode); + cstr=JS_GetStringBytes(js_fmt); + rc=JS_SUSPENDREQUEST(cx); + sbbs->gettmplt(str,cstr,mode); + JS_RESUMEREQUEST(cx, rc); if((js_str=JS_NewStringCopyZ(cx, str))==NULL) return(JS_FALSE); @@ -574,6 +636,7 @@ js_ungetstr(JSContext *cx, JSObject *obj char* p; sbbs_t* sbbs; JSString* js_str; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -583,8 +646,10 @@ js_ungetstr(JSContext *cx, JSObject *obj p=JS_GetStringBytes(js_str); + rc=JS_SUSPENDREQUEST(cx); while(p && *p) sbbs->ungetkey(*(p++)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -593,6 +658,8 @@ js_yesno(JSContext *cx, JSObject *obj, u { sbbs_t* sbbs; JSString* js_str; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -600,7 +667,10 @@ js_yesno(JSContext *cx, JSObject *obj, u if((js_str=JS_ValueToString(cx, argv[0]))==NULL) return(JS_FALSE); - *rval = BOOLEAN_TO_JSVAL(sbbs->yesno(JS_GetStringBytes(js_str))); + cstr=JS_GetStringBytes(js_str); + rc=JS_SUSPENDREQUEST(cx); + *rval = BOOLEAN_TO_JSVAL(sbbs->yesno(cstr)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -609,6 +679,8 @@ js_noyes(JSContext *cx, JSObject *obj, u { sbbs_t* sbbs; JSString* js_str; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -616,7 +688,10 @@ js_noyes(JSContext *cx, JSObject *obj, u if((js_str=JS_ValueToString(cx, argv[0]))==NULL) return(JS_FALSE); - *rval = BOOLEAN_TO_JSVAL(sbbs->noyes(JS_GetStringBytes(js_str))); + cstr=JS_GetStringBytes(js_str); + rc=JS_SUSPENDREQUEST(cx); + *rval = BOOLEAN_TO_JSVAL(sbbs->noyes(cstr)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -625,6 +700,8 @@ js_mnemonics(JSContext *cx, JSObject *ob { sbbs_t* sbbs; JSString* js_str; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -632,7 +709,10 @@ js_mnemonics(JSContext *cx, JSObject *ob if((js_str=JS_ValueToString(cx, argv[0]))==NULL) return(JS_FALSE); - sbbs->mnemonics(JS_GetStringBytes(js_str)); + cstr=JS_GetStringBytes(js_str); + rc=JS_SUSPENDREQUEST(cx); + sbbs->mnemonics(cstr); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -640,19 +720,23 @@ static void js_set_attr(JSContext* cx, sbbs_t* sbbs, jsval val) { int32 attr; + jsrefcount rc; if(JSVAL_IS_STRING(val)) attr=attrstr(js_ValueToStringBytes(cx,val,NULL)); else JS_ValueToInt32(cx, val, &attr); + rc=JS_SUSPENDREQUEST(cx); sbbs->attr(attr); + JS_RESUMEREQUEST(cx, rc); } static JSBool js_clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -660,7 +744,9 @@ js_clear(JSContext *cx, JSObject *obj, u if(argc) js_set_attr(cx, sbbs, argv[0]); + rc=JS_SUSPENDREQUEST(cx); sbbs->CLS; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -668,6 +754,7 @@ static JSBool js_clearline(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -675,7 +762,9 @@ js_clearline(JSContext *cx, JSObject *ob if(argc) js_set_attr(cx, sbbs, argv[0]); + rc=JS_SUSPENDREQUEST(cx); sbbs->clearline(); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -683,6 +772,7 @@ static JSBool js_cleartoeol(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -690,7 +780,9 @@ js_cleartoeol(JSContext *cx, JSObject *o if(argc) js_set_attr(cx, sbbs, argv[0]); + rc=JS_SUSPENDREQUEST(cx); sbbs->cleartoeol(); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -698,12 +790,22 @@ static JSBool js_crlf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; + int32 i; + int32 count=1; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); - sbbs->outchar(CR); - sbbs->outchar(LF); + if(argc) + JS_ValueToInt32(cx, argv[0], &count); + + rc=JS_SUSPENDREQUEST(cx); + for(i=0;ioutchar(CR); + sbbs->outchar(LF); + } + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -711,11 +813,14 @@ static JSBool js_pause(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); sbbs->pause(); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -725,14 +830,17 @@ js_beep(JSContext *cx, JSObject *obj, ui sbbs_t* sbbs; int32 i; int32 count=1; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); if(argc) JS_ValueToInt32(cx, argv[0], &count); + rc=JS_SUSPENDREQUEST(cx); for(i=0;ioutchar('\a'); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -740,17 +848,22 @@ js_beep(JSContext *cx, JSObject *obj, ui static JSBool js_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - JSString* str; + uintN i; sbbs_t* sbbs; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); - str = JS_ValueToString(cx, argv[0]); - if (!str) - return(JS_FALSE); + for (i = 0; i < argc; i++) { + if((cstr=js_ValueToStringBytes(cx, argv[i], NULL))==NULL) + return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); + sbbs->bputs(cstr); + JS_RESUMEREQUEST(cx, rc); + } - sbbs->bputs(JS_GetStringBytes(str)); return(JS_TRUE); } @@ -758,37 +871,66 @@ static JSBool js_strlen(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSString* str; + char* cstr; + jsrefcount rc; if((str=JS_ValueToString(cx, argv[0]))==NULL) return(JS_FALSE); - *rval = INT_TO_JSVAL(bstrlen(JS_GetStringBytes(str))); + cstr=JS_GetStringBytes(str); + rc=JS_SUSPENDREQUEST(cx); + *rval = INT_TO_JSVAL(bstrlen(cstr)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - JSString* str; sbbs_t* sbbs; + uintN i; + char* str; + size_t len; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); - str = JS_ValueToString(cx, argv[0]); - if (!str) - return(JS_FALSE); + for (i = 0; i < argc; i++) { + if((str=js_ValueToStringBytes(cx, argv[i], &len))==NULL) + return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); + sbbs->rputs(str, len); + JS_RESUMEREQUEST(cx, rc); + } - sbbs->rputs(JS_GetStringBytes(str)); return(JS_TRUE); } static JSBool +js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + sbbs_t* sbbs; + + if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) + return(JS_FALSE); + + if(argc) { + if(!js_write(cx, obj, argc, argv, rval)) + return(JS_FALSE); + } + sbbs->rputs("\r\n"); + return(JS_TRUE); +} + +static JSBool js_putmsg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { long mode=0; JSString* str; sbbs_t* sbbs; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -800,7 +942,10 @@ js_putmsg(JSContext *cx, JSObject *obj, if(argc>1 && JSVAL_IS_NUMBER(argv[1])) JS_ValueToInt32(cx,argv[1],(int32*)&mode); - sbbs->putmsg(JS_GetStringBytes(str),mode); + cstr=JS_GetStringBytes(str); + rc=JS_SUSPENDREQUEST(cx); + sbbs->putmsg(cstr,mode); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -810,6 +955,8 @@ js_printfile(JSContext *cx, JSObject *ob long mode=0; JSString* str; sbbs_t* sbbs; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -821,7 +968,10 @@ js_printfile(JSContext *cx, JSObject *ob if(argc>1 && JSVAL_IS_NUMBER(argv[1])) JS_ValueToInt32(cx,argv[1],(int32*)&mode); - sbbs->printfile(JS_GetStringBytes(str),mode); + cstr=JS_GetStringBytes(str); + rc=JS_SUSPENDREQUEST(cx); + sbbs->printfile(cstr,mode); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -833,6 +983,8 @@ js_printtail(JSContext *cx, JSObject *ob uintN i; sbbs_t* sbbs; JSString* js_str=NULL; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -853,7 +1005,10 @@ js_printtail(JSContext *cx, JSObject *ob if(!lines) lines=5; - sbbs->printtail(JS_GetStringBytes(js_str),lines,mode); + cstr=JS_GetStringBytes(js_str); + rc=JS_SUSPENDREQUEST(cx); + sbbs->printtail(cstr,lines,mode); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -862,6 +1017,8 @@ js_editfile(JSContext *cx, JSObject *obj { JSString* str; sbbs_t* sbbs; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -869,7 +1026,10 @@ js_editfile(JSContext *cx, JSObject *obj if((str=JS_ValueToString(cx, argv[0]))==NULL) return(JS_FALSE); - sbbs->editfile(JS_GetStringBytes(str)); + cstr=JS_GetStringBytes(str); + rc=JS_SUSPENDREQUEST(cx); + *rval = BOOLEAN_TO_JSVAL(sbbs->editfile(JS_GetStringBytes(str))); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -885,6 +1045,7 @@ js_uselect(JSContext *cx, JSObject *obj, uchar* ar=NULL; sbbs_t* sbbs; JSString* js_str; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -912,7 +1073,9 @@ js_uselect(JSContext *cx, JSObject *obj, } } + rc=JS_SUSPENDREQUEST(cx); *rval = INT_TO_JSVAL(sbbs->uselect(1, num, title, item, ar)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -921,6 +1084,8 @@ js_center(JSContext *cx, JSObject *obj, { JSString* str; sbbs_t* sbbs; + char* cstr; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -929,7 +1094,10 @@ js_center(JSContext *cx, JSObject *obj, if (!str) return(JS_FALSE); + cstr=JS_GetStringBytes(str); + rc=JS_SUSPENDREQUEST(cx); sbbs->center(JS_GetStringBytes(str)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -941,10 +1109,13 @@ js_saveline(JSContext *cx, JSObject *obj if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); - sbbs->slatr[sbbs->slcnt]=sbbs->latr; - sprintf(sbbs->slbuf[sbbs->slcntslcnt++ : sbbs->slcnt] - ,"%.*s",sbbs->lbuflen,sbbs->lbuf); - sbbs->lbuflen=0; + if(sbbs->slcntslatr[sbbs->slcnt]=sbbs->latr; + sbbs->slcuratr[sbbs->slcnt]=sbbs->curatr; + sprintf(sbbs->slbuf[sbbs->slcnt],"%.*s",sbbs->lbuflen,sbbs->lbuf); + sbbs->slcnt++; + sbbs->lbuflen=0; + } return(JS_TRUE); } @@ -952,14 +1123,19 @@ static JSBool js_restoreline(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); sbbs->lbuflen=0; - sbbs->attr(sbbs->slatr[--sbbs->slcnt]); + if(sbbs->slcnt) + sbbs->slcnt--; + sbbs->attr(sbbs->slatr[sbbs->slcnt]); sbbs->rputs(sbbs->slbuf[sbbs->slcnt]); - sbbs->curatr=LIGHTGRAY; + sbbs->curatr=sbbs->slcuratr[sbbs->slcnt]; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -975,8 +1151,17 @@ js_ansi(JSContext *cx, JSObject *obj, ui if(argc) JS_ValueToInt32(cx,argv[0],&attr); - if((js_str=JS_NewStringCopyZ(cx,sbbs->ansi(attr)))==NULL) - return(JS_FALSE); + if(argc>1) { + int32 curattr=0; + char buf[16]; + + JS_ValueToInt32(cx,argv[0],&curattr); + if((js_str=JS_NewStringCopyZ(cx,sbbs->ansi(attr,curattr,buf)))==NULL) + return(JS_FALSE); + } else { + if((js_str=JS_NewStringCopyZ(cx,sbbs->ansi(attr)))==NULL) + return(JS_FALSE); + } *rval = STRING_TO_JSVAL(js_str); return(JS_TRUE); @@ -986,11 +1171,14 @@ static JSBool js_pushxy(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); - sbbs->ANSI_SAVE(); + rc=JS_SUSPENDREQUEST(cx); + sbbs->ansi_save(); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -998,11 +1186,14 @@ static JSBool js_popxy(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); - sbbs->ANSI_RESTORE(); + rc=JS_SUSPENDREQUEST(cx); + sbbs->ansi_restore(); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1012,6 +1203,7 @@ js_gotoxy(JSContext *cx, JSObject *obj, int32 x=1,y=1; jsval val; sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -1026,7 +1218,9 @@ js_gotoxy(JSContext *cx, JSObject *obj, JS_ValueToInt32(cx,argv[1],&y); } - sbbs->GOTOXY(x,y); + rc=JS_SUSPENDREQUEST(cx); + sbbs->ansi_gotoxy(x,y); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1037,11 +1231,14 @@ js_getxy(JSContext *cx, JSObject *obj, u sbbs_t* sbbs; int x,y; JSObject* screen; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); sbbs->ansi_getxy(&x,&y); + JS_RESUMEREQUEST(cx, rc); if((screen=JS_NewObject(cx,NULL,NULL,obj))==NULL) return(JS_TRUE); @@ -1059,11 +1256,14 @@ static JSBool js_cursor_home(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); sbbs->cursor_home(); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1072,13 +1272,16 @@ js_cursor_up(JSContext *cx, JSObject *ob { int32 val=1; sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); if(argc) JS_ValueToInt32(cx,argv[0],&val); + rc=JS_SUSPENDREQUEST(cx); sbbs->cursor_up(val); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1087,13 +1290,16 @@ js_cursor_down(JSContext *cx, JSObject * { int32 val=1; sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); if(argc) JS_ValueToInt32(cx,argv[0],&val); + rc=JS_SUSPENDREQUEST(cx); sbbs->cursor_down(val); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1102,13 +1308,16 @@ js_cursor_right(JSContext *cx, JSObject { int32 val=1; sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); if(argc) JS_ValueToInt32(cx,argv[0],&val); + rc=JS_SUSPENDREQUEST(cx); sbbs->cursor_right(val); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1117,13 +1326,43 @@ js_cursor_left(JSContext *cx, JSObject * { int32 val=1; sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); if(argc) JS_ValueToInt32(cx,argv[0],&val); + rc=JS_SUSPENDREQUEST(cx); sbbs->cursor_left(val); + JS_RESUMEREQUEST(cx, rc); + return(JS_TRUE); +} + +static JSBool +js_backspace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + sbbs_t* sbbs; + jsrefcount rc; + + if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) + return(JS_FALSE); + + rc=JS_SUSPENDREQUEST(cx); + sbbs->backspace(); + JS_RESUMEREQUEST(cx, rc); + return(JS_TRUE); +} + +static JSBool +js_clearkeybuf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + sbbs_t* sbbs; + + if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) + return(JS_FALSE); + + sbbs->keybufbot=sbbs->keybuftop=0; return(JS_TRUE); } @@ -1131,11 +1370,14 @@ static JSBool js_getlines(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { sbbs_t* sbbs; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); sbbs->ansi_getlines(); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1144,6 +1386,7 @@ js_lock_input(JSContext *cx, JSObject *o { sbbs_t* sbbs; JSBool lock=TRUE; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -1151,6 +1394,7 @@ js_lock_input(JSContext *cx, JSObject *o if(argc) JS_ValueToBoolean(cx, argv[0], &lock); + rc=JS_SUSPENDREQUEST(cx); if(lock) { pthread_mutex_lock(&sbbs->input_thread_mutex); sbbs->input_thread_mutex_locked=true; @@ -1158,6 +1402,7 @@ js_lock_input(JSContext *cx, JSObject *o pthread_mutex_unlock(&sbbs->input_thread_mutex); sbbs->input_thread_mutex_locked=false; } + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1167,6 +1412,7 @@ js_telnet_cmd(JSContext *cx, JSObject *o { sbbs_t* sbbs; int32 cmd,opt=0; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -1175,7 +1421,9 @@ js_telnet_cmd(JSContext *cx, JSObject *o if(argc>1) JS_ValueToInt32(cx,argv[1],&opt); + rc=JS_SUSPENDREQUEST(cx); sbbs->send_telnet_cmd((uchar)cmd,(uchar)opt); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1185,6 +1433,7 @@ js_term_supports(JSContext *cx, JSObject { sbbs_t* sbbs; int32 flags; + jsrefcount rc; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); @@ -1192,9 +1441,15 @@ js_term_supports(JSContext *cx, JSObject if(argc) { if(!JS_ValueToInt32(cx,argv[0],&flags)) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(sbbs->term_supports(flags)); - } else - JS_NewNumberValue(cx,sbbs->term_supports(),rval); + JS_RESUMEREQUEST(cx, rc); + } else { + rc=JS_SUSPENDREQUEST(cx); + flags=sbbs->term_supports(); + JS_RESUMEREQUEST(cx, rc); + JS_NewNumberValue(cx,flags,rval); + } return(JS_TRUE); } @@ -1215,8 +1470,8 @@ static jsSyncMethodSpec js_console_funct "see K_* in sbbsdefs.js for mode bits") ,310 }, - {"getnum", js_getnum, 0, JSTYPE_NUMBER, JSDOCSTR("[maxnum]") - ,JSDOCSTR("get a number between 1 and maxnum from the user") + {"getnum", js_getnum, 0, JSTYPE_NUMBER, JSDOCSTR("[maxnum[, default]]") + ,JSDOCSTR("get a number between 1 and maxnum from the user with a default value of default") ,310 }, {"getkeys", js_getkeys, 1, JSTYPE_NUMBER, JSDOCSTR("string keys [,maxnum]") @@ -1233,11 +1488,11 @@ static jsSyncMethodSpec js_console_funct ,310 }, {"yesno", js_yesno, 1, JSTYPE_BOOLEAN, JSDOCSTR("question") - ,JSDOCSTR("YES/no question") + ,JSDOCSTR("YES/no question - returns true if yes is selected") ,310 }, {"noyes", js_noyes, 1, JSTYPE_BOOLEAN, JSDOCSTR("question") - ,JSDOCSTR("NO/yes question") + ,JSDOCSTR("NO/yes question - returns true if no is selected") ,310 }, {"mnemonics", js_mnemonics, 1, JSTYPE_VOID, JSDOCSTR("text") @@ -1263,8 +1518,8 @@ static jsSyncMethodSpec js_console_funct "optionally (in v3.13b+) setting current attribute first") ,311 }, - {"crlf", js_crlf, 0, JSTYPE_VOID, JSDOCSTR("") - ,JSDOCSTR("output a carriage-return/line-feed pair (new-line)") + {"crlf", js_crlf, 0, JSTYPE_VOID, JSDOCSTR("[count=1]") + ,JSDOCSTR("output count number of carriage-return/line-feed pairs (new-lines)") ,310 }, {"pause", js_pause, 0, JSTYPE_VOID, JSDOCSTR("") @@ -1272,17 +1527,21 @@ static jsSyncMethodSpec js_console_funct ,310 }, {"beep", js_beep, 1, JSTYPE_VOID, JSDOCSTR("[count=1]") - ,JSDOCSTR("beep for count number of times (default count is 1)") + ,JSDOCSTR("beep for count number of times (default count is 1)") ,311 }, - {"print", js_print, 1, JSTYPE_VOID, JSDOCSTR("text") - ,JSDOCSTR("display a string (supports Ctrl-A codes)") + {"print", js_print, 1, JSTYPE_VOID, JSDOCSTR("value [,value]") + ,JSDOCSTR("display one or more values as strings (supports Ctrl-A codes, Telnet-escaping, auto-screen pausing, etc.)") ,310 }, - {"write", js_write, 1, JSTYPE_VOID, JSDOCSTR("text") - ,JSDOCSTR("display a raw string") + {"write", js_write, 1, JSTYPE_VOID, JSDOCSTR("value [,value]") + ,JSDOCSTR("display one or more values as raw strings (may include NULs)") ,310 }, + {"writeln", js_writeln, 1, JSTYPE_VOID, JSDOCSTR("value [,value]") + ,JSDOCSTR("display one or more values as raw strings followed by a single carriage-return/line-feed pair (new-line)") + ,315 + }, {"putmsg", js_putmsg, 1, JSTYPE_VOID, JSDOCSTR("text [,mode=P_NONE]") ,JSDOCSTR("display message text (Ctrl-A codes, @-codes, pipe codes, etc), " "see P_* in sbbsdefs.js for mode bits") @@ -1304,7 +1563,7 @@ static jsSyncMethodSpec js_console_funct ,JSDOCSTR("print last x lines of file with optional mode") ,310 }, - {"editfile", js_editfile, 1, JSTYPE_VOID, JSDOCSTR("filename") + {"editfile", js_editfile, 1, JSTYPE_BOOLEAN, JSDOCSTR("filename") ,JSDOCSTR("edit/create a text file using the user's preferred message editor") ,310 }, @@ -1320,8 +1579,10 @@ static jsSyncMethodSpec js_console_funct ,JSDOCSTR("restore last output line") ,310 }, - {"ansi", js_ansi, 1, JSTYPE_STRING, JSDOCSTR("attribute_number") - ,JSDOCSTR("returns ANSI encoding of specified attribute_number") + {"ansi", js_ansi, 1, JSTYPE_STRING, JSDOCSTR("attribute [,current_attribute]") + ,JSDOCSTR("returns ANSI sequence required to generate specified terminal attribute " + "(e.g. YELLOW|HIGH|BG_BLUE), " + "if current_attribute is specified, an optimized ANSI sequence may be returned") ,310 }, {"ansi_save", js_pushxy, 0, JSTYPE_ALIAS }, @@ -1364,13 +1625,15 @@ static jsSyncMethodSpec js_console_funct ,311 }, {"ansi_getlines", js_getlines, 0, JSTYPE_ALIAS }, - {"getlines", js_getlines, 0, JSTYPE_VOID, JSDOCSTR("") - ,JSDOCSTR("auto-detect the number of rows/lines on the user's terminal (ANSI)") + {"getlines", js_getlines, 0, JSTYPE_ALIAS }, + {"getdimensions", js_getlines, 0, JSTYPE_VOID, JSDOCSTR("") + ,JSDOCSTR("query the number of rows and columns on the remote terminal (ANSI)") ,311 }, {"ansi_getxy", js_getxy, 0, JSTYPE_ALIAS }, {"getxy", js_getxy, 0, JSTYPE_OBJECT, JSDOCSTR("") - ,JSDOCSTR("returns the current cursor position as an object (with x and y properties)") + ,JSDOCSTR("query the current cursor position on the remote terminal (ANSI) " + "and returns the coordinates as an object (with x and y properties)") ,311 }, {"lock_input", js_lock_input, 1, JSTYPE_VOID, JSDOCSTR("[lock=true]") @@ -1391,10 +1654,33 @@ static jsSyncMethodSpec js_console_funct "terminal_flags (numeric bit-field) if no terminal_flags were specified") ,314 }, + {"backspace", js_backspace, 0, JSTYPE_VOID, JSDOCSTR("") + ,JSDOCSTR("send a destructive backspace sequence") + ,315 + }, + {"clearkeybuffer", js_clearkeybuf, 0, JSTYPE_VOID, JSDOCSTR("") + ,JSDOCSTR("clear keyboard input buffer") + ,315 + }, {0} }; +static JSBool js_console_resolve(JSContext *cx, JSObject *obj, jsval id) +{ + char* name=NULL; + + if(id != JSVAL_NULL) + name=JS_GetStringBytes(JSVAL_TO_STRING(id)); + + return(js_SyncResolve(cx, obj, name, js_console_properties, js_console_functions, NULL, 0)); +} + +static JSBool js_console_enumerate(JSContext *cx, JSObject *obj) +{ + return(js_console_resolve(cx, obj, JSVAL_NULL)); +} + static JSClass js_console_class = { "Console" /* name */ ,0 /* flags */ @@ -1402,8 +1688,8 @@ static JSClass js_console_class = { ,JS_PropertyStub /* delProperty */ ,js_console_get /* getProperty */ ,js_console_set /* setProperty */ - ,JS_EnumerateStub /* enumerate */ - ,JS_ResolveStub /* resolve */ + ,js_console_enumerate /* enumerate */ + ,js_console_resolve /* resolve */ ,JS_ConvertStub /* convert */ ,JS_FinalizeStub /* finalize */ }; @@ -1420,12 +1706,6 @@ JSObject* js_CreateConsoleObject(JSConte ,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL) return(NULL); - if(!js_DefineSyncProperties(cx, obj, js_console_properties)) - return(NULL); - - if (!js_DefineSyncMethods(cx, obj, js_console_functions, FALSE)) - return(NULL); - /* Create an array of pre-defined colors */ JSObject* color_list; @@ -1442,10 +1722,10 @@ JSObject* js_CreateConsoleObject(JSConte jsval val=INT_TO_JSVAL(sbbs->cfg.color[i]); if(!JS_SetElement(cx, color_list, i, &val)) return(NULL); - } + } #ifdef BUILD_JSDOCS - js_DescribeSyncObject(cx,obj,"Controls the user's Telnet/RLogin terminal",310); + js_DescribeSyncObject(cx,obj,"Controls the remote terminal",310); js_CreateArrayOfStrings(cx, obj, "_property_desc_list", con_prop_desc, JSPROP_READONLY); #endif