diff --git a/ctrl/videotex.ini b/ctrl/videotex.ini index 7d3a1c9..80c7fa8 100644 --- a/ctrl/videotex.ini +++ b/ctrl/videotex.ini @@ -8,16 +8,19 @@ ; Frames with no specific owner are owned by this key [prefix] key=0@videotex -logo=AWgBUkEBR04BQlMBWUkBbgE3AWt0ZXgBbg== +logoans=AWgBUkEBR04BQlMBWUkBbgE3AWt0ZXgBbg== +logovtx=AVYCSQNEBEUFTwZ0ZXg= ; System frames are owned by this key [prefix:9] key=0@videotex -logo=AWgBUkEBR04BQlMBWUkBbgE3AWt0ZXgBbg== -user=1 +logoans=AWgBUkEBR04BQlMBWUkBbgE3AWt0ZXgBbg== +logovtx=AVYCSQNEBEUFTwZ0ZXg= +user=1,3 ; Ansitex Help Pages [prefix:516] key=516@videotex -logo=AWgBUkEBR04BQlMBWUkBbgE3AWt0ZXgBbg== +logoans=AWgBUkEBR04BQlMBWUkBbgE3AWt0ZXgBbg== +logovtx=AVYCSQNEBEUFTwZ0ZXg= user=1 diff --git a/load/ansiframe.js b/load/ansiframe.js index 1fa4e17..bebe33b 100644 --- a/load/ansiframe.js +++ b/load/ansiframe.js @@ -1,25 +1,25 @@ -var FRAME_ANSI=(1<<1); +var FRAME_ANSI = (1<<1); -var ANSI_FRAME_LENGTH =22; /* Length of a frame */ -var ANSI_FRAME_WIDTH =80; /* Width of a frame */ -var ANSI_FRAME_HEADER =56; /* Size of page owner (length) */ -var ANSI_FRAME_PAGENUM =12; /* Size of page number (length with a-z) */ +var ANSI_FRAME_LENGTH = 22; /* Length of a frame */ +var ANSI_FRAME_WIDTH = 80; /* Width of a frame */ +var ANSI_FRAME_HEADER = 56; /* Size of page owner (length) */ +var ANSI_FRAME_PAGENUM = 12; /* Size of page number (length with a-z) */ var ANSI_FRAME_COST = 9; /* Size of cost (length without unit) */ -var ANSI_MSG_SENDORNOT ='\1n\1h\1GKEY 1 TO SEND, 2 NOT TO SEND'; -var ANSI_MSG_LOGON ='\1n\1h\1GKEY 1 TO LOGON, 2 TO RETURN'; -var ANSI_MSG_SENT ='\1n\1h\1GMESSAGE SENT - KEY # TO CONTINUE'; -var ANSI_MSG_NOTSENT ='\1n\1h\1GMESSAGE NOT SENT - KEY # TO CONTINUE'; -var ANSI_ERR_NO_PARENT ='\1n\1h\1RPARENT FRAME DOESNT EXIST'; -var ANSI_ERR_NOT_IMPLEMENTED ='\1n\1h\1RNOT IMPLEMENTED YET?'; -var ANSI_ERR_ROUTE ='\1n\1h\1WMISTAKE? \1GTRY AGAIN OR TELL US ON *08'; -var ANSI_ERR_METHOD_NOT_EXIST ='\1n\1h\1WMISTAKE? \1GTRY AGAIN OR TELL US ON *08'; -var ANSI_ACCESS_DENIED ='\1n\1h\1RACCESS DENIED. \1RMISTAKE? TRY AGAIN OR TELL US *08'; -var ANSI_ALREADY_MEMBER ='\1n\1h\1RALREADY MEMBER OF CUG' -var ANSI_INACTIVITY ='\1n\1h\1RINACTIVITY ALERT, DISCONNECT PENDING...'; -var ANSI_INACTIVE ='\1n\1h\1RINACTIVITY DISCONNECT'; -var ANSI_NOACTION ='\1n\1h\1RNO ACTION PERFORMED'; -var ANSI_BASESTAR ='\1N\1G\1H*'; +var ANSI_MSG_SENDORNOT = '\1n\1h\1GKEY 1 TO SEND, 2 NOT TO SEND'; +var ANSI_MSG_LOGON = '\1n\1h\1GKEY 1 TO LOGON, 2 TO RETURN'; +var ANSI_MSG_SENT = '\1n\1h\1GMESSAGE SENT - KEY # TO CONTINUE'; +var ANSI_MSG_NOTSENT = '\1n\1h\1GMESSAGE NOT SENT - KEY # TO CONTINUE'; +var ANSI_ERR_NO_PARENT = '\1n\1h\1RPARENT FRAME DOESNT EXIST'; +var ANSI_ERR_NOT_IMPLEMENTED = '\1n\1h\1RNOT IMPLEMENTED YET?'; +var ANSI_ERR_ROUTE = '\1n\1h\1WMISTAKE? \1GTRY AGAIN OR TELL US ON *08'; +var ANSI_ERR_METHOD_NOT_EXIST = '\1n\1h\1WMISTAKE? \1GTRY AGAIN OR TELL US ON *08'; +var ANSI_ACCESS_DENIED = '\1n\1h\1RACCESS DENIED. MISTAKE? TRY AGAIN OR TELL US *08'; +var ANSI_ALREADY_MEMBER = '\1n\1h\1RALREADY MEMBER OF CUG' +var ANSI_INACTIVITY = '\1n\1h\1RINACTIVITY ALERT, DISCONNECT PENDING...'; +var ANSI_INACTIVE = '\1n\1h\1RINACTIVITY DISCONNECT'; +var ANSI_NOACTION = '\1n\1h\1RNO ACTION PERFORMED'; +var ANSI_BASESTAR = '\1N\1G\1H*'; // Our frame object function ANSIFrame() { @@ -49,16 +49,27 @@ function ANSIFrame() { this.type = FRAME_TYPE_INFO; // The frame type - see FRAME_TYPES above this.key=[ null,null,null,null,null,null,null,null,null,null ]; // Key actions [0-9] + /** + * Set the attribute at the current position + */ + this.attr=function(field) { + console.write(KEY_ESC+'['+field.i+';'+field.f+';'+field.b+'m'); + } + /** * Turn off the cursor */ this.cursorOff=function() { ansi.send('ext_mode','clear','cursor'); - console.gotoxy(0,24); + this.gotoxy(0,24); } this.cursorOn=function(x,y) { ansi.send('ext_mode','set','cursor'); + this.gotoxy(x,y); + } + + this.gotoxy=function(x,y) { console.gotoxy(x,y); } @@ -75,7 +86,7 @@ function ANSIFrame() { if (user.number || (this.type != FRAME_TYPE_LOGIN && NO_HISTORY_FRAMES.indexOf(this.page) == -1)) { log(LOG_DEBUG,' - Owner: ['+this.pageowner+']'); - cost = (this.isAccessible ? this.cost+FRAME_COSTUNIT : ' -') + cost = (this.isAccessible ? this.cost+FRAME_COSTUNIT : ' -'); header = '\1n'+this.pageownerlogo+' '.repeat(ANSI_FRAME_HEADER-console.strlen(this.pageownerlogo))+'\1n '+ (this.isAccessible ? '\1W' : '\1R')+'\1H'+this.page+' '.repeat(ANSI_FRAME_PAGENUM-this.page.length)+' '+ @@ -467,7 +478,7 @@ function ANSIFrame() { Object.defineProperty(this,'pageownerlogo', { get: function() { - return base64_decode(pageOwner(this.frame).logo); + return base64_decode(pageOwner(this.frame).logoans); } }) } \ No newline at end of file diff --git a/load/funcs.js b/load/funcs.js index 99f1cf8..33e13cb 100644 --- a/load/funcs.js +++ b/load/funcs.js @@ -92,17 +92,19 @@ function getPageOwners() { var f = new File(file_cfgname(system.mods_dir,'ansitex/ctrl/videotex.ini')); if (f.open("r")) { - var logo = f.iniGetValue('prefix','logo'); + var logoans = f.iniGetValue('prefix','logoans'); + var logovtx = f.iniGetValue('prefix','logovtx'); var users = f.iniGetValue('prefix','user'); //log(LOG_DEBUG,'+ pageOwner: users='+JSON.stringify(users)); - pageowners.push({prefix: 0,logo: logo,user:users}); + pageowners.push({prefix: 0,logoans: logoans,logovtx: logovtx,user:users}); f.iniGetSections('prefix:').forEach(function (prefix) { var p = parseInt(prefix.substr(7)); - var logo = f.iniGetValue(prefix,'logo',''); + var logoans = f.iniGetValue(prefix,'logoans',''); + var logovtx = f.iniGetValue(prefix,'logovtx',''); var users = f.iniGetValue(prefix,'user',''); //log(LOG_DEBUG,'+ pageOwner: users='+JSON.stringify(users)); - pageowners.push({prefix: p,logo: logo,user: users}); + pageowners.push({prefix: p,logoans: logoans,logovtx: logovtx,user:users}); }); } diff --git a/load/viewdataframe.js b/load/viewdataframe.js new file mode 100644 index 0000000..14171cf --- /dev/null +++ b/load/viewdataframe.js @@ -0,0 +1,507 @@ +var FRAME_VIEWDATA = (1<<2); + +var VIEWDATA_FRAME_LENGTH = 22; /* Length of a frame */ +var VIEWDATA_FRAME_WIDTH = 40; /* Width of a frame */ +var VIEWDATA_FRAME_HEADER = 23; /* Size of page owner (length) */ +var VIEWDATA_FRAME_PAGENUM = 11; /* Size of page number (length with a-z) */ +var VIEWDATA_FRAME_COST = 3; /* Size of cost (length without unit) */ + +var VIEWDATA_HOME = "\x1e"; +var VIEWDATA_CLS = "\x0c"; +var VIEWDATA_UP = "\x0b"; +var VIEWDATA_DOWN = "\x0a"; +var VIEWDATA_COFF = "\x14"; +var VIEWDATA_CON = "\x11"; +var VIEWDATA_RIGHT = "\x09"; +var VIEWDATA_LEFT = "\x08"; + +var VIEWDATA_MSG_SENDORNOT = KEY_ESC+'BKEY 1 TO SEND, 2 NOT TO SEND'; +var VIEWDATA_MSG_LOGON = KEY_ESC+'BKEY 1 TO LOGON, 2 TO RETURN'; +var VIEWDATA_MSG_SENT = KEY_ESC+'BMESSAGE SENT - KEY # TO CONTINUE'; +var VIEWDATA_MSG_NOTSENT = KEY_ESC+'BMESSAGE NOT SENT - KEY # TO CONTINUE'; +var VIEWDATA_ERR_NO_PARENT = KEY_ESC+'APARENT FRAME DOESNT EXIST'; +var VIEWDATA_ERR_NOT_IMPLEMENTED = KEY_ESC+'ANOT IMPLEMENTED YET?'; +var VIEWDATA_ERR_ROUTE = KEY_ESC+'GMISTAKE?'+KEY_ESC+'BTRY AGAIN OR TELL US ON *08'; +var VIEWDATA_ERR_METHOD_NOT_EXIST = KEY_ESC+'GMISTAKE?'+KEY_ESC+'BTRY AGAIN OR TELL US ON *08'; +var VIEWDATA_ACCESS_DENIED = KEY_ESC+'ACCESS DENIED.'; +var VIEWDATA_ALREADY_MEMBER = KEY_ESC+'AALREADY MEMBER OF CUG' +var VIEWDATA_INACTIVITY = KEY_ESC+'AINACTIVITY ALERT, DISCONNECT PENDING...'; +var VIEWDATA_INACTIVE = KEY_ESC+'AINACTIVITY DISCONNECT'; +var VIEWDATA_NOACTION = KEY_ESC+'ANO ACTION PERFORMED'; +var VIEWDATA_BASESTAR = KEY_ESC+'B*'; + +// Our frame object +function VIEWDATAFrame() { + this.version=1; // The version of this frame - in case we update functionality and we need to be + // backwards compatible + this.frame=null; // Frame Number [0-9]+ + this.index=null; // Frame Index [a-z] + this.owner=0; // The Service Provider owning the frame. + this.cost=0; // The cost to view the frame @TODO + this.content=''; // The frame content, base64 encoded + var blp=0; // Length of data on the bottom line + + // Frame's owned by the system where: + // isPublic is FALSE - the user must be logged in to view it + // isPublic is TRUE - can be viewed by non-logged in users + + // Frame's owned by Service Providers where: + // isPublic is FALSE - can only be viewed if a user is + // a member of the Service Providers CUG + // isPublic is TRUE - can be viewed by users (if logged in) + + this.isPublic=false; // Is this frame accessible to non CUG users + // If FALSE user must be a member of the CUG to view the frame + // All users, including unauthenticated, are members of 'system' (owner = 0) + this.isAccessible=false; // Is this frame available to be accessed + // If FALSE, only the SP can view/edit the frame + + this.type = FRAME_TYPE_INFO; // The frame type - see FRAME_TYPES above + this.key=[ null,null,null,null,null,null,null,null,null,null ]; // Key actions [0-9] + + this.attr=function(field) { + //@todo + } + + /** + * Turn off the cursor + */ + this.cursorOff=function() { + write_raw(VIEWDATA_COFF); + this.gotoxy(1,1); + } + + this.cursorOn=function(x,y) { + write_raw(VIEWDATA_CON); + this.gotoxy(x,y); + } + + this.gotoxy=function(x,y) { + // @todo This could be optimised to go the shortest route + write_raw(VIEWDATA_HOME); + if (x>0) + write_raw(VIEWDATA_RIGHT.repeat(x)); + if (y>0) + write_raw(VIEWDATA_DOWN.repeat(y)); + } + + this.strlen=function(str) { + return str.replace(/\x1b/g,'').length; + }; + + // Render the frame to the user + this.render=function(withHeader) { + log(LOG_DEBUG,'- VIEWDATA FRAME'); + owner = base64_decode(this.owner); + + header = VIEWDATA_DOWN; + + log(LOG_DEBUG,' - FRAME User: ['+JSON.stringify(user)+']'); + + // Dont show the page number on system login page + if (user.number || (this.type != FRAME_TYPE_LOGIN && NO_HISTORY_FRAMES.indexOf(this.page) == -1)) { + log(LOG_DEBUG,' - Owner: ['+this.pageowner+'] ('+this.strlen(videotex(this.pageownerlogo))+')'); + + cost = (this.isAccessible ? this.cost+FRAME_COSTUNIT : ' -'); + + header = videotex(this.pageownerlogo)+' '.repeat(VIEWDATA_FRAME_HEADER-this.strlen(videotex(this.pageownerlogo)))+ + (this.isAccessible ? KEY_ESC+'G' : KEY_ESC+'A')+this.page+' '.repeat(VIEWDATA_FRAME_PAGENUM-this.page.length)+ + KEY_ESC+'B'+' '.repeat(VIEWDATA_FRAME_COST-cost.toString().length+1)+cost; + } + + //console.status |= CON_RAW_IN; + write_raw(VIEWDATA_CLS); + write_raw(header); + return write_raw(videotex(base64_decode(this.content))); + }; + + this.fieldValue=function(key) { + for each (var k in this.frame_fields) { + log(LOG_DEBUG,' - k:'+JSON.stringify(k)); + + if (k.fname == key) { + return k.fvalue; + } + } + + return null; + } + + // Load a frame from disk (.tex file) + this.load = function(filename) { + log(LOG_DEBUG,'Loading VIEWDATA frame from: '+filename); + + f = new File(system.mods_dir+'ansitex/text/'+filename+'.vtx'); + if (! f.exists || ! f.open('r')) { + return null; + } + + try { + var load = JSON.parse(f.read()); + + for (property in load) { + this[property] = load[property]; + } + + } catch (error) { + log(LOG_ERROR,'Frame error: '+error); + return null; + } + + log(LOG_DEBUG,'Loaded frame: ['+this.frame+']['+this.index+'] ('+this.page+')'); + }; + + /** + * Parse the page text, and return the frame as 2 arrays: + * + First array is all the characters and the position on the frame + * + Second array is the array of the control codes that changes the color of the character + * + * The purpose of this function is to convert any special char sequences there are interpreted directly by Ansitex + * Currently they are: + * + ESC _ [;value] ESC \ + * + * Additionally, for response frames, if the cursor is moved to a field, its to determine what attributes (eg: color) + * should apply for that field. + * + * @param text + */ + this.parse = function(text) { + var c = 1; // column + var r = 2; // row (row 1 is the header) + var output = ''; + this.frame_fields = []; + + // Default Attributes + f = 39; + b = 49; + i = 0; + + for(p=0;p= 0 && csi[num] <= 8) { + i = csi[num]; + f = 39; + b = 49; + + // Forground Color + } else if (csi[num] >= 30 && csi[num] <= 39) { + f = csi[num]; + + // Background Color + } else if (csi[num] >= 40 && csi[num] <= 49) { + b = num; + } + } + break; + + // Advance characters + case 'C': + //log(LOG_DEBUG,'CSI C ['+r+'x'+c+'] CHARS: '+matches[1]); + c += parseInt(matches[1]); // Advance our position + break; + + default: + log(LOG_DEBUG,'? CSI: '.matches[2]); + } + + break; + + case ' ': + log(LOG_DEBUG,'LOOSE ESC? ['+r+'x'+c+'] '+advance); + + break; + + // SOS + case '_': + //log(LOG_DEBUG,'SOS ['+r+'x'+c+'] '+advance); + advance++; + + // Find our end ST param in the next 50 chars + matches = text.substr(p+advance,50).match(/(([A-Z]+;[0-9a-z]+)([;]?.+)?)\x1b\\/); + //log(LOG_DEBUG,'SOS ['+r+'x'+c+'] ADVANCE: '+advance+', MATCHES: '+matches+', LENGTH: '+matches[0].length+', STRING: '+text.substr(p+advance,50)); + + if (! matches) { + chars += nextbyte; + + break; + } + + advance += matches[0].length-1; + + // The last 2 chars of matches[0] are the ESC \ + sos = matches[0].substr(0,matches[0].length-2).split(';'); + //log(LOG_DEBUG,'SOS ['+r+'x'+c+'] ADVANCE: '+advance+', SOS: '+sos); + + var num = null; + var fieldlen = null; + for (num in sos) { + //log(LOG_DEBUG,'SOS ['+r+'x'+c+'] NUM: '+num+', SOS: '+sos[num]); + + switch (num) { + // First value is the field name + case '0': + field = sos[num]; + break; + + // Second value is the length/type of the field + case '1': + x = sos[num].match(/([0-9]+)([a-z])/); + if (! x) { + log(LOG_ERROR,'SOS FAILED PARSING FIELD LENGTH/TYPE. ['+r+'x'+c+'] '+sos[num]); + break; + } + + //log(LOG_DEBUG,'SOS ['+r+'x'+c+'] NUM CHARS: '+x[1]+', TYPE: '+x[2]); + fieldlen = x[1]; + fieldtype = x[2]; + break; + + // Third field is the char to to use + case '2': + fieldchar = sos[num]; + break; + + default: + log(LOG_ERROR,'IGNORING ADDITIONAL SOS FIELDS. ['+r+'x'+c+'] '+sos[num]); + } + } + + if (fieldlen) { + chars = fieldchar.repeat(fieldlen); + } + + byte = ''; + + this.frame_fields.push({ + ftype: fieldtype, + flength: fieldlen, + fchar: fieldchar, + fname: field, + r: r, + c: c, + attribute: {i:i,f:f,b:b}, + fvalue: '', + }); + + log(LOG_DEBUG,'SOS Field found at ['+r+'x'+(c-1)+'], Type: '+fieldtype+', Length: '+fieldlen+', Attrs: '+JSON.stringify({i:i,f:f,b:b})); + + break; + + default: + log(LOG_DEBUG,'DEFAULT ['+r+'x'+c+'] '+advance); + } + + break; + + default: + c++; + } + + output += byte; + + if (advance) { + //log(LOG_DEBUG,'ADVANCE P ['+r+'x'+c+'] '+advance+', NEXT CHAR: '+text.charAt(p+advance)+' ('+text.charCodeAt(p+advance)+')'); + output += chars; + p += advance; + } + + if (c>FRAME_WIDTH) { + c = 1; + r++; + } + + /* + // @todo - If we are longer than FRAME_LENGTH, move the output into the next frame. + if (r>FRAME_LENGTH) { + break; + } + */ + } + + return output; + }; + + this.save=function() { + file = system.mods_dir+'ansitex/text/'+this.page+'.tex'; + w = new File(file); + if (! w.open('w')) { + log(LOG_ERROR,'! ERROR: Unable to create TEX file for '+this.page); + exit(1); + } + + w.write(JSON.stringify(this)); + w.close(); + + log(LOG_DEBUG,'Saved file: '+this.page+'.tex'); + } + + /** + * Send a message to the baseline. + * + * @param text + * @param reposition + */ + this.sendBaseline=function(text,reposition) { + eval('var msg = VIEWDATA_'+text+';'); + var x = this.strlen(msg); + + write_raw(VIEWDATA_HOME+VIEWDATA_UP+msg+ + ((blp > x) + ? (' '.repeat(blp-x)+(reposition ? VIEWDATA_HOME+VIEWDATA_UP+VIEWDATA_RIGHT.repeat(x) : '')) + : '') + ); + + blp = x; + } + + this.clearBaseline=function(reposition) { + msg = ''; + + write_raw(VIEWDATA_HOME+VIEWDATA_UP+msg+ + ((blp > msg.length) + ? (' '.repeat(blp-msg.length)+(reposition ? VIEWDATA_HOME+VIEWDATA_UP+VIEWDATA_RIGHT.repeat(msg.length) : '')) + : '') + ); + + blp = msg.length; + } + + Object.defineProperty(this,'accessible',{ + get: function() { + log(LOG_DEBUG,'- Checking if user can access frame: '+this.page); + log(LOG_DEBUG,' - User: '+JSON.stringify(user.number)); + log(LOG_DEBUG,' - Frame Owner: '+JSON.stringify(this.owner)+', System Frame: '+(this.pageowner == SYSTEM_OWNER)); + + // user.number 0 is unidentified user. + if (user.number) { + return ( + (this.isAccessible && this.pageowner == SYSTEM_OWNER && ! this.isPublic) || + (this.isAccessible && this.isPublic) || + (this.isAccessible && ! this.isPublic && this.isMember) || + (pageEditor(this.frame)) + ); + + } else { + return (this.isAccessible && this.pageowner == SYSTEM_OWNER && this.isPublic); + } + } + }); + + Object.defineProperty(this,'fields', { + get: function() { + return this.frame_fields; + } + }); + + // Check if the user is already a member of the CUG + Object.defineProperty(this,'isMember',{ + get: function() { + log(LOG_DEBUG,'- Checking if user is a member of frame: '+this.page); + + if (user.number) { + return ( + (this.pageowner == SYSTEM_OWNER) + ); + + } else { + return false; + } + } + }) + + Object.defineProperty(this,'page', { + get: function() { + if (this.frame == null || this.index == null) return null; + return this.frame.toString()+this.index; + } + }); + + Object.defineProperty(this,'pageowner', { + get: function() { + return pageOwner(this.frame).prefix; + } + }) + + Object.defineProperty(this,'pageownerlogo', { + get: function() { + return base64_decode(pageOwner(this.frame).logovtx); + } + }) +} + +function videotex(data) { + var output = ''; + //$output .= ($byte < 32) ? ESC.chr($byte+64) : chr($byte); + for (var i = 0; i < data.length; i++) { + output += (data.charCodeAt(i) < 32) ? "\x1b"+String.fromCharCode(data.charCodeAt(i)+64) : String.fromCharCode(data.charCodeAt(i)); + } + return output; +} diff --git a/main.js b/main.js index d299153..ccfe251 100644 --- a/main.js +++ b/main.js @@ -101,7 +101,7 @@ while(bbs.online) { fo.sendBaseline('INACTIVITY',false); if (cf) - console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m'); + fo.attr(cf.attribute); } } else { @@ -109,7 +109,7 @@ while(bbs.online) { fo.clearBaseline(false); if (cf) - console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m'); + fo.attr(cf.attribute); } timer = time(); @@ -307,8 +307,8 @@ while(bbs.online) { cc.prefield(); mode = MODE_FIELD; - console.gotoxy(cf.c,cf.r); - console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m'); + fo.gotoxy(cf.c,cf.r); + fo.attr(cf.attribute); console.write(cf.fchar.repeat(cf.fvalue.length)); fo.cursorOn(cf.c,cf.r); cf.fvalue = ''; @@ -397,8 +397,8 @@ while(bbs.online) { cc.prefield(); mode = MODE_FIELD; - console.gotoxy(cf.c,cf.r); - console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m'); + fo.gotoxy(cf.c,cf.r); + fo.attr(cf.attribute); // Finished all editable fields. } else { @@ -448,8 +448,8 @@ while(bbs.online) { cc.prefield(); mode = MODE_FIELD; - console.gotoxy(cf.c+cf.fvalue.length,cf.r); - console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m'); + fo.gotoxy(cf.c+cf.fvalue.length,cf.r); + fo.attr(cf.attribute); break; @@ -470,8 +470,8 @@ while(bbs.online) { cc.prefield(); mode = MODE_FIELD; - console.gotoxy(cf.c+cf.fvalue.length,cf.r); - console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m'); + fo.gotoxy(cf.c+cf.fvalue.length,cf.r); + fo.attr(cf.attribute); break; @@ -788,6 +788,11 @@ while(bbs.online) { if (fo.page == null) { fo = current; + + // In case the frame doesnt exist + if (fo == null) + fo = (client.socket.local_port !== 516) ? new ANSIFrame() : new VIEWDATAFrame(); + // sendbaseline ERR_PAGE fo.sendBaseline('ERR_ROUTE',false); mode = action = false; @@ -899,7 +904,7 @@ while(bbs.online) { if (cf) { mode = MODE_FIELD; fo.cursorOn(cf.c,cf.r); - console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m'); + fo.attr(cf.attribute); // There were no editable fields. } else { diff --git a/text/1a.vtx b/text/1a.vtx new file mode 100644 index 0000000..93410b5 --- /dev/null +++ b/text/1a.vtx @@ -0,0 +1 @@ +{"version":1,"frame":"1","index":"a","owner":0,"cost":0,"content":"FiAgF3AwcDBwIGBwcCBzMXAwcCAgICAgICAgICAgICAgICAgICAgIAQdIBd/N2o3ajVzcXo1fzV/N2o1ICAgICAgICAgICAgICAgICAgICAEHSAXfzVqNWo1fzV6NX81fzVqNSAgICAgICAgICAgICAgICAgICAgICAgFyMhIiEiISIjIiEjISMhIiEgICAgICAgICAgICAgICAgICAgIAQdIAcqMF8gdG8gZ2V0IGJhY2sgaGVyZSBhbnl0aW1lLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAQ1VbmRlciBDb25zdHJ1Y3Rpb24hICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAzEHTWVzc2FnZXMgICAgICAgICAgICAgIAIqOTBfB1VzZXIgTWVudQMzB0ZpZG9OZXQgTmV0d29ya3MgICAgICACKjkxXwdNZXNzYWdlcyADNQdEaXJlY3RvcnkgICAgICAgICAgICAgICAgICAgICAgICAgICAgAzgHSGVscCAgICAgICAgICAgICAgICAgIAIqOTVfB0hlbHAgICAgIAM5B0Fib3V0IHRoaXMgc3lzdGVtICAgICACKjk3XwdEaXJlY3RvcnkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAIqOTlfB0xvZ29mZiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV291bGQgeW91IGxpa2UgdG8gaGF2ZSB5b3VyIG93biBwYWdlcyAgIG9uIHRoaXMgc3lzdGVtPyBDb250YWN0IG1lISAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAFkZW9uQGxlZW5vb2tzLm5ldCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA==","isPublic":1,"isAccessible":1,"type":"i","key":[null,91,null,11,null,97,null,null,5160,516],"date":"2020-07-05T12:57:03.790Z"} diff --git a/text/98a.vtx b/text/98a.vtx new file mode 100644 index 0000000..ed7de99 --- /dev/null +++ b/text/98a.vtx @@ -0,0 +1 @@ +{"version":1,"frame":98,"index":"a","owner":9,"cost":0,"content":"ICAgF3AwYDBgMGBwcCB/NSAgYHBwIGBwcCBwMHAwcCBgcHAgfzUgIAQdIBd/NWo1ajV/dXo1fzUgIH81IiF/NWo1fzdqN2o1f3V6NX81ICAEHSAXf3VqdWo1fzVgMH81IDB/NWAwfzVqNX81ajVqNX81YDBwMCAgICAgFyIhIyEjISIjIyAiIyMgIiMjICIjIyAjISIhIiEiIyMgIyEgIAQdIAdBIHZCQlMgYnkDLi4uZGVvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIBQaeH18NCAgfgcgICAgICAgICAgICAgICAgICAgICAgICAgICAUGnh8eH9/fzAgIH98ByAgICAgICAgICAgICAgICAgICAgICAgICAUGnh/f39/f39/fXh/fzQHICAgICAgICAgICAgICAgICAgICAgIBQaYHh/f39/f39/f39/f399dAcgICAgICAgICAgICAgICAgICAgFBp4f38vLy8vLy8vLy8vLy9/f398ByAgICAgICAgICAgICAgICAgIBQaf39/B1dlbGNvbWUgdG8Uf39/f30HICAgICAgICAgICAgICAgICAUGmt/f39/f39/f39/Ly8vLy8vL39/ByAgICAgICAgICAgICAgICAgFBoif39/f39/f39/fwNPelRleBR/PwcgICAgICAgICAgICAgICAgICAUGmt/f39/JyMgIm9/f39/f39/fyUHICAgICAgICAgICAgICAgICAgFBoqfz8nISAgICAgISt/f39/fz8HICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIBQab39vfy8HICABVXNlcjoHLi4uLi4uLi4uLi4uICAgICAgICAgICAgFBpgdHQHICAgAVBhc3M6By4uLi4uLi4uLi4uLiAgICAgICAgICAgICAUGm8lByAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRvIHJlZ2lzdGVyIGFzIGEgbmV3IHVzZXIsIHVzZQFORVdfICAgCg==","isPublic":1,"isAccessible":1,"type":"l","key":[null,"login",null,null,null,null,null,null,null,null],"frame_fields": [{"ftype":"t","flength":"25","fchar":".","fname":"USER","r":18,"c":7,"attribute":{},"fvalue":""},{"ftype":"p","flength":"40","fchar":".","fname":"PASS","r":19,"c":7,"attribute":{},"fvalue":""}],"date":"2020-07-08T05:17:35.174Z"}