Enabled adding a context to render, so that dynamic fields can resolve locally (like in a message). Improved dynamic fields identification and resolution. Use of more consts for standard frames. Fix history recording and backtracking.

This commit is contained in:
Deon George
2022-05-01 17:42:19 +10:00
parent 0214416c4e
commit 2dc348a29c
12 changed files with 202 additions and 79 deletions

View File

@@ -59,6 +59,10 @@ const FRAME_TYPE_EXTERNAL ='x';
const FRAME_TYPE_RESPONSE ='r';
/* Login frame, enables the user to authenticate to the system, or to a CUG */
const FRAME_TYPE_LOGIN ='l';
/* Mail template frames - mail templates will have the user's stats for the area passed to render() */
const FRAME_TYPE_MAIL_TEMPLATE ='m';
/* Frame is a message */
const FRAME_TYPE_MESSAGE ='M';
/* Disable *# going backwards for the following frames */
var NO_HISTORY_FRAMES =['980a','98b','981a','982a','983a','998a'];
@@ -74,6 +78,7 @@ const INACTIVE_LOGIN =5*60000;
var SYSTEM_ZONE =516;
// @todo rename these all to FRAME_*
/* Home Frame */
const HOME_FRAME ={frame: 1,index: 'a'};
/* Login Frame */
@@ -88,8 +93,18 @@ const LOGIN_FAILED_FRAME ={frame: 983,index: 'a'};
const HOME_FRAME_AUTH ={frame: 98,index: 'b'};
/* Home page for initial connection */
const HOME_FRAME_CONNECT ={frame: 980,index: 'a'};
const FRAME_SYSTEM_ERROR ={frame: 998,index: 'a'};
/* Attributes saved/loaded from files */
const SAVED_FRAME_ATTRS =['version','frame','frame_fields','index','owner','cost','content','isPublic','isAccessible','type','key'];
/* The page that has our echomail area reading template */
var MAIL_TEMPLATE_FRAME ='199a';
/* The page that has our echomail area summary template */
var MAIL_TEMPLATE_AREA_SUMMARY ='198a';
// The maximum size of embedded dynamic fields in frames
var DYNAMIC_FIELD_SIZE_MAX =50;
this;

View File

