2020-05-27 11:56:12 +00:00
|
|
|
log(LOG_DEBUG,'- INIT: ANSITEX');
|
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
// Load many SBBS definitions
|
2020-05-27 11:56:12 +00:00
|
|
|
require('sbbsdefs.js','SS_UNUSED');
|
|
|
|
// Load text.dat definitions
|
|
|
|
require('text.js','TOTAL_TEXT');
|
2020-03-27 13:55:42 +00:00
|
|
|
// Key definitions
|
2020-05-27 11:56:12 +00:00
|
|
|
require('key_defs.js','KEY_ESC');
|
|
|
|
|
2020-03-26 06:22:46 +00:00
|
|
|
ansi = load({},'ansiterm_lib.js');
|
2020-05-27 11:56:12 +00:00
|
|
|
load('ansitex/load/funcs.js');
|
2019-10-03 04:08:48 +00:00
|
|
|
|
|
|
|
// Ansitex specific includes
|
2020-05-27 11:56:12 +00:00
|
|
|
require('ansitex/load/defs.js','ACTION_EXIT');
|
2019-10-03 04:08:48 +00:00
|
|
|
|
2020-05-28 13:30:44 +00:00
|
|
|
// @TODO LIST
|
|
|
|
// login screen - backspace not working
|
|
|
|
// login screen ** to clear the current field not working
|
|
|
|
// Returning from chat should refresh the frame
|
|
|
|
// Supress displays of telegrams
|
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
while(bbs.online) {
|
2019-10-08 23:22:38 +00:00
|
|
|
var mode = false; // Initial mode
|
2020-05-27 11:56:12 +00:00
|
|
|
|
|
|
|
// If the user is already on, our start page is 98b
|
2020-07-06 12:55:58 +00:00
|
|
|
var next_page = user.number ? { frame: 98,index: 'b' } : { frame: 980,index: 'a' }; // Start Frame
|
2020-05-27 11:56:12 +00:00
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
var action = ACTION_GOTO; // Initial action
|
2020-07-09 13:12:17 +00:00
|
|
|
var inkey_timeout = 60000; // Timeout waiting for input
|
2019-10-15 10:48:16 +00:00
|
|
|
var fo = null; // Current Frame
|
2020-05-27 11:56:12 +00:00
|
|
|
var fn = null; // Current Field Number for an Input Frame
|
2020-07-21 11:56:57 +00:00
|
|
|
var fe = null; // Frame to edit
|
2019-10-17 13:27:51 +00:00
|
|
|
var history = []; // Page history
|
2020-05-27 11:56:12 +00:00
|
|
|
|
2020-07-06 12:55:58 +00:00
|
|
|
var cf = null; // Current Input Field
|
|
|
|
var cc = null; // Current Control Method
|
|
|
|
|
2020-07-17 14:36:49 +00:00
|
|
|
var timeout = false; // Track our inactivity timeout
|
|
|
|
var timer = time();
|
2020-05-27 11:56:12 +00:00
|
|
|
var control = []; // Methods that need to process input
|
|
|
|
|
2020-03-26 06:22:46 +00:00
|
|
|
ansi.send('ext_mode','clear','cursor');
|
2019-10-03 04:08:48 +00:00
|
|
|
|
2020-05-27 11:56:12 +00:00
|
|
|
while (action != ACTION_TERMINATE && action !=ACTION_EXIT) {
|
2019-10-15 10:48:16 +00:00
|
|
|
bbs.nodesync(false); // @todo Stop the display of telegrams
|
2019-10-27 01:04:22 +00:00
|
|
|
read = '';
|
2020-05-27 11:56:12 +00:00
|
|
|
|
|
|
|
// If we have no action, read from the terminal
|
2019-10-27 01:04:22 +00:00
|
|
|
if (action == false) {
|
|
|
|
read = console.inkey(K_NONE,inkey_timeout);
|
2020-07-09 13:12:17 +00:00
|
|
|
|
2020-07-17 14:36:49 +00:00
|
|
|
if (read == '' && ! (user.security.exemptions&UFLAG_H) ) {
|
|
|
|
if (time() > timer+inkey_timeout/1000) {
|
|
|
|
sendBaseline(INACTIVE,false);
|
|
|
|
bbs.hangup();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
timeout = true;
|
|
|
|
sendBaseline(INACTIVITY,false);
|
|
|
|
|
|
|
|
if (cf)
|
|
|
|
console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m');
|
|
|
|
}
|
2020-07-09 13:12:17 +00:00
|
|
|
|
|
|
|
} else {
|
2020-07-17 14:36:49 +00:00
|
|
|
if (timeout) {
|
|
|
|
sendBaseline('',false);
|
2020-07-09 13:12:17 +00:00
|
|
|
|
2020-07-17 14:36:49 +00:00
|
|
|
if (cf)
|
|
|
|
console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m');
|
|
|
|
}
|
2020-07-09 13:12:17 +00:00
|
|
|
|
2020-07-17 14:36:49 +00:00
|
|
|
timer = time();
|
|
|
|
timeout = false;
|
2020-07-09 13:12:17 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-17 14:36:49 +00:00
|
|
|
log(LOG_DEBUG,'READ: ['+read+'] ('+read.charCodeAt(0)+')');
|
2020-05-27 11:56:12 +00:00
|
|
|
|
|
|
|
system.node_list[bbs.node_num-1].action=0xff; // to ensure our node status is updated correctly
|
2019-10-03 04:08:48 +00:00
|
|
|
|
2020-07-06 12:55:58 +00:00
|
|
|
if (mode != MODE_BL && control.length) {
|
|
|
|
cc = control[control.length-1];
|
2020-07-09 13:12:17 +00:00
|
|
|
log(LOG_DEBUG,'CONTROL START: ['+read+'] ('+cc.getName+')');
|
2020-07-06 12:55:58 +00:00
|
|
|
read = cc.handle(read);
|
2020-07-09 13:12:17 +00:00
|
|
|
log(LOG_DEBUG,'CONTROL RETURN: ['+read+'] ('+cc.isComplete+')');
|
|
|
|
|
|
|
|
if (cc.isComplete) {
|
2020-07-13 13:08:37 +00:00
|
|
|
control.pop();
|
2020-07-09 13:12:17 +00:00
|
|
|
log(LOG_DEBUG,'CONTROL COMPLETE: ['+read+'] ('+control.length+')');
|
2020-07-13 13:08:37 +00:00
|
|
|
cc = null;
|
2020-07-09 13:12:17 +00:00
|
|
|
}
|
2020-07-06 12:55:58 +00:00
|
|
|
|
|
|
|
log(LOG_DEBUG,'CONTROL END: ['+read+']');
|
|
|
|
}
|
|
|
|
|
2020-07-09 13:12:17 +00:00
|
|
|
log(LOG_DEBUG,'MODE START: ['+read.charCodeAt(0)+']');
|
2019-10-03 04:08:48 +00:00
|
|
|
switch (mode) {
|
|
|
|
case false:
|
|
|
|
log(LOG_DEBUG,'- false: ['+read+']');
|
|
|
|
cmd='';
|
|
|
|
|
|
|
|
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':
|
2020-07-06 12:55:58 +00:00
|
|
|
log(LOG_DEBUG,'- 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 = { frame: user.number ? 1 : 98,index: 'a' };
|
|
|
|
|
|
|
|
} else {
|
|
|
|
next_page = { frame: fo.key[read] };
|
|
|
|
}
|
2019-10-03 04:08:48 +00:00
|
|
|
action = ACTION_GOTO;
|
|
|
|
log(LOG_DEBUG,'- false: Key ['+read+'] ['+pageStr(next_page)+']');
|
|
|
|
|
|
|
|
} else {
|
|
|
|
sendBaseline(ERR_ROUTE,false);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2019-10-07 12:15:28 +00:00
|
|
|
|
|
|
|
case '#':
|
2020-03-27 13:55:42 +00:00
|
|
|
log(LOG_DEBUG,'- false: Key ['+read+'] ['+pageStr(fo)+']');
|
|
|
|
if (fo.index !== 'z') {
|
2019-10-07 12:15:28 +00:00
|
|
|
next_page = { frame: fo.frame, index: String.fromCharCode(fo.index.charCodeAt(0)+1) };
|
|
|
|
action = ACTION_GOTO;
|
2019-10-08 23:22:38 +00:00
|
|
|
|
2019-10-07 12:15:28 +00:00
|
|
|
} else {
|
|
|
|
sendBaseline(ERR_ROUTE,false);
|
|
|
|
}
|
|
|
|
break;
|
2019-10-03 04:08:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// @todo check if CTRL_H is required?
|
|
|
|
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 = '';
|
|
|
|
cursorOff();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-07-21 11:56:57 +00:00
|
|
|
// Invalid system pages.
|
|
|
|
if (cmd.match(/^0[2367]/)) {
|
|
|
|
cursorOff();
|
|
|
|
sendBaseline(ERR_ROUTE, false);
|
|
|
|
mode = action = false;
|
|
|
|
cmd = '';
|
|
|
|
}
|
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
// Edit specific frame
|
|
|
|
if (cmd.match(/^04/) && read.match(/[a-z]/)) {
|
2020-07-21 11:56:57 +00:00
|
|
|
var page = cmd.substr(2,cmd.length-1);
|
|
|
|
|
|
|
|
// If we are not a user
|
|
|
|
if (! user.number) {
|
|
|
|
cursorOff();
|
|
|
|
sendBaseline(ERR_ROUTE,false);
|
|
|
|
action = false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
fe = { frame: page, index: read };
|
|
|
|
cursorOff();
|
|
|
|
action = ACTION_EDIT;
|
|
|
|
|
|
|
|
log(LOG_DEBUG,'- MODE_BL: EDIT ['+JSON.stringify(fe)+']');
|
|
|
|
}
|
|
|
|
|
|
|
|
mode = false;
|
2019-10-03 04:08:48 +00:00
|
|
|
cmd = '';
|
2020-07-21 11:56:57 +00:00
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bookmark frame
|
|
|
|
if (cmd == '05') {
|
2020-07-21 11:56:57 +00:00
|
|
|
if (! user.number) {
|
|
|
|
cursorOff();
|
|
|
|
sendBaseline(ERR_ROUTE, false);
|
|
|
|
mode = action = false;
|
|
|
|
cmd = '';
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// @todo
|
|
|
|
cursorOff();
|
|
|
|
sendBaseline(ERR_NOT_IMPLEMENTED,false);
|
|
|
|
mode = action = false;
|
|
|
|
cmd = '';
|
|
|
|
}
|
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Report Problem
|
|
|
|
if (cmd == '08') {
|
2020-07-21 11:56:57 +00:00
|
|
|
if (! user.number) {
|
|
|
|
cursorOff();
|
|
|
|
sendBaseline(ERR_ROUTE, false);
|
|
|
|
mode = action = false;
|
|
|
|
cmd = '';
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// @todo
|
|
|
|
cursorOff();
|
|
|
|
sendBaseline(ERR_NOT_IMPLEMENTED,false);
|
|
|
|
mode = action = false;
|
|
|
|
cmd = '';
|
|
|
|
}
|
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reload frame
|
|
|
|
if (cmd == '09') {
|
2020-07-21 11:56:57 +00:00
|
|
|
cursorOff();
|
2019-10-03 04:08:48 +00:00
|
|
|
action = ACTION_GOTO;
|
|
|
|
cmd = '';
|
|
|
|
next_page = { frame: fo.frame, index: fo.index};
|
2020-07-21 11:56:57 +00:00
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Another star aborts the command
|
|
|
|
if (read == '*') {
|
|
|
|
sendBaseline('',false);
|
|
|
|
cursorOff();
|
2020-07-21 11:56:57 +00:00
|
|
|
mode = action = false;
|
|
|
|
cmd = '';
|
2019-10-03 04:08:48 +00:00
|
|
|
|
2020-07-06 12:55:58 +00:00
|
|
|
if (cf) {
|
|
|
|
// If there is a control for this field,
|
|
|
|
if (cc)
|
|
|
|
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');
|
|
|
|
console.write(cf.fchar.repeat(cf.fvalue.length));
|
|
|
|
console.gotoxy(cf.c,cf.r);
|
|
|
|
ansi.send('ext_mode','set','cursor');
|
|
|
|
cf.fvalue = '';
|
|
|
|
}
|
2019-10-03 04:08:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (read == '#' || read == '\r') {
|
|
|
|
// Nothing typed between * and #
|
|
|
|
// *# means go back
|
|
|
|
if (cmd == '') {
|
2019-10-17 13:27:51 +00:00
|
|
|
sendBaseline('',false);
|
|
|
|
action = ACTION_BACKUP;
|
2019-10-03 04:08:48 +00:00
|
|
|
|
|
|
|
} else if (cmd == '0') {
|
2020-07-06 12:55:58 +00:00
|
|
|
next_page = { frame: user.number ? 1 : 98,index: 'a' }; // @todo specify home page in config
|
2019-10-03 04:08:48 +00:00
|
|
|
action = ACTION_GOTO;
|
|
|
|
|
|
|
|
// Edit frame
|
|
|
|
} else if (cmd == '04') {
|
2020-07-21 11:56:57 +00:00
|
|
|
// If we are not a user
|
|
|
|
if (! user.number) {
|
|
|
|
sendBaseline(ERR_ROUTE,false);
|
|
|
|
action = false;
|
2020-07-13 13:08:37 +00:00
|
|
|
|
2020-07-21 11:56:57 +00:00
|
|
|
} else {
|
|
|
|
action = ACTION_EDIT;
|
|
|
|
}
|
2019-10-03 04:08:48 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
next_page = { frame: cmd };
|
|
|
|
action = ACTION_GOTO;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear the command we are finished processing...
|
|
|
|
cursorOff();
|
|
|
|
cmd = '';
|
|
|
|
mode = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2020-05-27 11:56:12 +00:00
|
|
|
// 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
|
2020-07-06 12:55:58 +00:00
|
|
|
// @todo Need to make sure this is only actioned on user login
|
|
|
|
if (cf.ftype == 't' && cf.fvalue.toUpperCase() == 'NEW') {
|
|
|
|
action = ACTION_GOTO;
|
|
|
|
next_page = { frame: 981,index: 'a' }; // @todo This should be in the INI.
|
2020-05-27 11:56:12 +00:00
|
|
|
|
2020-07-06 12:55:58 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-05-27 11:56:12 +00:00
|
|
|
|
|
|
|
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':
|
2020-07-09 13:12:17 +00:00
|
|
|
log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: # ['+read+']');
|
2020-05-27 11:56:12 +00:00
|
|
|
// Next Field
|
|
|
|
fn++;
|
|
|
|
|
|
|
|
cf = fo.frame_fields[fn];
|
|
|
|
log(LOG_DEBUG,'fn:'+fn+', cf'+JSON.stringify(cf));
|
|
|
|
|
|
|
|
if (cf) {
|
2020-07-06 12:55:58 +00:00
|
|
|
// If there is a control for this field,
|
|
|
|
if (cc)
|
|
|
|
cc.prefield();
|
|
|
|
|
2020-05-27 11:56:12 +00:00
|
|
|
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 '*':
|
2020-07-05 12:02:06 +00:00
|
|
|
log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: ['+read+']');
|
2020-05-27 11:56:12 +00:00
|
|
|
|
|
|
|
//$current['prevmode'] = MODE_FIELD;
|
|
|
|
action = ACTION_STAR;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2020-07-05 12:02:06 +00:00
|
|
|
// Delete Key pressed
|
|
|
|
case CTRL_H:
|
2020-07-09 13:12:17 +00:00
|
|
|
log(LOG_DEBUG,'- MODE_FIELD:FRAME_TYPE_RESPONSE: DEL ['+read+']'+' cf:'+(cf ? cf.fvalue.length : '{}')+' ct:'+cf.ftype);
|
2020-05-27 11:56:12 +00:00
|
|
|
|
2020-07-05 12:02:06 +00:00
|
|
|
if (cf.fvalue.length > 0) {
|
|
|
|
cf.fvalue = cf.fvalue.substring(0,cf.fvalue.length-1);
|
|
|
|
console.write(KEY_ESC+'[D'+cf.fchar+KEY_ESC+'[D');
|
|
|
|
}
|
2020-05-27 11:56:12 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_ESC:
|
2020-07-09 13:12:17 +00:00
|
|
|
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;
|
|
|
|
console.gotoxy(cf.c+cf.fvalue.length,cf.r);
|
|
|
|
console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m');
|
|
|
|
|
|
|
|
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;
|
|
|
|
console.gotoxy(cf.c+cf.fvalue.length,cf.r);
|
|
|
|
console.write(KEY_ESC+'['+cf.attribute.i+';'+cf.attribute.f+';'+cf.attribute.b+'m');
|
|
|
|
|
2020-05-27 11:56:12 +00:00
|
|
|
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;
|
2020-07-09 13:12:17 +00:00
|
|
|
|
|
|
|
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));
|
|
|
|
x = cc.process();
|
|
|
|
log(LOG_DEBUG,' = EVAL method:'+JSON.stringify(x));
|
2020-05-27 11:56:12 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
2020-07-09 13:12:17 +00:00
|
|
|
// Destroy the object.
|
|
|
|
cc = null;
|
|
|
|
|
2020-05-27 11:56:12 +00:00
|
|
|
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
|
2019-10-03 04:08:48 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
log(LOG_DEBUG,'- SHOULDNT GET HERE: ['+read+']');
|
2020-05-27 11:56:12 +00:00
|
|
|
action = ACTION_TERMINATE;
|
2019-10-03 04:08:48 +00:00
|
|
|
}
|
|
|
|
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) : '')+']');
|
|
|
|
|
|
|
|
// @todo If something on the baseline preserve it
|
|
|
|
|
2020-03-26 06:22:46 +00:00
|
|
|
ansi.send('ext_mode','set','cursor');
|
2019-10-03 04:08:48 +00:00
|
|
|
sendBaseline('\1N\1G\1H*',true);
|
|
|
|
action = false;
|
|
|
|
mode = MODE_BL;
|
|
|
|
|
|
|
|
bbs.replace_text(NodeActionRetrieving,'\1h%s \1n\1gJumping to page');
|
|
|
|
bbs.node_action=NODE_RFSD;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2020-05-27 11:56:12 +00:00
|
|
|
// 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;
|
|
|
|
|
2019-10-17 13:27:51 +00:00
|
|
|
// GO Backwards
|
|
|
|
case ACTION_BACKUP:
|
|
|
|
// 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 ['+(next_page ? pageStr(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;
|
|
|
|
}
|
|
|
|
|
2020-07-21 11:56:57 +00:00
|
|
|
// Edit a frame
|
|
|
|
case ACTION_EDIT:
|
|
|
|
log(LOG_DEBUG,'- ACTION_EDIT: ['+JSON.stringify(fe)+']');
|
|
|
|
|
|
|
|
if (! pageEditor(fe ? fe.frame : fo.frame)) {
|
|
|
|
cursorOff();
|
|
|
|
sendBaseline(ACCESS_DENIED,false);
|
|
|
|
action = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
require('ansitex/load/edit.js','CONTROL_EDIT');
|
|
|
|
|
|
|
|
// @todo validate that the user is authorised to edit it.
|
|
|
|
// If we are editing a specific frame, attempt to load it
|
|
|
|
if (fe) {
|
|
|
|
current = fo;
|
|
|
|
fo = new TexFrame();
|
|
|
|
fo.load(pageStr(fe));
|
|
|
|
|
|
|
|
if (fo.page == null) {
|
|
|
|
fo = current;
|
|
|
|
// sendbaseline ERR_PAGE
|
|
|
|
sendBaseline(ERR_ROUTE,false);
|
|
|
|
mode = action = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
control.push(new edit(fo));
|
|
|
|
|
|
|
|
mode = false;
|
|
|
|
action = false;
|
|
|
|
break;
|
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
// Goto specific page
|
|
|
|
case ACTION_GOTO:
|
|
|
|
log(LOG_DEBUG,'- ACTION_GOTO: ['+(next_page ? pageStr(next_page) : '')+']');
|
|
|
|
|
|
|
|
if (next_page !== null) {
|
|
|
|
current = fo;
|
2020-07-13 13:08:37 +00:00
|
|
|
fo = new TexFrame();
|
2020-03-26 06:22:46 +00:00
|
|
|
fo.load(pageStr(next_page));
|
|
|
|
|
|
|
|
if (fo.page == null) {
|
2019-10-03 04:08:48 +00:00
|
|
|
fo = current;
|
|
|
|
// sendbaseline ERR_PAGE
|
|
|
|
sendBaseline(ERR_ROUTE,false);
|
|
|
|
mode = action = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:56:12 +00:00
|
|
|
// If the user has access to the frame
|
|
|
|
if (fo.accessible) {
|
2020-07-18 13:48:51 +00:00
|
|
|
if (fo.isMember && fo.type == FRAME_TYPE_LOGIN) {
|
|
|
|
sendBaseline(ALREADY_MEMBER,false);
|
|
|
|
mode = action = false;
|
2019-10-03 04:08:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:56:12 +00:00
|
|
|
// Check if the frame exists, and the user is the Service Provider
|
2019-10-03 04:08:48 +00:00
|
|
|
} else {
|
2020-05-27 11:56:12 +00:00
|
|
|
sendBaseline(ACCESS_DENIED,false);
|
|
|
|
mode = action = false;
|
2020-05-28 13:30:44 +00:00
|
|
|
// Reset the current frame to what it was.
|
|
|
|
fo = current;
|
2020-05-27 11:56:12 +00:00
|
|
|
break;
|
2019-10-03 04:08:48 +00:00
|
|
|
}
|
|
|
|
|
2020-05-28 13:30:44 +00:00
|
|
|
current = null;
|
2019-10-17 13:27:51 +00:00
|
|
|
log(LOG_DEBUG,'- ACTION_GOTO: next_page ['+JSON.stringify(next_page)+'] last history ['+JSON.stringify(history[history.length-1])+']');
|
|
|
|
|
|
|
|
// Record our history
|
2020-03-26 06:22:46 +00:00
|
|
|
if (next_page && (! history.length || (pageStr(history[history.length-1]) != pageStr(next_page))) && (fo.type != FRAME_TYPE_LOGIN)) {
|
2019-10-17 13:27:51 +00:00
|
|
|
// Ignore the login frames
|
2020-03-26 06:22:46 +00:00
|
|
|
if (NO_HISTORY_FRAMES.indexOf(pageStr(next_page)) == -1) {
|
2019-10-17 13:27:51 +00:00
|
|
|
history.push(next_page);
|
|
|
|
log(LOG_DEBUG,'- ACTION_GOTO: Added to history ['+(next_page ? pageStr(next_page) : '')+'] now ['+history.length+']');
|
|
|
|
}
|
2019-10-03 04:08:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
next_page = null;
|
|
|
|
|
2020-05-27 11:56:12 +00:00
|
|
|
// Load frame
|
2019-10-03 04:08:48 +00:00
|
|
|
case ACTION_RELOAD:
|
|
|
|
log(LOG_DEBUG,'- ACTION_RELOAD: ['+(next_page ? pageStr(next_page) : '')+']');
|
|
|
|
|
|
|
|
// Clear the baseline history
|
|
|
|
// $this->sendBaseline($client,'');
|
|
|
|
// $current['baseline'] = '';
|
2019-10-16 05:32:43 +00:00
|
|
|
console.line_counter=0; // @todo fix to suppress a pause that is occurring before clear()
|
|
|
|
console.clear();
|
2020-07-08 02:42:58 +00:00
|
|
|
// Clear any controls
|
|
|
|
control = [];
|
2020-02-26 11:54:39 +00:00
|
|
|
bbs.replace_text(NodeActionMain,'\1h%s \1nViewing \1h*'+fo.frame+'#\1n ['+fo.index+']');
|
|
|
|
bbs.log_str(fo.page+'|');
|
|
|
|
bbs.node_action=NODE_MAIN;
|
2019-10-03 04:08:48 +00:00
|
|
|
|
|
|
|
switch(fo.type) {
|
2019-10-16 05:32:43 +00:00
|
|
|
// Terminate frame
|
|
|
|
case FRAME_TYPE_TERMINATE:
|
2019-10-27 01:04:22 +00:00
|
|
|
console.putmsg(fo.render());
|
2020-05-27 11:56:12 +00:00
|
|
|
mode = false;
|
|
|
|
action = ACTION_TERMINATE;
|
|
|
|
|
|
|
|
break;
|
2019-10-16 05:32:43 +00:00
|
|
|
|
2019-10-27 01:04:22 +00:00
|
|
|
// External Frame
|
2019-11-03 12:42:03 +00:00
|
|
|
// @todo returning from the frame, go to the 0 key if it is set
|
2019-10-27 01:04:22 +00:00
|
|
|
case FRAME_TYPE_EXTERNAL:
|
2020-07-19 11:58:35 +00:00
|
|
|
var content = base64_decode(fo.content);
|
|
|
|
log(LOG_DEBUG,'- ACTION_GOTO: EXTERNAL ['+JSON.stringify(content)+']');
|
2019-11-03 12:42:03 +00:00
|
|
|
|
2020-07-19 11:58:35 +00:00
|
|
|
switch(content.replace(/\n/,'')) {
|
2019-10-27 01:04:22 +00:00
|
|
|
case 'bbs.user_config()':
|
|
|
|
case 'bbs.read_mail(MAIL_YOUR)':
|
2019-11-03 12:42:03 +00:00
|
|
|
case 'bbs.scan_subs(SCAN_NEW)':
|
|
|
|
case 'bbs.scan_posts()':
|
|
|
|
case 'bbs.post_msg()':
|
2020-07-19 11:58:35 +00:00
|
|
|
eval(content);
|
2019-10-27 01:04:22 +00:00
|
|
|
|
|
|
|
// Check and see if our shell was changed
|
|
|
|
if (user.command_shell != 'ansitex') {
|
|
|
|
exit();
|
|
|
|
}
|
2019-11-03 12:42:03 +00:00
|
|
|
|
|
|
|
action = ACTION_BACKUP;
|
2019-10-27 01:04:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2020-07-19 11:58:35 +00:00
|
|
|
console.putmsg(JSON.stringify(content));
|
2019-10-27 01:04:22 +00:00
|
|
|
sendBaseline(ERR_ROUTE,false);
|
2019-11-03 12:42:03 +00:00
|
|
|
action = false;
|
2019-10-27 01:04:22 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-11-03 12:42:03 +00:00
|
|
|
|
2019-10-27 01:04:22 +00:00
|
|
|
mode = false;
|
|
|
|
break;
|
|
|
|
|
2020-03-27 13:55:42 +00:00
|
|
|
case FRAME_TYPE_LOGIN:
|
2020-05-27 11:56:12 +00:00
|
|
|
action = false;
|
|
|
|
|
2020-03-27 13:55:42 +00:00
|
|
|
case FRAME_TYPE_RESPONSE:
|
2020-05-27 11:56:12 +00:00
|
|
|
//log(LOG_DEBUG,'FRAME_TYPE_RESPONSE :'+fo.page+', FIELDS: '+fo.frame_fields.count);
|
|
|
|
fn = 0;
|
|
|
|
cf = null;
|
2020-03-27 13:55:42 +00:00
|
|
|
console.putmsg(fo.render());
|
2020-05-27 11:56:12 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-07-06 12:55:58 +00:00
|
|
|
// If this is the register page
|
|
|
|
// @todo this needs to be configurable
|
|
|
|
if (fo.page == '981a') {
|
|
|
|
log(LOG_DEBUG,'Adding REGISTER to control stack');
|
2020-07-09 13:12:17 +00:00
|
|
|
require('ansitex/load/'+fo.key[1]+'.js','CONTROL_REGISTER');
|
|
|
|
control.push(eval("new "+fo.key[1]+'();'));
|
2020-07-06 12:55:58 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 13:55:42 +00:00
|
|
|
break;
|
|
|
|
|
2019-10-03 04:08:48 +00:00
|
|
|
// Standard Frame
|
2019-10-16 05:32:43 +00:00
|
|
|
case FRAME_TYPE_INFO:
|
2019-10-03 04:08:48 +00:00
|
|
|
default:
|
2019-10-27 01:04:22 +00:00
|
|
|
console.putmsg(fo.render());
|
2019-10-03 04:08:48 +00:00
|
|
|
mode = action = false;
|
2019-10-27 01:04:22 +00:00
|
|
|
break;
|
2019-10-03 04:08:48 +00:00
|
|
|
|
|
|
|
// Active frame
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
log(LOG_DEBUG,'ACTION END: ['+read+']');
|
|
|
|
}
|
2020-05-27 11:56:12 +00:00
|
|
|
|
|
|
|
log(LOG_DEBUG,'- FINISHED');
|
|
|
|
if (action == ACTION_TERMINATE) {
|
|
|
|
log(LOG_DEBUG,'! Hangup');
|
|
|
|
bbs.hangup();
|
|
|
|
}
|
|
|
|
|
|
|
|
exit();
|
|
|
|
}
|