From 0febc9ff38cfa5df814e69d1aa6c16829d7d2bbd Mon Sep 17 00:00:00 2001 From: Deon George Date: Wed, 27 May 2020 21:56:12 +1000 Subject: [PATCH] Enabled login and shell --- load/defs.js | 166 +++++++++++++-------- load/funcs.js | 13 +- main.js | 391 +++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 471 insertions(+), 99 deletions(-) diff --git a/load/defs.js b/load/defs.js index 24fc800..df54c8a 100644 --- a/load/defs.js +++ b/load/defs.js @@ -2,6 +2,7 @@ * ANSItex definitions */ +var ACTION_EXIT =99; /* Exit the script */ var ACTION_RELOAD =1; /* Reload the current frame */ var ACTION_GOTO =2; /* Goto a specific frame */ var ACTION_BACKUP =3; /* Goto previous frame */ @@ -11,6 +12,11 @@ var ACTION_SUBMITRF =6; /* Submit form contents */ var ACTION_STAR =7; /* Star command entry */ var MODE_BL =1; /* Typing * command on baseline */ +var MODE_FIELD =2; /* Field Input */ +var MODE_SUBMITRF =3; /* Asking if form should be submitted */ +var MODE_RFNOTSENT =4; /* Response frame not sent */ +var MODE_RFSENT =5; /* Response frame sent */ +var MODE_RFERROR =6; /* Response frame error */ var FRAME_LENGTH =22; /* Length of a frame */ var FRAME_WIDTH =80; /* Width of a frame */ @@ -19,52 +25,71 @@ var FRAME_PAGENUM =12; /* Size of page number (length with a-z) */ var FRAME_COST = 9; /* Size of cost (length without unit) */ var FRAME_COSTUNIT ='c'; /* Unit of cost */ -var FRAME_TYPE_INFO ='i'; -var FRAME_TYPE_TERMINATE ='t'; -var FRAME_TYPE_EXTERNAL ='x'; -var FRAME_TYPE_RESPONSE ='r'; -var FRAME_TYPE_LOGIN ='l'; +var FRAME_TYPE_INFO ='i'; // Information Frame, requires no response after viewed +var FRAME_TYPE_TERMINATE ='t'; // Terminate Frame, contents displayed and then carrier dropped +var FRAME_TYPE_EXTERNAL ='x'; // Frame the calls an External Method + // Contents indicate the method to be called with arguments +var FRAME_TYPE_RESPONSE ='r'; // Response frame, input fields are embedded in the frame and after input the + // response will be submitted to the Service Provider, or to a method +var FRAME_TYPE_LOGIN ='l'; // Login frame, enables the user to authenticate to the system, or to a CUG -var ERR_NOT_IMPLEMENTED ='\1RNOT IMPLEMENTED YET?'; +var MSG_SENDORNOT ='\1n\1h\1GKEY 1 TO SEND, 2 NOT TO SEND'; +var MSG_LOGON ='\1n\1h\1GKEY 1 TO LOGON, 2 TO RETURN'; +var MSG_SENT ='\1n\1h\1GMESSAGE SENT - KEY # TO CONTINUE'; +var MSG_NOTSENT ='\1n\1h\1GMESSAGE NOT SENT - KEY # TO CONTINUE'; +var ERR_NOT_IMPLEMENTED ='\1n\1h\1RNOT IMPLEMENTED YET?'; var ERR_ROUTE ='\1n\1h\1WMISTAKE? \1GTRY AGAIN OR TELL US ON *08'; +var ERR_METHOD_NOT_EXIST ='\1n\1h\1WMISTAKE? \1GTRY AGAIN OR TELL US ON *08'; +var ACCESS_DENIED ='\1n\1h\1RACCESS DENIED. \1RMISTAKE? TRY AGAIN OR TELL US *08'; var NO_HISTORY_FRAMES =['98b']; +var SYSTEM_FRAMES =['AWgBUkEBR04BQlMBWUkBbgE3AWt0ZXgBbg==']; + // Our frame object function Frame() { - this.version=1; - this.frame=null; - this.index=null; - this.owner=''; // @todo - this.cost=0; // @todo - this.content=''; - this.isPublic=false; // @todo - this.isAccessible=false; // @todo - this.type = FRAME_TYPE_INFO; - this.key=[ null,null,null,null,null,null,null,null,null,null ]; + 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=''; // The Service Provider owning the frame. + this.cost=0; // The cost to view the frame @TODO + this.content=''; // The frame content - // Initialise frame array - /* - this.frame_data = {}; - this.frame_content = {}; - for(x=0;x-1)); + + system_frame = (SYSTEM_FRAMES.indexOf(this.owner)>-1); + + // user.number 0 is unidentified user. + if (user.number) { + return ( + (this.isAccessible && this.isPublic) || + (this.isAccessible && ! this.isPublic && user.isMember) || + (user.isOwner) + ); + + } else { + return (system_frame && this.isPublic && this.isAccessible); + } + } + }); } // Load a frame from disk (.tex file) @@ -102,7 +149,7 @@ Frame.prototype.load = function(filename) { } try { - load = JSON.parse(f.read()); + var load = JSON.parse(f.read()); for (property in load) { this[property] = load[property]; @@ -134,8 +181,9 @@ Frame.prototype.load = function(filename) { */ Frame.prototype.parse = function(text) { var c = 1; // column - var r = 1; // row + var r = 2; // row (row 1 is the header) var output = ''; + this.frame_fields = []; // Default Attributes f = 39; @@ -146,11 +194,11 @@ Frame.prototype.parse = function(text) { // Look for a special character until the end of the frame width cte = (r*FRAME_WIDTH - ((r-1)*FRAME_WIDTH+c)); match = text.substr(p,cte).match(/[\r\n\x1b]/); - log(LOG_DEBUG,'SPECIAL CHAR ['+r+'x'+c+'] ['+p+'-'+cte+'] for: '+match); + //log(LOG_DEBUG,'SPECIAL CHAR ['+r+'x'+c+'] ['+p+'-'+cte+'] for: '+match); if (match == null || match.index) { advance = match ? match.index : cte; - log(LOG_DEBUG,'INCLUDE: '+text.substr(p,advance)); + //log(LOG_DEBUG,'INCLUDE: '+text.substr(p,advance)); output += text.substr(p,advance); p += advance; @@ -165,13 +213,13 @@ Frame.prototype.parse = function(text) { switch (byte) { // Carriage Return case '\r': - log(LOG_DEBUG,'CR'); + // log(LOG_DEBUG,'CR'); c=1; break; // New line case '\n': - log(LOG_DEBUG,'LF'); + // log(LOG_DEBUG,'LF'); r++; break; @@ -180,7 +228,7 @@ Frame.prototype.parse = function(text) { advance = 1; // Is the next byte something we know about nextbyte = text.charAt(p+advance); - log(LOG_DEBUG,'ESC ['+r+'x'+c+'] NEXT: '+nextbyte); + //log(LOG_DEBUG,'ESC ['+r+'x'+c+'] NEXT: '+nextbyte); switch (nextbyte) { // CSI @@ -190,7 +238,7 @@ Frame.prototype.parse = function(text) { // Find our end CSI param in the next 50 chars matches = text.substr(p+advance,50).match(/([0-9]+[;]?)+([a-zA-Z])/); - log(LOG_DEBUG,'CSI ['+r+'x'+c+'] ADVANCE: '+advance+', MATCHES: '+matches+', STRING: '+text.substr(p+advance,50)); + //log(LOG_DEBUG,'CSI ['+r+'x'+c+'] ADVANCE: '+advance+', MATCHES: '+matches+', STRING: '+text.substr(p+advance,50)); if (! matches) { chars += nextbyte; @@ -200,17 +248,17 @@ Frame.prototype.parse = function(text) { advance += matches[0].length-1; chars += nextbyte+matches[0]; - log(LOG_DEBUG,'CSI ['+r+'x'+c+'] ADVANCE: '+advance+', CHARS: '+chars+', CHARSLEN: '+chars.length); + //log(LOG_DEBUG,'CSI ['+r+'x'+c+'] ADVANCE: '+advance+', CHARS: '+chars+', CHARSLEN: '+chars.length); switch (matches[2]) { // Color CSIs case 'm': - log(LOG_DEBUG,'CSI m ['+r+'x'+c+'] MATCHES: '+matches[0]+', LENGTH : '+matches[0].length); + //log(LOG_DEBUG,'CSI m ['+r+'x'+c+'] MATCHES: '+matches[0]+', LENGTH : '+matches[0].length); csi = matches[0].substr(0,matches[0].length-1).split(';'); var num = null; for (num in csi) { - log(LOG_DEBUG,'CSI m ['+r+'x'+c+'] NUM: '+num+', CSI: '+csi[num]); + //log(LOG_DEBUG,'CSI m ['+r+'x'+c+'] NUM: '+num+', CSI: '+csi[num]); // Intensity if (csi[num] >= 0 && csi[num] <= 8) { i = csi[num]; @@ -230,12 +278,12 @@ Frame.prototype.parse = function(text) { // Advance characters case 'C': - log(LOG_DEBUG,'CSI C ['+r+'x'+c+'] CHARS: '+matches[1]); + //log(LOG_DEBUG,'CSI C ['+r+'x'+c+'] CHARS: '+matches[1]); c += parseInt(matches[1]); // Advance our position break; default: - dump('? CSI: '.matches[2]); + log(LOG_DEBUG,'? CSI: '.matches[2]); } break; @@ -247,12 +295,12 @@ Frame.prototype.parse = function(text) { // SOS case '_': - log(LOG_DEBUG,'SOS ['+r+'x'+c+'] '+advance); + //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)); + //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; @@ -264,12 +312,12 @@ Frame.prototype.parse = function(text) { // 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); + //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]); + //log(LOG_DEBUG,'SOS ['+r+'x'+c+'] NUM: '+num+', SOS: '+sos[num]); switch (num) { // First value is the field name @@ -285,7 +333,7 @@ Frame.prototype.parse = function(text) { break; } - log(LOG_DEBUG,'SOS ['+r+'x'+c+'] NUM CHARS: '+x[1]+', TYPE: '+x[2]); + //log(LOG_DEBUG,'SOS ['+r+'x'+c+'] NUM CHARS: '+x[1]+', TYPE: '+x[2]); fieldlen = x[1]; fieldtype = x[2]; break; @@ -296,7 +344,7 @@ Frame.prototype.parse = function(text) { break; default: - log(LOG_ERROR,'IGNORING ADITIONAL SOS FIELDS. ['+r+'x'+c+'] '+sos[num]); + log(LOG_ERROR,'IGNORING ADDITIONAL SOS FIELDS. ['+r+'x'+c+'] '+sos[num]); } } @@ -307,11 +355,12 @@ Frame.prototype.parse = function(text) { byte = ''; this.frame_fields.push({ - type: fieldtype, - length: fieldlen, + ftype: fieldtype, + flength: fieldlen, 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})); @@ -325,16 +374,13 @@ Frame.prototype.parse = function(text) { break; default: - //this.frame_data[r][c] = {i:i,f:f,b:b}; - //this.frame_content[r][c] = byte; - log(LOG_DEBUG,'ADD OUTPUT ['+r+'x'+c+'] for: '+byte); c++; } output += byte; if (advance) { - log(LOG_DEBUG,'ADVANCE P ['+r+'x'+c+'] '+advance+', NEXT CHAR: '+text.charAt(p+advance)+' ('+text.charCodeAt(p+advance)+')'); + //log(LOG_DEBUG,'ADVANCE P ['+r+'x'+c+'] '+advance+', NEXT CHAR: '+text.charAt(p+advance)+' ('+text.charCodeAt(p+advance)+')'); output += chars; p += advance; } @@ -344,19 +390,15 @@ Frame.prototype.parse = function(text) { r++; } + /* // @todo - If we are longer than FRAME_LENGTH, move the output into the next frame. if (r>FRAME_LENGTH) { break; } - - // Debugging - if (false && r > 3) { - console.write(output); - bbs.hangup(); - exit(1); - } - + */ } return output; -}; \ No newline at end of file +}; + +this; \ No newline at end of file diff --git a/load/funcs.js b/load/funcs.js index ea5b8a3..8cd594c 100644 --- a/load/funcs.js +++ b/load/funcs.js @@ -41,6 +41,9 @@ if (!String.prototype.repeat) { }; } +/** + * Turn off the cursor + */ function cursorOff() { ansi.send('ext_mode','clear','cursor'); console.gotoxy(0,24); @@ -148,6 +151,12 @@ function saveFrame(frame) { log(LOG_DEBUG,'Saved file: '+frame.page+'.tex'); } +/** + * Send a message to the baseline. + * + * @param text + * @param reposition + */ function sendBaseline(text,reposition) { console.pushxy(); console.gotoxy(0,24); @@ -157,4 +166,6 @@ function sendBaseline(text,reposition) { if (! reposition) { console.popxy(); } -} \ No newline at end of file +} + +this; \ No newline at end of file diff --git a/main.js b/main.js index 2bb5b36..ce3226e 100644 --- a/main.js +++ b/main.js @@ -1,34 +1,46 @@ +log(LOG_DEBUG,'- INIT: ANSITEX'); + // Load many SBBS definitions -load('sbbsdefs.js'); -// Load text.dat defintions -load('text.js'); +require('sbbsdefs.js','SS_UNUSED'); +// Load text.dat definitions +require('text.js','TOTAL_TEXT'); // Key definitions -load('key_defs.js'); -// Enable to manipulate the ANSI terminal +require('key_defs.js','KEY_ESC'); + ansi = load({},'ansiterm_lib.js'); +load('ansitex/load/funcs.js'); // Ansitex specific includes -load('ansitex/load/defs.js'); -load('ansitex/load/funcs.js'); +require('ansitex/load/defs.js','ACTION_EXIT'); while(bbs.online) { var mode = false; // Initial mode - var next_page = { frame: 98,index: 'b' }; // Start Frame + + // If the user is already on, our start page is 98b + var next_page = { frame: 98,index: user.number ? 'b' : 'a' }; // Start Frame + var action = ACTION_GOTO; // Initial action - var inkey_timeout = 600000; // Timeout waiting for input @todo required? check if idle timetout occurs + var inkey_timeout = 10000; // Timeout waiting for input @todo required? check if idle timeout occurs var fo = null; // Current Frame + var fn = null; // Current Field Number for an Input Frame var history = []; // Page history + + var control = []; // Methods that need to process input + ansi.send('ext_mode','clear','cursor'); - while (action != ACTION_TERMINATE) { + while (action != ACTION_TERMINATE && action !=ACTION_EXIT) { bbs.nodesync(false); // @todo Stop the display of telegrams read = ''; + + // If we have no action, read from the terminal if (action == false) { read = console.inkey(K_NONE,inkey_timeout); } - system.node_list[bbs.node_num-1].action=0xff; // to ensure our node status is updated correctly - inkey_timeout = 60000; // Set our key timeout to 60s log(LOG_DEBUG,'READ: ['+read+']'); + inkey_timeout = 60000; // Set our key timeout to 60s + + system.node_list[bbs.node_num-1].action=0xff; // to ensure our node status is updated correctly log(LOG_DEBUG,'MODE START: ['+read+']'); switch (mode) { @@ -177,10 +189,272 @@ while(bbs.online) { break; - // @todo MODE_CONTROL + // Key presses during field input. + case MODE_FIELD: + //$cmd = ''; + action = false; + + switch (fo.type) { + // Login frame. + case FRAME_TYPE_LOGIN: + switch (read) { + case '#': + case '\r': + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_LOGIN: ['+read+'] A'); + // If we are the main login screen, see if it is a new user + //if ($this->fo->isCUG(0)) { + if (fo.frame_fields[fn].ftype == 't' && fo.frame_fields[fn].fvalue == 'NEW') { + action = ACTION_GOTO; + next_page = { frame: 981,index: 'a' }; // @todo This should be in the INI. + + break; + } + //} + + break; + } + + // Response frame. + case FRAME_TYPE_RESPONSE: + // If we came from FRAME_TYPE_LOGIN and the user typed NEW to register + if (action == ACTION_GOTO) + break; + + switch (read) { + // End of field entry. + case '#': + case '\r': + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ['+read+'] A'); + // Next Field + fn++; + + cf = fo.frame_fields[fn]; + log(LOG_DEBUG,'fn:'+fn+', cf'+JSON.stringify(cf)); + + if (cf) { + mode = MODE_FIELD; + console.gotoxy(cf.c,cf.r); + console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m'); + + // Finished all editable fields. + } else { + action = ACTION_SUBMITRF; + } + + break; + + case '*': + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ['+read+'] B'); + + //$current['prevmode'] = MODE_FIELD; + action = ACTION_STAR; + + break; + + case KEY_DEL: + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ['+read+'] C'); + /* + if ($this->fo->setFieldCurrentInputDelete()) + $client->send(LEFT.$this->fo::$if_filler.LEFT); + + */ + + break; + + case KEY_ESC: + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ['+read+'] D'); + break; + + // Record Data Entry + default: + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ['+read+'] E:'+read.charCodeAt(0)+' cf:'+(cf ? cf.flength : '{}')); + + if (read.charCodeAt(0) > 31 && cf.fvalue.length < cf.flength) { + cf.fvalue += read; + console.write((cf.ftype == 't') ? read : 'x'); + } + } + + break; + + // Other Frame Types - Shouldnt get here. + default: + log(LOG_DEBUG,'- SHOULDNT GET HERE: ['+read+']'); + action = ACTION_TERMINATE; + } + + break; + + // Form submission: 1 to send, 2 not to send. + case MODE_SUBMITRF: + switch (read) { + case '1': + log(LOG_DEBUG,'- MODE_SUBMITRF: Key ['+read+'] ['+pageStr(fo)+']'); + log(LOG_DEBUG,' - Frame fields: '+JSON.stringify(fo.frame_fields)); + log(LOG_DEBUG,' - Key 1 is:'+JSON.stringify(fo.key[1])); + + // If we are in a control method, complete it + if (control.count) { + log(LOG_DEBUG,'Last control method is:'+JSON.stringify(control[control.length-1])); + + control[control.length-1].process(); + + } else if (fo.key[1] == '*' || fo.key[1].match(/[0-9]/)) { + sendBaseline('\1n\1h\1RNO ACTION PERFORMED',false); + mode = MODE_RFSENT; + + } else { + log(LOG_DEBUG,' - Key 1 is a METHOD check it exists:'+JSON.stringify(fo.key[1])); + + switch(fo.key[1]) { + // User is logging in to system or CUG + case 'login': + log(LOG_DEBUG,' - User:'+JSON.stringify(fo.frame_fields[0].fvalue)); + + // If login is successful, we'll exit here + if (bbs.login(fo.frame_fields[0].fvalue,null,fo.frame_fields[1].fvalue)) { + log(LOG_DEBUG,' - User:'+JSON.stringify(user.number)); + bbs.logon(); + log(LOG_DEBUG,' - SEND TO EXIT:'); + + action = ACTION_EXIT; + break; + } + + log(LOG_DEBUG,' ! Login failed for User:'+JSON.stringify(fo.frame_fields[0].fvalue)); + break; + } + /* + + } elseif ($ao = FrameClass\Action::factory($this->fo->route(1),$this,$user,$action,$mode)) { + $ao->handle(); + $mode = $ao->mode; + $action = $ao->action; + + if ($ao->page) + $next_page = $ao->page; + + } else { + sendBaseline(ERR_METHOD_NOT_EXIST,false); + + mode = MODE_RFSENT; + } + */ + } + + break; + + case '2': + log(LOG_DEBUG,'- MODE_SUBMITRF: Key ['+read+'] ['+pageStr(fo)+']'); + // @todo Check if HASH is a valid next destination + + if (fo.type == 'l') { + action = ACTION_RELOAD; + mode = false; + + } else { + sendBaseline(MSG_NOTSENT,false); + mode = MODE_RFNOTSENT; + } + + /* + // If a Control method was rejected, we can clear it + if ($control AND $method->count()) { + $save = $method->pop(); + + if ($method->count()) { + $control = $method->last()->state['control']; + + } else { + $mode = $save->state['mode']; + $action = $save->state['action']; + $control = FALSE; + } + } + */ + + break; + + case '*': + action = ACTION_STAR; + + break; + } + + break; + + // Response form after Sent processing + case MODE_RFSENT: + ansi.send('ext_mode','clear','cursor'); + + switch (read) { + case '*': + action = ACTION_STAR; + break; + } + + /* + if ($read == HASH) { + if ($x = $this->fo->route(2) AND $x !== '*' AND is_numeric($x)) { + $next_page = ['frame'=>$x]; + + } elseif (FrameModel::where('frame',$this->fo->frame())->where('index',$this->fo->index_next())->exists()) { + $next_page = ['frame'=>$this->fo->frame(),'index'=>$this->fo->index_next()]; + + } elseif ($x = $this->fo->route(0) AND $x !== '*' AND is_numeric($x)) { + $next_page = ['frame'=>$x]; + + // No further routes defined, go home. + } else { + $next_page = ['frame'=>0]; + } + + $action = ACTION_GOTO; + + } + + */ + break; + + // Response form after NOT sending + case MODE_RFNOTSENT: + + // Response form ERROR + case MODE_RFERROR: + cursorOff(); + + if (read == '#') { + /* + if ($x = $this->fo->route(2) AND $x !== '*' AND is_numeric($x)) { + $next_page = ['frame'=>$x]; + + } elseif (FrameModel::where('frame',$this->fo->frame())->where('index',$this->fo->index_next())->exists()) { + $next_page = ['frame'=>$this->fo->frame(),'index'=>$this->fo->index_next()]; + + } elseif ($x = $this->fo->route(0) AND $x !== '*' AND is_numeric($x)) { + $next_page = ['frame'=>$x]; + + // No further routes defined, go home. + } else { + $next_page = ['frame'=>0]; + } + */ + + action = ACTION_GOTO; + + } else if (read == '*') { + action = ACTION_STAR; + + break; + } + + break; + + // @todo MODE_CONTROL default: log(LOG_DEBUG,'- SHOULDNT GET HERE: ['+read+']'); + action = ACTION_TERMINATE; } log(LOG_DEBUG,'MODE END: ['+read+']'); @@ -202,6 +476,16 @@ while(bbs.online) { break; + // Submitting forms + case ACTION_SUBMITRF: + action = false; + cursorOff(); + log(LOG_DEBUG,'- ACTION_SUBMITRF: ['+fo.type+']'); + sendBaseline((fo.type == 'l' ? MSG_LOGON : MSG_SENDORNOT),true); + mode = MODE_SUBMITRF; + + break; + // GO Backwards case ACTION_BACKUP: // Do we have anywhere to go, drop the current page from the history. @@ -239,28 +523,19 @@ while(bbs.online) { current = null; } - if (fo.isPublic && fo.isAccessible) { + // If the user has access to the frame + if (fo.accessible) { // @todo if its a login frame and the user is already member of CUG, display error if (false) { // baseline USER_ALREADY_MEMBER break; } + // Check if the frame exists, and the user is the Service Provider } else { - // @todo if user is not the owner - if (false) { - // @todo if frame is not accessible - if (false) { - // baseline ACCESS_DENIED - break; - } - - // @todo if user not a member - if (false) { - // baseline ACCESS_DENIED_NOT_IN_CUG - break; - } - } + sendBaseline(ACCESS_DENIED,false); + mode = action = false; + break; } log(LOG_DEBUG,'- ACTION_GOTO: next_page ['+JSON.stringify(next_page)+'] last history ['+JSON.stringify(history[history.length-1])+']'); @@ -276,6 +551,7 @@ while(bbs.online) { next_page = null; + // Load frame case ACTION_RELOAD: log(LOG_DEBUG,'- ACTION_RELOAD: ['+(next_page ? pageStr(next_page) : '')+']'); @@ -292,8 +568,10 @@ while(bbs.online) { // Terminate frame case FRAME_TYPE_TERMINATE: console.putmsg(fo.render()); - bbs.hangup(); - exit(); + mode = false; + action = ACTION_TERMINATE; + + break; // External Frame // @todo returning from the frame, go to the 0 key if it is set @@ -327,13 +605,46 @@ while(bbs.online) { break; case FRAME_TYPE_LOGIN: + action = false; + + /* + // If this is the registration page + // @todo Should be evaluated out of the DB + if ($this->fo->page() == '981a') { + $control = CONTROL_METHOD; + $method->push(Control::factory('register',$this)); + $method->last()->state['control'] = $control; + $method->last()->state['action'] = FALSE; + $method->last()->state['mode'] = MODE_FIELD; + } + */ + case FRAME_TYPE_RESPONSE: - log(LOG_DEBUG,'response frame :'+fo.page); + //log(LOG_DEBUG,'FRAME_TYPE_RESPONSE :'+fo.page+', FIELDS: '+fo.frame_fields.count); + fn = 0; + cf = null; console.putmsg(fo.render()); - mode = action = false; - //fo.fields; - //bbs.hangup(); - //exit(); + + if (fo.frame_fields.length) { + cf = fo.frame_fields[fn]; + log(LOG_DEBUG,'cf'+JSON.stringify(cf)); + + if (cf) { + mode = MODE_FIELD; + ansi.send('ext_mode','set','cursor'); + console.gotoxy(cf.c,cf.r); + console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m'); + + // There were no editable fields. + } else { + mode = MODE_COMPLETE; + cursorOff(); + } + + } else { + mode = false; + } + break; // Standard Frame @@ -350,4 +661,12 @@ while(bbs.online) { } log(LOG_DEBUG,'ACTION END: ['+read+']'); } -} + + log(LOG_DEBUG,'- FINISHED'); + if (action == ACTION_TERMINATE) { + log(LOG_DEBUG,'! Hangup'); + bbs.hangup(); + } + + exit(); +} \ No newline at end of file