diff --git a/load/frame-ansi.js b/load/frame-ansi.js index db64113..68209b2 100644 --- a/load/frame-ansi.js +++ b/load/frame-ansi.js @@ -44,6 +44,7 @@ function FrameAnsi() { this.settings.USER_CREATE_ERROR = '\1n\1h\1RERROR CREATING USER, PLEASE TRY AGAIN *00'; this.settings.LOGIN_ERROR = '\1n\1h\1RERROR LOGGING IN, PLEASE TRY AGAIN *00'; this.settings.CANCEL_MSG = '\1n\1h\1GPRESS 2 TO CANCEL'; + this.settings.SYS_ERROR = '\1n\1h\1RSYSTEM ERROR DETECTED - TRY AGAIN OR TELL US *08'; /** * Set the attribute at the current position diff --git a/load/frame-viewdata.js b/load/frame-viewdata.js index d946b3f..65b9d84 100644 --- a/load/frame-viewdata.js +++ b/load/frame-viewdata.js @@ -45,22 +45,23 @@ function FrameViewdata() { this.settings.ERR_NOT_IMPLEMENTED = ascii(27)+'ANOT IMPLEMENTED YET?'; this.settings.ERR_ROUTE = ascii(27)+'GMISTAKE?'+ascii(27)+'BTRY AGAIN OR TELL US ON *08'; this.settings.ERR_METHOD_NOT_EXIST = ascii(27)+'GMISTAKE?'+ascii(27)+'BTRY AGAIN OR TELL US ON *08'; - this.settings.ACCESS_DENIED = ascii(27)+'ACCESS DENIED.'; - this.settings.ALREADY_MEMBER = ascii(27)+'AALREADY MEMBER OF CUG' - this.settings.INACTIVITY = ascii(27)+'AINACTIVITY ALERT, DISCONNECT PENDING...'; + this.settings.ACCESS_DENIED = ascii(27)+'AACCESS DENIED.'; + this.settings.ALREADY_MEMBER = ascii(27)+'AALREADY MEMBER OF CUG' + this.settings.INACTIVITY = ascii(27)+'AINACTIVITY ALERT, DISCONNECT PENDING...'; this.settings.INACTIVE = ascii(27)+'AINACTIVITY DISCONNECT'; this.settings.NOACTION = ascii(27)+'ANO ACTION PERFORMED'; this.settings.BASESTAR = ascii(27)+'B*'; this.settings.INVALID_CODE = ascii(27)+'AINVAID CODE, PLEASE TRY AGAIN *00'; this.settings.TOKEN_EMAIL = ascii(27)+'ATOKEN EMAILED TO YOU...'; - this.settings.TOKEN_SENT = ascii(27)+'ATOKEN SENT, PLEASE ENTER TOKEN'; + this.settings.TOKEN_SENT = ascii(27)+'ATOKEN SENT, PLEASE ENTER TOKEN'; this.settings.INVALID_EMAIL = ascii(27)+'AINVAID EMAIL, PLEASE TRY AGAIN *00'; this.settings.INVALID_UID = ascii(27)+'AINVAID USER ID, PLEASE TRY AGAIN *00'; this.settings.CANNOT_SEND_TOKEN = ascii(27)+'ACANNOT SEND VALIDATION CODE, PLEASE TRY AGAIN *00'; this.settings.USER_EXISTS = ascii(27)+'AERROR USER EXISTS, PLEASE TRY AGAIN *00'; this.settings.USER_CREATE_ERROR = ascii(27)+'AERROR CREATING USER, PLEASE TRY AGAIN *00'; this.settings.LOGIN_ERROR = ascii(27)+'AERROR LOGGING IN, PLEASE TRY AGAIN *00'; - this.settings.CANCEL_MSG = ascii(27)+'BPRESS 2 TO CANCEL'; + this.settings.CANCEL_MSG = ascii(27)+'BPRESS 2 TO CANCEL'; + this.settings.SYS_ERROR = ascii(27)+'ASYSTEM ERROR, TRY AGAIN OR TELL US ON *08'; var blp=0; // Length of data on the bottom line diff --git a/load/funcs.js b/load/funcs.js index 040ff5e..8b41f60 100644 --- a/load/funcs.js +++ b/load/funcs.js @@ -153,8 +153,7 @@ function atcode(field,length,pad,context) { var x = context.msgbase.first_msg || 1; - result = x ? context.getMessagePage(x) : null; - break; + return x ? context.getMessagePage(x) : null; // Newest message in msgarea case 'msg_area_msgnewest_date': @@ -172,8 +171,7 @@ function atcode(field,length,pad,context) { break; } - result = context.msgbase.last_msg ? context.getMessagePage(context.msgbase.last_msg) : null; - break; + return context.msgbase.last_msg ? context.getMessagePage(context.msgbase.last_msg) : null; // First unread message case 'msg_area_msgunread_date': @@ -193,8 +191,7 @@ function atcode(field,length,pad,context) { } var x = context.getUserStats().last_read+1; - result = (x <= context.msgbase.last_msg) ? context.getMessagePage(x) : null; - break; + return (x <= context.msgbase.last_msg) ? context.getMessagePage(x) : null; // First unread message to me case 'msg_area_msgotome_date': @@ -215,8 +212,7 @@ function atcode(field,length,pad,context) { } var x = context.newMsgs(); - result = x.length ? context.getMessagePage(x.shift().number) : null; - break; + return x.length ? context.getMessagePage(x.shift().number) : null; // Count of unread messages case 'msg_area_new': @@ -225,7 +221,7 @@ function atcode(field,length,pad,context) { break; } - result = ''+(context.msgbase.last_msg-context.getUserStats().last_read); + result = ''+context.newMsgs().length; break; // Count of unread messages to me @@ -235,7 +231,7 @@ function atcode(field,length,pad,context) { break; } - result = ''+context.newMsgs().length; + result = ''+context.newMsgsToMe().length; break; // Is this message area in my new scan list diff --git a/load/msgbases.js b/load/msgbases.js index a802f53..6518cc2 100644 --- a/load/msgbases.js +++ b/load/msgbases.js @@ -160,13 +160,36 @@ function MsgArea() { } /** - * New Messages for the logged in user + * Unread messages + * + * @returns {*[]} */ MsgArea.prototype.newMsgs = function() { var msgs = []; var stats = this.getUserStats(); //log(LOG_DEBUG,'Users scan pointer: '+JSON.stringify(stats.scan_ptr)); + for(var x in this.headers) { + // Advance past our last scan_ptr + if (x <= stats.last_read) + continue; + + msgs.push(this.headers[x]); + + write(); // @todo This is needed for this to work? + } + + return msgs; +} + +/** + * New Messages for the logged in user + */ +MsgArea.prototype.newMsgsToMe = function() { + var msgs = []; + var stats = this.getUserStats(); + //log(LOG_DEBUG,'Users scan pointer: '+JSON.stringify(stats.scan_ptr)); + for(var x in this.headers) { // Advance past our last scan_ptr if (x <= stats.scan_ptr) diff --git a/main.js b/main.js index e97c31a..773dcfb 100644 --- a/main.js +++ b/main.js @@ -121,1049 +121,1056 @@ while(bbs.online) { const viewdata = (client.socket.local_port === 516); while (action !== ACTION_TERMINATE && action !== ACTION_EXIT) { - bbs.nodesync(); // @todo Stop the display of telegrams + try { + bbs.nodesync(); // @todo Stop the display of telegrams - /* The current input character */ - var read = ''; - /* ESC key sequence received */ - var esc = false; + /* The current input character */ + var read = ''; + /* ESC key sequence received */ + var esc = false; - // If we have no action, read from the terminal - if (action === false) { - // If a special key sequence is coming... - while (esc || ! read) { - log(LOG_DEBUG,'- READ START'); - // Wait for a key from the user - read = console.inkey(K_NONE,inkey_timeout); + // If we have no action, read from the terminal + if (action === false) { + // If a special key sequence is coming... + while (esc || ! read) { + log(LOG_DEBUG,'- READ START'); + // Wait for a key from the user + read = console.inkey(K_NONE,inkey_timeout); - // We are entering a special keyboard char. - if (read === KEY_ESC) { - log(LOG_DEBUG,'- READ SPECIAL KEY COMING'); - esc = true; - // We reduce our timeout, and assume the key is a function key. If the user pressed ESC we'll process that later - inkey_timeout = 200; + // We are entering a special keyboard char. + if (read === KEY_ESC) { + log(LOG_DEBUG,'- READ SPECIAL KEY COMING'); + esc = true; + // We reduce our timeout, and assume the key is a function key. If the user pressed ESC we'll process that later + inkey_timeout = 200; - // If we got the ESC, but no [ then re-put the ESC in the read, we loose the current key - // @todo We loose the current pressed key - } else if (esc && ! extendedkey && read !== '[') { - log(LOG_DEBUG,'- READ SPECIAL KEY ABANDONED: ['+read+'] ('+read.charCodeAt(0)+')'); - esc = false; - inkey_timeout = INKEY_TIMEOUT; - read = KEY_ESC; + // If we got the ESC, but no [ then re-put the ESC in the read, we loose the current key + // @todo We loose the current pressed key + } else if (esc && ! extendedkey && read !== '[') { + log(LOG_DEBUG,'- READ SPECIAL KEY ABANDONED: ['+read+'] ('+read.charCodeAt(0)+')'); + esc = false; + inkey_timeout = INKEY_TIMEOUT; + read = KEY_ESC; - // Recognise when the ESC sequence has ended (with a ~ or ;) - } else if (esc && extendedkey && (read === '~' || read === ';' || ! read)) { - switch (extendedkey) { - case '[15': read = false; break; // F5 - case '[17': read = false; break; // F6 - case '[18': read = false; break; // F7 - case '[19': read = false; break; // F8 - case '[20': read = false; break; // F9 - case '[21': read = ascii(26); break; // F10 - case '[23': read = false; break; // F11 - case '[24': read = false; break; // F12 - default: - log(LOG_DEBUG,'- READ UNKNOWN KEY: ['+extendedkey+']'); - read = ''; - } - - esc = false; - extendedkey = ''; - inkey_timeout = INKEY_TIMEOUT; - - // Record the character as an extended key - } else if (esc) { - log(LOG_DEBUG,'- READ SPECIAL KEY ['+read+'] ('+read.charCodeAt(0)+')'); - extendedkey += read; - read = false; - } - - // Calculate idle timeouts - // If the user has exemption H we dont worry about timeout - if (! read && ! (user.security.exemptions&UFLAG_H) ) { - // Terminate the user if they have been inactive too long. - if (time() > timer+((user.number ? INACTIVE_LOGIN : INACTIVE_NOLOGIN)+INKEY_TIMEOUT)/1000) { - fo.sendBaseline('INACTIVE',false); - bbs.hangup(); - - // Idle warning - due to inactivity. - } else if (time() > timer+(user.number ? INACTIVE_LOGIN : INACTIVE_NOLOGIN)/1000) { - timeout = true; - fo.sendBaseline('INACTIVITY',false); - - if (cf) { - fo.gotoxy(cf.c+cf.fvalue.length,cf.r); - fo.attr(cf.attribute); + // Recognise when the ESC sequence has ended (with a ~ or ;) + } else if (esc && extendedkey && (read === '~' || read === ';' || ! read)) { + switch (extendedkey) { + case '[15': read = false; break; // F5 + case '[17': read = false; break; // F6 + case '[18': read = false; break; // F7 + case '[19': read = false; break; // F8 + case '[20': read = false; break; // F9 + case '[21': read = ascii(26); break; // F10 + case '[23': read = false; break; // F11 + case '[24': read = false; break; // F12 + default: + log(LOG_DEBUG,'- READ UNKNOWN KEY: ['+extendedkey+']'); + read = ''; } + + esc = false; + extendedkey = ''; + inkey_timeout = INKEY_TIMEOUT; + + // Record the character as an extended key + } else if (esc) { + log(LOG_DEBUG,'- READ SPECIAL KEY ['+read+'] ('+read.charCodeAt(0)+')'); + extendedkey += read; + read = false; } - } else { - // If the user become active during inactivity, clear the baseline message - if (timeout) { - fo.clearBaseline(false); + // Calculate idle timeouts + // If the user has exemption H we dont worry about timeout + if (! read && ! (user.security.exemptions&UFLAG_H) ) { + // Terminate the user if they have been inactive too long. + if (time() > timer+((user.number ? INACTIVE_LOGIN : INACTIVE_NOLOGIN)+INKEY_TIMEOUT)/1000) { + fo.sendBaseline('INACTIVE',false); + bbs.hangup(); - if (cf) { - fo.gotoxy(cf.c+cf.fvalue.length,cf.r); - fo.attr(cf.attribute); + // Idle warning - due to inactivity. + } else if (time() > timer+(user.number ? INACTIVE_LOGIN : INACTIVE_NOLOGIN)/1000) { + timeout = true; + fo.sendBaseline('INACTIVITY',false); + + if (cf) { + fo.gotoxy(cf.c+cf.fvalue.length,cf.r); + fo.attr(cf.attribute); + } } + + } else { + // If the user become active during inactivity, clear the baseline message + if (timeout) { + fo.clearBaseline(false); + + if (cf) { + fo.gotoxy(cf.c+cf.fvalue.length,cf.r); + fo.attr(cf.attribute); + } + } + + timer = time(); + timeout = false; } - timer = time(); - timeout = false; - } - - if (esc) { - log(LOG_DEBUG,'- READ SPECIAL KEY LOOP'); + if (esc) { + log(LOG_DEBUG,'- READ SPECIAL KEY LOOP'); + } } } - } - log(LOG_DEBUG,'READ: ['+read+'] ('+read.charCodeAt(0)+')'); + log(LOG_DEBUG,'READ: ['+read+'] ('+read.charCodeAt(0)+')'); - system.node_list[bbs.node_num-1].action=0xff; // to ensure our node status is updated correctly + system.node_list[bbs.node_num-1].action=0xff; // to ensure our node status is updated correctly - // After reading from the terminal, see if we need to pass that input to a control module, - // except if input is on the bottom line - log(LOG_DEBUG,'CONTROL: mode ['+mode+'] ('+control.length+')'); - if ((mode !== MODE_BL) && control.length) { - log(LOG_DEBUG,'CONTROL DEBUG: ['+control.length+'] ('+JSON.stringify(control)+')'); - cc = control[control.length-1]; - log(LOG_DEBUG,'CONTROL IS: ['+typeof cc+']'); - log(LOG_DEBUG,'CONTROL START: ['+read+'] ('+cc.getName+')'); - // We pass the read to the control and see if it consumes it. - read = cc.handle(read); - log(LOG_DEBUG,'CONTROL RETURN: ['+read+'] ('+cc.isComplete+')'); + // After reading from the terminal, see if we need to pass that input to a control module, + // except if input is on the bottom line + log(LOG_DEBUG,'CONTROL: mode ['+mode+'] ('+control.length+')'); + if ((mode !== MODE_BL) && control.length) { + log(LOG_DEBUG,'CONTROL DEBUG: ['+control.length+'] ('+JSON.stringify(control)+')'); + cc = control[control.length-1]; + log(LOG_DEBUG,'CONTROL IS: ['+typeof cc+']'); + log(LOG_DEBUG,'CONTROL START: ['+read+'] ('+cc.getName+')'); + // We pass the read to the control and see if it consumes it. + read = cc.handle(read); + log(LOG_DEBUG,'CONTROL RETURN: ['+read+'] ('+cc.isComplete+')'); - if (cc.isComplete) { - control.pop(); - cc = null; - log(LOG_DEBUG,'CONTROL COMPLETE: ['+read+'] ('+control.length+')'); + if (cc.isComplete) { + control.pop(); + cc = null; + log(LOG_DEBUG,'CONTROL COMPLETE: ['+read+'] ('+control.length+')'); + } + + log(LOG_DEBUG,'CONTROL END: ['+read+']'); } - log(LOG_DEBUG,'CONTROL END: ['+read+']'); - } + log(LOG_DEBUG,'MODE START: ['+read.charCodeAt(0)+']'); + switch (mode) { + // Normal navigation + case false: + log(LOG_DEBUG,'- MODE false: ['+read+']'); - log(LOG_DEBUG,'MODE START: ['+read.charCodeAt(0)+']'); - switch (mode) { - // Normal navigation - case false: - log(LOG_DEBUG,'- MODE false: ['+read+']'); + switch (read) { + case '*': action = ACTION_STAR; + break; - switch (read) { - case '*': action = ACTION_STAR; - break; + // Frame Routing + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + log(LOG_DEBUG,'- MODE false: Key ['+read+'] Route ['+fo.key[read]+']'); + if (fo.key[read] !== null) { + // If are requesting a home page + if (fo.key[read] === 0) { + next_page = user.number ? HOME_FRAME : LOGIN_FRAME; - // Frame Routing - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - log(LOG_DEBUG,'- MODE false: Key ['+read+'] Route ['+fo.key[read]+']'); - if (fo.key[read] !== null) { - // If are requesting a home page - if (fo.key[read] === 0) { - next_page = user.number ? HOME_FRAME : LOGIN_FRAME; + } else { + next_page = {frame: fo.key[read],index: 'a'}; + } + + action = ACTION_GOTO; + log(LOG_DEBUG,'- false: Key ['+read+'] ['+pageStr(next_page)+']'); } else { - next_page = {frame: fo.key[read],index: 'a'}; + fo.sendBaseline('ERR_ROUTE',false); } - action = ACTION_GOTO; - log(LOG_DEBUG,'- false: Key ['+read+'] ['+pageStr(next_page)+']'); + break; - } else { - fo.sendBaseline('ERR_ROUTE',false); - } + case '_': + // Viewdata terminal's # is an _ character + if (! viewdata) break; + /* fallthrough */ + case '#': + log(LOG_DEBUG,'- false: Key ['+read+'] ['+pageStr(fo)+']'); + if (fo.index !== 'z') { + next_page = {frame: fo.frame,index: String.fromCharCode(fo.index.charCodeAt(0)+1)}; + action = ACTION_GOTO; + } else { + fo.sendBaseline('ERR_ROUTE',false); + } + + break; + } + + break; + + // Command input on bottom line + case MODE_BL: + log(LOG_DEBUG,'- MODE_BL: ['+read+']'); + if (read.match(/[0-9]/)) { + cmd += read; + console.write(read); + } + + // If the user pressed backspace + // @todo We should get the user's configuration of backspace + if ((read === CTRL_H || read === KEY_DEL) && cmd.length) { + console.backspace(); + cmd = cmd.substring(0,cmd.length-1); + } + + if (cmd === '00') { + action = ACTION_RELOAD; + cmd = ''; + fo.cursorOff(); break; - - case '_': - // Viewdata terminal's # is an _ character - if (! viewdata) break; - /* fallthrough */ - case '#': - log(LOG_DEBUG,'- false: Key ['+read+'] ['+pageStr(fo)+']'); - if (fo.index !== 'z') { - next_page = {frame: fo.frame,index: String.fromCharCode(fo.index.charCodeAt(0)+1)}; - action = ACTION_GOTO; - - } else { - fo.sendBaseline('ERR_ROUTE',false); - } - - break; - } - - break; - - // Command input on bottom line - case MODE_BL: - log(LOG_DEBUG,'- MODE_BL: ['+read+']'); - if (read.match(/[0-9]/)) { - cmd += read; - console.write(read); - } - - // If the user pressed backspace - // @todo We should get the user's configuration of backspace - if ((read === CTRL_H || read === KEY_DEL) && cmd.length) { - console.backspace(); - cmd = cmd.substring(0,cmd.length-1); - } - - if (cmd === '00') { - action = ACTION_RELOAD; - cmd = ''; - fo.cursorOff(); - break; - } - - if (cmd === '01' && ! user.number) { - action = ACTION_GOTO; - next_page = SQRL_FRAME; - break; - } - - // Invalid system pages. - if (cmd.match(/^0[2367]/)) { - fo.cursorOff(); - fo.sendBaseline('ERR_ROUTE',false); - mode = action = false; - cmd = ''; - } - - // Edit specific frame - if (cmd.match(/^04/) && read.match(/[a-z]/)) { - // If we are not a user - if (! user.number) { - fo.cursorOff(); - fo.sendBaseline('ERR_ROUTE',false); - action = false; - - } else { - next_page = {frame: parseInt(cmd.substr(2,cmd.length-1)),index: read}; - fo.cursorOff(); - action = ACTION_EDIT; - - log(LOG_DEBUG,'- MODE_BL: EDIT ['+JSON.stringify(next_page)+']'); } - mode = false; - cmd = ''; - - break; - } - - // Bookmark frame - if (cmd === '05') { - if (! user.number) { - fo.cursorOff(); - fo.sendBaseline('ERR_ROUTE',false); - mode = action = false; - cmd = ''; - - } else { - // @todo - fo.cursorOff(); - fo.sendBaseline('ERR_NOT_IMPLEMENTED',false); - mode = action = false; - cmd = ''; - } - - break; - } - - // Report Problem - if (cmd === '08') { - if (! user.number) { - fo.cursorOff(); - fo.sendBaseline('ERR_ROUTE',false); - mode = action = false; - cmd = ''; - - } else { - // @todo - fo.cursorOff(); - fo.sendBaseline('ERR_NOT_IMPLEMENTED',false); - mode = action = false; - cmd = ''; - } - - break; - } - - // Reload frame - if (cmd === '09') { - fo.cursorOff(); - action = ACTION_GOTO; - cmd = ''; - next_page = {frame: fo.frame,index: fo.index}; - - break; - } - - // Another star aborts the command - if (read === '*') { - fo.clearBaseline(false); - fo.cursorOff(); - mode = action = false; - cmd = ''; - - if (cf) { - // If there is a control for this field, - if (cc) - cc.prefield(); - - mode = MODE_FIELD; - 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 = ''; - } - } - - if ((viewdata && read === '_') || (! viewdata && read === '#') || read === "\r") { - // Nothing typed between * and # - // *# means go back - if (cmd === '') { - fo.clearBaseline(false); - action = ACTION_BACKUP; - - } else if (cmd === '0') { - next_page = user.number ? HOME_FRAME : LOGIN_FRAME; + if (cmd === '01' && ! user.number) { action = ACTION_GOTO; + next_page = SQRL_FRAME; + break; + } - // Edit frame - } else if (cmd === '04') { + // Invalid system pages. + if (cmd.match(/^0[2367]/)) { + fo.cursorOff(); + fo.sendBaseline('ERR_ROUTE',false); + mode = action = false; + cmd = ''; + } + + // Edit specific frame + if (cmd.match(/^04/) && read.match(/[a-z]/)) { // If we are not a user if (! user.number) { + fo.cursorOff(); fo.sendBaseline('ERR_ROUTE',false); action = false; } else { + next_page = {frame: parseInt(cmd.substr(2,cmd.length-1)),index: read}; + fo.cursorOff(); action = ACTION_EDIT; + + log(LOG_DEBUG,'- MODE_BL: EDIT ['+JSON.stringify(next_page)+']'); } - } else { - next_page = {frame: parseInt(cmd),index: 'a'}; - action = ACTION_GOTO; + mode = false; + cmd = ''; + + break; } - // Clear the command we are finished processing... - fo.cursorOff(); - cmd = ''; - mode = false; - } + // Bookmark frame + if (cmd === '05') { + if (! user.number) { + fo.cursorOff(); + fo.sendBaseline('ERR_ROUTE',false); + mode = action = false; + cmd = ''; - break; + } else { + // @todo + fo.cursorOff(); + fo.sendBaseline('ERR_NOT_IMPLEMENTED',false); + mode = action = false; + cmd = ''; + } - // Key presses during field input. - case MODE_FIELD: - action = false; + break; + } - switch (fo.type) { - // Login frame. - case FRAME_TYPE_LOGIN: - switch (read) { - case '_': - if (! viewdata) break; - /* fallthrough */ - 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 (cf.ftype === 't' && cf.fvalue.toUpperCase() === 'NEW') { - action = ACTION_GOTO; - next_page = REGISTER_FRAME; + // Report Problem + if (cmd === '08') { + if (! user.number) { + fo.cursorOff(); + fo.sendBaseline('ERR_ROUTE',false); + mode = action = false; + cmd = ''; + + } else { + // @todo + fo.cursorOff(); + fo.sendBaseline('ERR_NOT_IMPLEMENTED',false); + mode = action = false; + cmd = ''; + } + + break; + } + + // Reload frame + if (cmd === '09') { + fo.cursorOff(); + action = ACTION_GOTO; + cmd = ''; + next_page = {frame: fo.frame,index: fo.index}; + + break; + } + + // Another star aborts the command + if (read === '*') { + fo.clearBaseline(false); + fo.cursorOff(); + mode = action = false; + cmd = ''; + + if (cf) { + // If there is a control for this field, + if (cc) + cc.prefield(); + + mode = MODE_FIELD; + 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 = ''; + } + } + + if ((viewdata && read === '_') || (! viewdata && read === '#') || read === "\r") { + // Nothing typed between * and # + // *# means go back + if (cmd === '') { + fo.clearBaseline(false); + action = ACTION_BACKUP; + + } else if (cmd === '0') { + next_page = user.number ? HOME_FRAME : LOGIN_FRAME; + action = ACTION_GOTO; + + // Edit frame + } else if (cmd === '04') { + // If we are not a user + if (! user.number) { + fo.sendBaseline('ERR_ROUTE',false); + action = false; + + } else { + action = ACTION_EDIT; + } + + } else { + next_page = {frame: parseInt(cmd),index: 'a'}; + action = ACTION_GOTO; + } + + // Clear the command we are finished processing... + fo.cursorOff(); + cmd = ''; + mode = false; + } + + break; + + // Key presses during field input. + case MODE_FIELD: + action = false; + + switch (fo.type) { + // Login frame. + case FRAME_TYPE_LOGIN: + switch (read) { + case '_': + if (! viewdata) break; + /* fallthrough */ + 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 (cf.ftype === 't' && cf.fvalue.toUpperCase() === 'NEW') { + action = ACTION_GOTO; + next_page = REGISTER_FRAME; + + break; + } break; - } + } + /* fallthrough */ + // 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; - } - /* fallthrough */ - // 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 '_': + if (! viewdata) break; + /* fallthrough */ + case '#': + case "\r": + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: # ['+read+']'); + // Next Field + fn++; - switch (read) { - // End of field entry. - case '_': - if (! viewdata) break; - /* fallthrough */ - case '#': - case "\r": - log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: # ['+read+']'); - // Next Field - fn++; + cf = fo.frame_fields[fn]; + log(LOG_DEBUG,'fn:'+fn+', cf'+JSON.stringify(cf)); - cf = fo.frame_fields[fn]; - log(LOG_DEBUG,'fn:'+fn+', cf'+JSON.stringify(cf)); + if (cf) { + // If there is a control for this field, + if (cc) + cc.prefield(); + + mode = MODE_FIELD; + fo.gotoxy(cf.c,cf.r); + fo.attr(cf.attribute); + + // Finished all editable fields. + } else { + action = ACTION_SUBMITRF; + } + + break; + + case '*': + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ['+read+']'); + + action = ACTION_STAR; + + break; + + // Delete Key pressed + case CTRL_H: + case KEY_DEL: + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: DEL ['+read+']'+' cf:'+(cf ? cf.fvalue.length : '{}')+' ct:'+cf.ftype); + + if (cf.fvalue.length > 0) { + cf.fvalue = cf.fvalue.substring(0,cf.fvalue.length-1); + fo.fieldbs(cf.fchar); + } + + break; + + case KEY_ESC: + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ESC ['+read+']'); + break; + + case KEY_DOWN: + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: DOWN ['+read+']'); + // Next Field + fn++; + + cf = fo.frame_fields[fn]; + log(LOG_DEBUG,'fn:'+fn+', cf'+JSON.stringify(cf)); + + if (! cf) { + fn = 0; + cf = fo.frame_fields[fn]; + } - if (cf) { // If there is a control for this field, if (cc) cc.prefield(); mode = MODE_FIELD; - fo.gotoxy(cf.c,cf.r); + fo.gotoxy(cf.c+cf.fvalue.length,cf.r); fo.attr(cf.attribute); - // Finished all editable fields. - } else { - action = ACTION_SUBMITRF; - } - - break; - - case '*': - log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ['+read+']'); - - action = ACTION_STAR; - - break; - - // Delete Key pressed - case CTRL_H: - case KEY_DEL: - log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: DEL ['+read+']'+' cf:'+(cf ? cf.fvalue.length : '{}')+' ct:'+cf.ftype); - - if (cf.fvalue.length > 0) { - cf.fvalue = cf.fvalue.substring(0,cf.fvalue.length-1); - fo.fieldbs(cf.fchar); - } - - break; - - case KEY_ESC: - log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ESC ['+read+']'); - break; - - case KEY_DOWN: - log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: DOWN ['+read+']'); - // Next Field - fn++; - - cf = fo.frame_fields[fn]; - log(LOG_DEBUG,'fn:'+fn+', cf'+JSON.stringify(cf)); - - if (! cf) { - fn = 0; - cf = fo.frame_fields[fn]; - } - - // If there is a control for this field, - if (cc) - cc.prefield(); - - mode = MODE_FIELD; - fo.gotoxy(cf.c+cf.fvalue.length,cf.r); - fo.attr(cf.attribute); - - break; - - case KEY_UP: - log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: UP ['+read+']'); - // Next Field - fn--; - - if (fn < 0) { - fn = fo.frame_fields.length-1; - } - - cf = fo.frame_fields[fn]; - log(LOG_DEBUG,'fn:'+fn+', cf'+JSON.stringify(cf)); - - // If there is a control for this field, - if (cc) - cc.prefield(); - - mode = MODE_FIELD; - fo.gotoxy(cf.c+cf.fvalue.length,cf.r); - fo.attr(cf.attribute); - - 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]/)) { - fo.sendBaseline('NOACTION',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)); - action = ACTION_GOTO; - next_page = LOGIN_FAILED_FRAME; break; + case KEY_UP: + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: UP ['+read+']'); + // Next Field + fn--; + + if (fn < 0) { + fn = fo.frame_fields.length-1; + } + + cf = fo.frame_fields[fn]; + log(LOG_DEBUG,'fn:'+fn+', cf'+JSON.stringify(cf)); + + // If there is a control for this field, + if (cc) + cc.prefield(); + + mode = MODE_FIELD; + fo.gotoxy(cf.c+cf.fvalue.length,cf.r); + fo.attr(cf.attribute); + + break; + + // Record Data Entry default: - // Its assumed that you get here after completing a form and you have pressed 1 to submit that form. - log(LOG_DEBUG,' ! EVAL method:'+JSON.stringify(fo.key)); - var x = cc.process(); - log(LOG_DEBUG,' = EVAL method:'+JSON.stringify(x)); - } - /* + log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ['+read+'] E:'+read.charCodeAt(0)+' cf:'+(cf ? cf.flength : '{}')); - } elseif ($ao = FrameClass\Action::factory($this->fo->route(1),$this,$user,$action,$mode)) { - $ao->handle(); - $mode = $ao->mode; - $action = $ao->action; + if (read.charCodeAt(0) > 31 && cf.fvalue.length < cf.flength) { + cf.fvalue += read; + console.write((cf.ftype === 't') ? read : 'x'); + } + } - if ($ao->page) - $next_page = $ao->page; + break; - } else { - fo.sendBaseline('ERR_METHOD_NOT_EXIST',false); + // Other Frame Types - Shouldnt get here. + default: + log(LOG_DEBUG,'- SHOULDNT GET HERE: ['+read+']'); + action = ACTION_TERMINATE; + } - mode = MODE_RFSENT; - } - */ - } + break; - 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])); - case '2': - log(LOG_DEBUG,'- MODE_SUBMITRF: Key ['+read+'] ['+pageStr(fo)+']'); - // @todo Check if HASH is a valid next destination + // 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])); - if (fo.type === 'l') { - action = ACTION_RELOAD; - mode = false; + control[control.length-1].process(); - } else { - fo.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 if (fo.key[1] === '*' || fo.key[1].match(/[0-9]/)) { + fo.sendBaseline('NOACTION',false); + mode = MODE_RFSENT; } else { - $mode = $save->state['mode']; - $action = $save->state['action']; - $control = FALSE; + 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)); + action = ACTION_GOTO; + next_page = LOGIN_FAILED_FRAME; + break; + + default: + // Its assumed that you get here after completing a form and you have pressed 1 to submit that form. + log(LOG_DEBUG,' ! EVAL method:'+JSON.stringify(fo.key)); + var x = cc.process(); + log(LOG_DEBUG,' = EVAL method:'+JSON.stringify(x)); + } + /* + + } 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 { + fo.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 { + fo.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; + } + + // Destroy the object. + cc = null; + + break; + + // Response form after Sent processing + case MODE_RFSENT: + fo.cursorOff(); + + 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: + fo.cursorOff(); + + if ((viewdata && read === '_') || (! viewdata && 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]; } */ - break; + action = ACTION_GOTO; - case '*': + } else if (read === '*') { action = ACTION_STAR; break; - } - - // Destroy the object. - cc = null; - - break; - - // Response form after Sent processing - case MODE_RFSENT: - fo.cursorOff(); - - 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: - fo.cursorOff(); - - if ((viewdata && read === '_') || (! viewdata && 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 - // @todo MODE_CONTROL + default: + log(LOG_DEBUG,'- SHOULDNT GET HERE: ['+read+']'); + action = ACTION_TERMINATE; + } + log(LOG_DEBUG,'MODE END: ['+read+']'); - default: - log(LOG_DEBUG,'- SHOULDNT GET HERE: ['+read+']'); - action = ACTION_TERMINATE; - } - log(LOG_DEBUG,'MODE END: ['+read+']'); + log(LOG_DEBUG,'ACTION START: ['+read+']'); + switch (action) { + // Start command entry + case ACTION_STAR: + log(LOG_DEBUG,'- ACTION_STAR: ['+(next_page ? pageStr(next_page) : '')+']'); - log(LOG_DEBUG,'ACTION START: ['+read+']'); - switch (action) { - // Start command entry - case ACTION_STAR: - log(LOG_DEBUG,'- ACTION_STAR: ['+(next_page ? pageStr(next_page) : '')+']'); + // @todo If something on the baseline preserve it - // @todo If something on the baseline preserve it + fo.cursorOn(0,24); + fo.sendBaseline('BASESTAR',true); + action = false; + mode = MODE_BL; - fo.cursorOn(0,24); - fo.sendBaseline('BASESTAR',true); - action = false; - mode = MODE_BL; + bbs.replace_text(NodeActionRetrieving,'\1h%s \1n\1gJumping to page'); + bbs.node_action=NODE_RFSD; - bbs.replace_text(NodeActionRetrieving,'\1h%s \1n\1gJumping to page'); - bbs.node_action=NODE_RFSD; + break; - break; - - // Submitting forms - case ACTION_SUBMITRF: - action = false; - fo.cursorOff(); - log(LOG_DEBUG,'- ACTION_SUBMITRF: ['+fo.type+']'); - fo.sendBaseline((fo.type === 'l' ? 'MSG_LOGON' : 'MSG_SENDORNOT'),true); - mode = MODE_SUBMITRF; - - break; - - // Edit a frame - case ACTION_EDIT: - log(LOG_DEBUG,'- ACTION_EDIT: ['+JSON.stringify(next_page)+']'); - - if ((fo.type === FRAME_TYPE_MESSAGE) || (! pageEditor(next_page ? next_page.frame : fo.frame))) { + // Submitting forms + case ACTION_SUBMITRF: + action = false; fo.cursorOff(); - fo.sendBaseline('ACCESS_DENIED',false); + log(LOG_DEBUG,'- ACTION_SUBMITRF: ['+fo.type+']'); + fo.sendBaseline((fo.type === 'l' ? 'MSG_LOGON' : 'MSG_SENDORNOT'),true); + mode = MODE_SUBMITRF; + + break; + + // Edit a frame + case ACTION_EDIT: + log(LOG_DEBUG,'- ACTION_EDIT: ['+JSON.stringify(next_page)+']'); + + if ((fo.type === FRAME_TYPE_MESSAGE) || (! pageEditor(next_page ? next_page.frame : fo.frame))) { + fo.cursorOff(); + fo.sendBaseline('ACCESS_DENIED',false); + action = false; + break; + } + + require('ansitex/load/control-frameedit.js','CONTROL_FRAMEEDIT'); + + // If we are editing a specific frame, attempt to load it + if (next_page) { + var current = fo; + fo = viewdata ? new FrameViewdata() : new FrameAnsi(); + fo.load(pageStr(next_page)); + + // If the frame doesnt exist, check that the parent frame exists in case we are creating a new one + if (fo.page === null) { + log(LOG_DEBUG,'- ACTION_EDIT: check index: '+next_page.index+' ('+String.fromCharCode(next_page.index.charCodeAt(0)-1)+')'); + + // We can always create an 'a' frame + if (next_page.index !== 'a') { + fo = viewdata ? new FrameViewdata() : new FrameAnsi(); + fo.load(pageStr({frame: next_page.frame, index: String.fromCharCode(next_page.index.charCodeAt(0)-1)})); + + log(LOG_DEBUG,'- ACTION_EDIT: check index: '+JSON.stringify(fo)+' ('+String.fromCharCode(next_page.index.charCodeAt(0)-1)+')'); + if (fo.page === null) { + fo = current; + // sendbaseline ERR_PAGE + fo.sendBaseline('ERR_NO_PARENT',false); + mode = action = false; + break; + } + } + + // New frame + fo = viewdata ? new FrameViewdata() : new FrameAnsi(); + fo.frame = next_page.frame; + fo.index = next_page.index; + fo.cost = 0; + fo.owner = base64_decode(pageOwner(pageStr(next_page)).logo); + fo.content = base64_encode('Start your new page...'); + } + } + + control.push(new edit(fo)); + + mode = false; action = false; break; - } - require('ansitex/load/control-frameedit.js','CONTROL_FRAMEEDIT'); + // GO Backwards + case ACTION_BACKUP: + log(LOG_DEBUG,'- ACTION_BACKUP: history size - '+history.length+' with ['+history.join('|')+']'); + // Do we have anywhere to go, drop the current page from the history + if (history.length > 1) + history.pop(); - // If we are editing a specific frame, attempt to load it - if (next_page) { - var current = fo; - fo = viewdata ? new FrameViewdata() : new FrameAnsi(); - fo.load(pageStr(next_page)); + // @todo If in control... - // If the frame doesnt exist, check that the parent frame exists in case we are creating a new one - if (fo.page === null) { - log(LOG_DEBUG,'- ACTION_EDIT: check index: '+next_page.index+' ('+String.fromCharCode(next_page.index.charCodeAt(0)-1)+')'); + next_page = (history.length > 0) ? history[history.length-1] : null; - // We can always create an 'a' frame - if (next_page.index !== 'a') { - fo = viewdata ? new FrameViewdata() : new FrameAnsi(); - fo.load(pageStr({frame: next_page.frame, index: String.fromCharCode(next_page.index.charCodeAt(0)-1)})); + log(LOG_DEBUG,'- ACTION_BACKUP: Backing up to ['+JSON.stringify(next_page)+'] current ['+fo.page+']'); - log(LOG_DEBUG,'- ACTION_EDIT: check index: '+JSON.stringify(fo)+' ('+String.fromCharCode(next_page.index.charCodeAt(0)-1)+')'); - if (fo.page === null) { - fo = current; - // sendbaseline ERR_PAGE - fo.sendBaseline('ERR_NO_PARENT',false); + // If there is no next page, we'll ignore the request. + if (! next_page || (pageStr(next_page) === fo.page)) { + action = false; + break; + } + + // Goto specific page + case ACTION_GOTO: + // Clear any controls + control = []; + + log(LOG_DEBUG,'- ACTION_GOTO: ['+(next_page ? pageStr(next_page) : '')+']'); + var current = null; + + // For logged in users, we'll see if this is a mail page. + if (user.number) { + // @todo consider how we do mail security. + + // Echoarea mail summary + if (/^1[0-9]{6}1$/.test(next_page.frame)) { + log(LOG_DEBUG,'- ACTION_GOTO - load echoarea summary: ['+next_page.frame+']'); + + to = viewdata ? new FrameViewdata() : new FrameAnsi(); + // @todo look for a template in the area or group first + to.load(MAIL_TEMPLATE_AREA_SUMMARY); + + var ma = new MsgAreas(); + var area = ma.getArea(next_page.frame); + + // If the template page doesnt exist + if ((! to.content) || (! area)) { + fo.sendBaseline('ERR_ROUTE',false); mode = action = false; break; } - } - // New frame - fo = viewdata ? new FrameViewdata() : new FrameAnsi(); - fo.frame = next_page.frame; - fo.index = next_page.index; - fo.cost = 0; - fo.owner = base64_decode(pageOwner(pageStr(next_page)).logo); - fo.content = base64_encode('Start your new page...'); - } - } + current = fo; - control.push(new edit(fo)); - - mode = false; - action = false; - break; - - // GO Backwards - case ACTION_BACKUP: - log(LOG_DEBUG,'- ACTION_BACKUP: history size - '+history.length+' with ['+history.join('|')+']'); - // Do we have anywhere to go, drop the current page from the history - if (history.length > 1) - history.pop(); - - // @todo If in control... - - next_page = (history.length > 0) ? history[history.length-1] : null; - - log(LOG_DEBUG,'- ACTION_BACKUP: Backing up to ['+JSON.stringify(next_page)+'] current ['+fo.page+']'); - - // If there is no next page, we'll ignore the request. - if (! next_page || (pageStr(next_page) === fo.page)) { - action = false; - break; - } - - // Goto specific page - case ACTION_GOTO: - // Clear any controls - control = []; - - log(LOG_DEBUG,'- ACTION_GOTO: ['+(next_page ? pageStr(next_page) : '')+']'); - var current = null; - - // For logged in users, we'll see if this is a mail page. - if (user.number) { - // @todo consider how we do mail security. - - // Echoarea mail summary - if (/^1[0-9]{6}1$/.test(next_page.frame)) { - log(LOG_DEBUG,'- ACTION_GOTO - load echoarea summary: ['+next_page.frame+']'); - - to = viewdata ? new FrameViewdata() : new FrameAnsi(); - // @todo look for a template in the area or group first - to.load(MAIL_TEMPLATE_AREA_SUMMARY); - - var ma = new MsgAreas(); - var area = ma.getArea(next_page.frame); - - // If the template page doesnt exist - if ((! to.content) || (! area)) { - fo.sendBaseline('ERR_ROUTE',false); - mode = action = false; - break; - } - - current = fo; - - fo = viewdata ? new FrameViewdata() : new FrameAnsi(); - fo.frame = next_page.frame; - fo.index = next_page.index; - fo.content = to.content; - fo.isPublic = true; - fo.isAccessible = to.isAccessible; - fo.owner = to.owner; - fo.type = to.type; - // Parent - fo.key[0] = (''+next_page.frame).substr(0,7); - - // First Unread - fo.key[1] = atcode('msg_area_msgunread_page',null,null,area); - - // First to me - fo.key[2] = atcode('msg_area_msgtome_page',null,null,area); - - // Oldest - fo.key[3] = atcode('msg_area_msgoldest_page',null,null,area); - // Newest - fo.key[4] = atcode('msg_area_msgnewest_page',null,null,area); - - next_page = null; - - // 1zzzzEEnnnn - get a message - } else if (/^1[0-9]{10}/.test(next_page.frame)) { - log(LOG_DEBUG,'- ACTION_GOTO - load message: ['+next_page.frame+']'); - - if (next_page.index === 'a') { - require('ansitex/load/control-echomail.js','CONTROL_ECHOMAIL'); - control.push(new echomail(next_page.frame)); - action = false; - next_page = null; - log(LOG_DEBUG,'- ACTION_GOTO - control message: ['+JSON.stringify(control[control.length-1])+'] ('+control.length+')'); - - if (! control[control.length-1].ready()) { - log(LOG_DEBUG,'- ACTION_GOTO - control not ready aborting...'); - control.pop(); - mode = false; - - fo.sendBaseline('ERR_ROUTE',false); - break; - } - - // @todo - Show message stats - } else if (next_page.index === 'b') { - action = mode = false; - next_page = null; - - fo.sendBaseline('ERR_NOT_IMPLEMENTED',false); - break; - - } else { - mode = action = false; - next_page = null; - - fo.sendBaseline('ERR_ROUTE',false); - break; - } - } - } - - if (next_page !== null) { - current = fo; - fo = viewdata ? new FrameViewdata() : new FrameAnsi(); - fo.load(pageStr(next_page)); - - if (fo.page === null) { - fo = current; - - // In case the frame doesnt exist - if (fo === null) fo = viewdata ? new FrameViewdata() : new FrameAnsi(); + fo.frame = next_page.frame; + fo.index = next_page.index; + fo.content = to.content; + fo.isPublic = true; + fo.isAccessible = to.isAccessible; + fo.owner = to.owner; + fo.type = to.type; + // Parent + fo.key[0] = (''+next_page.frame).substr(0,7); - // sendbaseline ERR_PAGE - fo.sendBaseline('ERR_ROUTE',false); - mode = action = false; - break; - } + // First Unread + fo.key[1] = atcode('msg_area_msgunread_page',null,null,area); - next_page = null; - } + // First to me + fo.key[2] = atcode('msg_area_msgtome_page',null,null,area); - // If the user has access to the frame - if (fo.accessible) { - if (fo.isMember && fo.type === FRAME_TYPE_LOGIN) { - fo.sendBaseline('ALREADY_MEMBER',false); - mode = action = false; - break; - } + // Oldest + fo.key[3] = atcode('msg_area_msgoldest_page',null,null,area); + // Newest + fo.key[4] = atcode('msg_area_msgnewest_page',null,null,area); - // Check if the frame exists, and the user is the Service Provider - } else { - fo.sendBaseline('ACCESS_DENIED',false); - mode = action = false; - // Reset the current frame to what it was. - fo = current; - break; - } + next_page = null; - log(LOG_DEBUG,'- ACTION_GOTO: next_page ['+JSON.stringify(next_page)+'] last history ['+JSON.stringify(history[history.length-1])+']'); + // 1zzzzEEnnnn - get a message + } else if (/^1[0-9]{10}/.test(next_page.frame)) { + log(LOG_DEBUG,'- ACTION_GOTO - load message: ['+next_page.frame+']'); - // Record our history - if ((! history.length || (pageStr(history[history.length-1]) !== fo.page)) && (fo.type !== FRAME_TYPE_LOGIN)) { - // Ignore the login frames - if (NO_HISTORY_FRAMES.indexOf(fo.page) === -1) { - history.push({frame:fo.frame,index:fo.index}); - log(LOG_DEBUG,'- ACTION_GOTO: Added to history ['+fo.page+'] now ['+history.length+']'); - } - } + if (next_page.index === 'a') { + require('ansitex/load/control-echomail.js','CONTROL_ECHOMAIL'); + control.push(new echomail(next_page.frame)); + action = false; + next_page = null; + log(LOG_DEBUG,'- ACTION_GOTO - control message: ['+JSON.stringify(control[control.length-1])+'] ('+control.length+')'); - // Load frame - case ACTION_RELOAD: - log(LOG_DEBUG,'- ACTION_RELOAD: ['+(next_page ? pageStr(next_page) : '')+']'); + if (! control[control.length-1].ready()) { + log(LOG_DEBUG,'- ACTION_GOTO - control not ready aborting...'); + control.pop(); + mode = false; - console.line_counter = 0; // @todo fix to suppress a pause that is occurring before clear() - fo.cursorOff(); - - bbs.replace_text(NodeActionMain,'\1h%s \1nViewing \1h*'+fo.frame+'#\1n ['+fo.index+']'); - bbs.log_str(fo.page+'|'); - bbs.node_action=NODE_MAIN; - - switch(fo.type) { - // Terminate frame - case FRAME_TYPE_MAIL_TEMPLATE: - log(LOG_DEBUG,'- MAIL_TEMPLATE: ['+fo.frame+']'); - fo.render(ma.getArea(fo.frame)); - mode = false; - action = false; - - break; - - // Terminate frame - case FRAME_TYPE_TERMINATE: - fo.render(); - mode = false; - action = ACTION_TERMINATE; - - break; - - // External Frame - // @todo returning from the frame, go to the 0 key if it is set - case FRAME_TYPE_EXTERNAL: - var content = base64_decode(fo.content); - log(LOG_DEBUG,'- ACTION_GOTO: EXTERNAL ['+JSON.stringify(content)+']'); - - switch(content.replace(/\n/,'')) { - case 'bbs.user_config()': - case 'bbs.read_mail(MAIL_YOUR)': - case 'bbs.scan_subs(SCAN_NEW)': - case 'bbs.scan_posts()': - case 'bbs.post_msg()': - eval(content); - - // Check and see if our shell was changed - if (user.command_shell !== 'ansitex') { - exit(); + fo.sendBaseline('ERR_ROUTE',false); + break; } - action = ACTION_BACKUP; + // @todo - Show message stats + } else if (next_page.index === 'b') { + action = mode = false; + next_page = null; + + fo.sendBaseline('ERR_NOT_IMPLEMENTED',false); break; - default: - console.putmsg(JSON.stringify(content)); + } else { + mode = action = false; + next_page = null; + fo.sendBaseline('ERR_ROUTE',false); - action = false; break; + } + } + } + + if (next_page !== null) { + current = fo; + fo = viewdata ? new FrameViewdata() : new FrameAnsi(); + fo.load(pageStr(next_page)); + + if (fo.page === null) { + fo = current; + + // In case the frame doesnt exist + if (fo === null) + fo = viewdata ? new FrameViewdata() : new FrameAnsi(); + + // sendbaseline ERR_PAGE + fo.sendBaseline('ERR_ROUTE',false); + mode = action = false; + break; } - mode = false; + next_page = null; + } + + // If the user has access to the frame + if (fo.accessible) { + if (fo.isMember && fo.type === FRAME_TYPE_LOGIN) { + fo.sendBaseline('ALREADY_MEMBER',false); + mode = action = false; + break; + } + + // Check if the frame exists, and the user is the Service Provider + } else { + fo.sendBaseline('ACCESS_DENIED',false); + mode = action = false; + // Reset the current frame to what it was. + fo = current; break; + } - case FRAME_TYPE_LOGIN: - action = false; - /* fallthrough */ + log(LOG_DEBUG,'- ACTION_GOTO: next_page ['+JSON.stringify(next_page)+'] last history ['+JSON.stringify(history[history.length-1])+']'); - case FRAME_TYPE_RESPONSE: - fn = 0; - cf = null; - fo.render(); + // Record our history + if ((! history.length || (pageStr(history[history.length-1]) !== fo.page)) && (fo.type !== FRAME_TYPE_LOGIN)) { + // Ignore the login frames + if (NO_HISTORY_FRAMES.indexOf(fo.page) === -1) { + history.push({frame:fo.frame,index:fo.index}); + log(LOG_DEBUG,'- ACTION_GOTO: Added to history ['+fo.page+'] now ['+history.length+']'); + } + } - if (fo.frame_fields.length) { - cf = fo.frame_fields[fn]; - log(LOG_DEBUG,'cf'+JSON.stringify(cf)); + // Load frame + case ACTION_RELOAD: + log(LOG_DEBUG,'- ACTION_RELOAD: ['+(next_page ? pageStr(next_page) : '')+']'); - if (cf) { - mode = MODE_FIELD; - fo.cursorOn(cf.c,cf.r); - fo.attr(cf.attribute); + console.line_counter = 0; // @todo fix to suppress a pause that is occurring before clear() + fo.cursorOff(); - // There were no editable fields. - } else { - mode = MODE_COMPLETE; - fo.cursorOff(); + bbs.replace_text(NodeActionMain,'\1h%s \1nViewing \1h*'+fo.frame+'#\1n ['+fo.index+']'); + bbs.log_str(fo.page+'|'); + bbs.node_action=NODE_MAIN; + + switch(fo.type) { + // Terminate frame + case FRAME_TYPE_MAIL_TEMPLATE: + log(LOG_DEBUG,'- MAIL_TEMPLATE: ['+fo.frame+']'); + fo.render(ma.getArea(fo.frame)); + mode = false; + action = false; + + break; + + // Terminate frame + case FRAME_TYPE_TERMINATE: + fo.render(); + mode = false; + action = ACTION_TERMINATE; + + break; + + // External Frame + // @todo returning from the frame, go to the 0 key if it is set + case FRAME_TYPE_EXTERNAL: + var content = base64_decode(fo.content); + log(LOG_DEBUG,'- ACTION_GOTO: EXTERNAL ['+JSON.stringify(content)+']'); + + switch(content.replace(/\n/,'')) { + case 'bbs.user_config()': + case 'bbs.read_mail(MAIL_YOUR)': + case 'bbs.scan_subs(SCAN_NEW)': + case 'bbs.scan_posts()': + case 'bbs.post_msg()': + eval(content); + + // Check and see if our shell was changed + if (user.command_shell !== 'ansitex') { + exit(); + } + + action = ACTION_BACKUP; + break; + + default: + console.putmsg(JSON.stringify(content)); + fo.sendBaseline('ERR_ROUTE',false); + action = false; + break; } - } else { mode = false; - } + break; - // If this is the register page - if (fo.page === pageStr(REGISTER_FRAME)) { - log(LOG_DEBUG,'Adding REGISTER to control stack'); - require('ansitex/load/control-'+fo.key[1]+'.js','CONTROL_REGISTER'); - control.push(eval('new '+fo.key[1]+'();')); + case FRAME_TYPE_LOGIN: + action = false; + /* fallthrough */ - } else if (fo.page === pageStr(SQRL_FRAME)) { - log(LOG_DEBUG,'Adding SQRL to control stack'); - require('ansitex/load/control-'+fo.key[1]+'.js','CONTROL_SQRL'); - control.push(eval('new '+fo.key[1]+'();')); + case FRAME_TYPE_RESPONSE: + fn = 0; + cf = null; + fo.render(); - } else if (fo.key[1] && (fo.type === FRAME_TYPE_RESPONSE) && (typeof(fo.key[1]) !== 'number')) { - log(LOG_DEBUG,'Adding METHOD to control stack: '+fo.key[1]); - require('ansitex/load/control-'+fo.key[1]+'.js','CONTROL_'+fo.key[1].toUpperCase()); - control.push(eval('new '+fo.key[1]+'();')); - } + if (fo.frame_fields.length) { + cf = fo.frame_fields[fn]; + log(LOG_DEBUG,'cf'+JSON.stringify(cf)); - action = false; + if (cf) { + mode = MODE_FIELD; + fo.cursorOn(cf.c,cf.r); + fo.attr(cf.attribute); - break; + // There were no editable fields. + } else { + mode = MODE_COMPLETE; + fo.cursorOff(); + } - // Standard Frame - case FRAME_TYPE_INFO: - default: - fo.render(); - mode = action = false; - break; + } else { + mode = false; + } - // Active frame - } + // If this is the register page + if (fo.page === pageStr(REGISTER_FRAME)) { + log(LOG_DEBUG,'Adding REGISTER to control stack'); + require('ansitex/load/control-'+fo.key[1]+'.js','CONTROL_REGISTER'); + control.push(eval('new '+fo.key[1]+'();')); - break; + } else if (fo.page === pageStr(SQRL_FRAME)) { + log(LOG_DEBUG,'Adding SQRL to control stack'); + require('ansitex/load/control-'+fo.key[1]+'.js','CONTROL_SQRL'); + control.push(eval('new '+fo.key[1]+'();')); + + } else if (fo.key[1] && (fo.type === FRAME_TYPE_RESPONSE) && (typeof(fo.key[1]) !== 'number')) { + log(LOG_DEBUG,'Adding METHOD to control stack: '+fo.key[1]); + require('ansitex/load/control-'+fo.key[1]+'.js','CONTROL_'+fo.key[1].toUpperCase()); + control.push(eval('new '+fo.key[1]+'();')); + } + + action = false; + + break; + + // Standard Frame + case FRAME_TYPE_INFO: + default: + fo.render(); + mode = action = false; + break; + + // Active frame + } + + break; + } + log(LOG_DEBUG,'ACTION END: ['+read+']'); + + } catch (e) { + log(LOG_ERROR,JSON.stringify(e)); + fo.sendBaseline('SYS_ERROR',false); + mode = action = false; } - log(LOG_DEBUG,'ACTION END: ['+read+']'); } log(LOG_DEBUG,'- FINISHED');