@@ -75,7 +75,7 @@ function FrameAnsi() {
}
// Render the frame to the user
this.render=function(withoutHeader) {
this.render=function(context,withoutHeader) {
log(LOG_DEBUG,'- ANSI FRAME');
owner = base64_decode(this.owner);
@@ -99,7 +99,7 @@ function FrameAnsi() {
contentgraphic = new Graphic(this.settings.FRAME_WIDTH);
contentgraphic.auto_extend = true;
contentgraphic.atcodes = false;
contentgraphic.ANSI = this.parse(base64_decode(this.content));
contentgraphic.ANSI = this.parse(base64_decode(this.content),context);
var contentframe = new Frame(1,2,this.settings.FRAME_WIDTH,this.settings.FRAME_LENGTH,LIGHTGRAY,frame);
contentframe.open();

View File

@@ -1,5 +1,3 @@
var MAIL_TEMPLATE_FRAME = '199a';
// Our frame object
function PageFrame() {
'use strict';
@@ -171,8 +169,7 @@ PageFrame.prototype.load = function(filename) {
log(LOG_ERROR,'Frame error: '+error);
// Load our system error frame.
// @todo this should be a config item
this.load('998a');
this.load(pageStr(FRAME_SYSTEM_ERROR));
return null;
}
@@ -190,11 +187,13 @@ PageFrame.prototype.loadMessage = function(page) {
this.owner = 1;
this.isPublic = true;
this.isAccessible = true;
this.key = [0,null,null,null,null,null,null,null,null,918];
// @todo Keys should map to next/previous/send, etc as indicated in the template frame.
this.key = [this.frame.substr(0,7)+'1',null,null,null,null,null,null,null,null,null];
this.type = FRAME_TYPE_MESSAGE;
// Load our message
var ma = new MsgAreas()
var msg = ma.getMessage(page);
var msg = ma.getMessage(this.frame);
var msg_header;
if (! msg)
@@ -215,6 +214,7 @@ PageFrame.prototype.loadMessage = function(page) {
msg_header += 'SUBJECT: '+msg.subject.substr(0,72)+"\n\r";
} else {
// @todo change this to use atcode()
msg_header = base64_decode(to.content).replace(/@(.*)@/g,
function (str, code, offset, s) {
var length = code.split(':')[1];
@@ -228,7 +228,7 @@ PageFrame.prototype.loadMessage = function(page) {
);
}
log(LOG_DEBUG,'Loaded message: '+msg_header+msg.content);
//log(LOG_DEBUG,'Loaded message: '+msg_header+msg.content);
this.content = base64_encode(msg_header+msg.content);
log(LOG_DEBUG,'Loaded frame: ['+this.frame+']['+this.index+'] ('+this.page+')');
@@ -247,8 +247,16 @@ PageFrame.prototype.loadMessage = function(page) {
* should apply for that field.
*
* @param text
* @param context
*/
PageFrame.prototype.parse = function(text) {
PageFrame.prototype.parse = function(text,context) {
log(LOG_DEBUG,'Parsing Frame ...');
if (this.type === FRAME_TYPE_MESSAGE) {
log(LOG_DEBUG,'- Not parsing message frame');
return text;
}
/** Column
* @type {number}
*/
@@ -394,13 +402,16 @@ PageFrame.prototype.parse = function(text) {
break;
// X - dynamic fields, terminated with ESC
// Dynamic fields are defined with ESC X FIELD;LENGTH;PAD ESC \
// @note FIELD & LENGTH are required
// @note Dynamic field is can only be DYNAMIC_FIELD_SIZE_MAX chars in size
case 'X':
//log(LOG_DEBUG,'PU ['+r+'x'+c+'] '+advance);
//log(LOG_DEBUG,'DF ['+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-9]+)([;]?.+)?)\x1b\\/);
//log(LOG_DEBUG,'PU ['+r+'x'+c+'] ADVANCE: '+advance+', MATCHES: '+JSON.stringify(matches)+', LENGTH: '+(matches ? matches[0].length : 0)+', STRING: '+text.substr(p+advance,50));
// Find our end ST param in the next DYNAMIC_FIELD_SIZE_MAX chars
matches = text.substr(p+advance,DYNAMIC_FIELD_SIZE_MAX).match(/(([a-zA-Z._^;]+[0-9]?;-?[0-9^;]+)([;]?[^;]+)?)\x1b\\/);
//log(LOG_DEBUG,'- DF ['+r+'x'+c+'] ADVANCE: '+advance+', MATCHES: '+JSON.stringify(matches)+', LENGTH: '+(matches ? matches[0].length : 0)+', STRING: '+text.substr(p+advance,50));
if (! matches) {
chars += nextbyte;
@@ -410,14 +421,13 @@ PageFrame.prototype.parse = function(text) {
advance += matches[0].length-1;
var pu = matches[0].substr(0,matches[0].length-2).split(';');
//log(LOG_DEBUG,'PU ['+r+'x'+c+'] ADVANCE: '+advance+', PU: '+pu);
var df = matches[0].substr(0,matches[0].length-2).split(';');
//log(LOG_DEBUG,'- DF ['+r+'x'+c+'] ADVANCE: '+advance+', DF: '+df);
chars = renderfield(pu[0],pu[1]);
log(LOG_DEBUG,'- DF found at ['+r+'x'+(c-1)+'], Field: '+df[0]+', Length: '+df[1]+', Attrs: '+JSON.stringify({i:i,f:f,b:b}));
chars = atcode(df[0],df[1],df[2],context);
byte = '';
log(LOG_DEBUG,'PU Field found at ['+r+'x'+(c-1)+'], Field: '+pu[0]+', Length: '+pu[1]+', Attrs: '+JSON.stringify({i:i,f:f,b:b}));
break;
// _ - has our fields that take input
@@ -528,12 +538,5 @@ PageFrame.prototype.parse = function(text) {
*/
}
// Convert any atcodes
output = output.replace(/@(.*)@/g,
function (str, code, offset, s) {
return bbs.atcode(code);
}
);
return output;
};

View File

@@ -104,6 +104,58 @@ function ans2bin(ansi,frame) {
}
}
// Dynamic Field Processing
// @note bbs.atcodes() cannot process modifiers, so this function is a replacement.
function atcode(field,length,pad,context) {
'use strict';
length = length ? length : field.length;
pad = pad ? pad : ' ';
var result = '';
switch(field) {
// Get the ECHOAREA FTN AREA_TAG
case 'areatag':
if (typeof context !== 'object') {
log(LOG_ERROR,'Unable to render ['+field+'], no context provided');
break;
}
result = context.msgbase.cfg.area_tag;
break;
// Get the ECHOAREA Description
case 'areadesc':
if (typeof context !== 'object') {
log(LOG_ERROR,'Unable to render ['+field+'], no context provided');
break;
}
result = context.msgbase.cfg.description;
break;
case 'nodeid':
result = getNodeID();
break;
default:
result = bbs.atcode(field);
if (result === null)
result = '';
}
log(LOG_DEBUG,' - result length ['+result.length+'] desired ('+length+')');
if (result.length < Math.abs(length))
result = (length < 0) ? padright(result,Math.abs(length),pad) : padleft(result,length,pad);
else if (result.length > Math.abs(length))
result = result.substr(0,Math.abs(length));
log(LOG_DEBUG,'- ATCODE ['+field+'] ('+length+'|"'+pad+'") returns ['+result+']');
return result;
}
/**
* Find a message base by code
*
@@ -164,7 +216,7 @@ function getNodeID() {
}
}
return pad(matches[0],3)+pad(matches[1],3)+pad(bbs.node_num,2);
return padleft(matches[0],3,'0')+padleft(matches[1],3,'0')+padleft(bbs.node_num,2,'0');
}
function getPageOwners() {
@@ -228,11 +280,18 @@ function msgBaseImport(msgbase,page,text) {
return msgbase.save_msg(hdr, body);
}
// Pad a number with zeros
function pad(n, width, z) {
z = z || '0';
// Right Pad a string with char c
function padright(n,width,c) {
c = c || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
return n.length >= width ? n : new Array(width - n.length + 1).join(c) + n;
}
// Left Pad a string with char c
function padleft(n,width,c) {
c = c || '0';
n = n + '';
return n.length >= width ? n : n+new Array(width - n.length + 1).join(c);
}
/**
@@ -314,20 +373,6 @@ function pageEditor(page) {
return pageditor;
}
function renderfield(field,length) {
switch (field) {
case 'nodeid':
result = getNodeID();
}
if (result.length < length)
result += ' '.repeat(length-result.length);
else if (result.length > length)
result = result.substr(0,length);
return result;
}
/**
* This function returns a list of zones used by this system.
*/

View File

@@ -230,17 +230,30 @@ MsgArea.prototype.tag_msgs = function() {
return true;
}
MsgAreas.prototype.getMessage = function(page) {
if (page === undefined)
MsgAreas.prototype.getArea = function(area) {
log(LOG_DEBUG,'- AREA:'+JSON.stringify(area));
if (area === undefined)
return undefined;
var zone = page.substr(0,4);
var echo = page.substr(4,2);
var page = page.substr(6);
var zone = (''+area).substr(1,4);
var echo = (''+area).substr(5,2);
log(LOG_DEBUG,' - zone:'+JSON.stringify(zone));
log(LOG_DEBUG,' - echo:'+JSON.stringify(echo));
area = this.areas.filter(function(x) {
return this.areas.filter(function(x) {
return x.zone_id === zone && x.area_id === echo;
})[0]
return area ? area.getMessage(page) : undefined;
}
MsgAreas.prototype.getMessage = function(page) {
var area = this.getArea(page);
log(LOG_DEBUG,' - msg:'+JSON.stringify(page.substr(7,4)));
return area ? area.getMessage(page.substr(7,4)) : undefined;
}
MsgAreas.prototype.getUserStats = function(page) {
var area = this.getArea(page);
return area ? msg_area.grp_list[area.msgbase.cfg.grp_number].sub_list[msg_area.sub[area.msgbase.cfg.code].index] : undefined;
}