Implemented saving a frame to the message base and frame_import

This commit is contained in:
Deon George 2024-12-04 10:13:28 +11:00
parent f7a581fa30
commit da51bd3d0b
5 changed files with 183 additions and 250 deletions

View File

@ -143,19 +143,27 @@ function MsgArea() {
// Get all frames that are tagged // Get all frames that are tagged
Object.defineProperty(this,'frames',{ Object.defineProperty(this,'frames',{
get: function() { get: function() {
if (! this.managed) var msgbase;
var regex = false;
if (this.code === FRAMES_MSG_BASE) {
msgbase = this.msgbase;
} else if (this.managed) {
msgbase = new MsgAreas().getArea(FRAMES_MSG_BASE).msgbase;
regex = this.page_prefix_regex;
} else
return undefined; return undefined;
var msgbase = new MsgAreas().getArea(FRAMES_MSG_BASE).msgbase;
var frames = []; var frames = [];
var regex = this.page_prefix_regex;
try { try {
if (msgbase.open()) { if (msgbase.open()) {
var headers = msgbase.get_all_msg_headers(false,false) || []; var headers = msgbase.get_all_msg_headers(false,false) || [];
for (var i in headers) { for (var i in headers) {
if ((! (headers[i].attr&MSG_DELETE)) && headers[i].tags && regex.test(headers[i].tags)) if ((! (headers[i].attr&MSG_DELETE)) && headers[i].tags && ((! regex) || regex.test(headers[i].tags)))
frames.push(headers[i]); frames.push(headers[i]);
} }
@ -208,7 +216,8 @@ function MsgArea() {
} }
}); });
Object.defineProperty(this,'last_tagged',{ // Retrieve the last tagged frame
Object.defineProperty(this,'last_tagged_message',{
get: function() { get: function() {
var last_tag = this.frames.sort(function(a,b) { var last_tag = this.frames.sort(function(a,b) {
if (a.when_imported_time === b.when_imported_time) if (a.when_imported_time === b.when_imported_time)
@ -217,6 +226,9 @@ function MsgArea() {
return (a.when_imported_time > b.when_imported_time); return (a.when_imported_time > b.when_imported_time);
}).pop(); }).pop();
if (last_tag === undefined)
return undefined;
var msgbase = new MsgAreas().getArea(FRAMES_MSG_BASE).msgbase; var msgbase = new MsgAreas().getArea(FRAMES_MSG_BASE).msgbase;
try { try {
@ -230,7 +242,7 @@ function MsgArea() {
} }
} catch (e) { } catch (e) {
log(LOG_ERROR,this.code+' cannot be opened (last_tagged):'+e.message); log(LOG_ERROR,this.code+' cannot be opened (last_tagged_message):'+e.message);
return undefined; return undefined;
} }
@ -248,7 +260,7 @@ function MsgArea() {
} }
} catch (e) { } catch (e) {
log(LOG_ERROR,this.code+' cannot be opened (last_tagged):'+e.message); log(LOG_ERROR,this.code+' cannot be opened (last_tagged_message_base):'+e.message);
return undefined; return undefined;
} }
@ -257,7 +269,7 @@ function MsgArea() {
} }
}) })
// Is this area defined for videotex messages // Is this area defined for ansitex messages
Object.defineProperty(this,'managed',{ Object.defineProperty(this,'managed',{
get: function() { get: function() {
return (this.zone_id !== undefined) && (this.area_id !== undefined); return (this.zone_id !== undefined) && (this.area_id !== undefined);
@ -365,7 +377,7 @@ function MsgArea() {
return undefined; return undefined;
var msgbase = this.msgbase; var msgbase = this.msgbase;
var last_tag = this.last_tagged; var last_tag = this.last_tagged_message;
var msgs = []; var msgs = [];
try { try {
@ -401,6 +413,40 @@ function MsgArea() {
} }
}); });
// Get frame content
MsgArea.prototype.getContent = function(id) {
// @todo If this is for a echomail/netmail content, then we need to switch message bases
if (this.code !== FRAMES_MSG_BASE)
return undefined;
var msgbase = this.msgbase;
try {
if (msgbase.open()) {
var content = JSON.parse(LZString.decompressFromBase64(msgbase.get_msg_body(false,id,false,false,true,true)));
msgbase.close();
var i;
for (var i=0; i<content.length; i++) {
// Echomail tag line
if (content[i] === '---' || content[i].substring(0,4) === '--- ')
break;
}
content.length = i;
} else {
writeln('*** NOPE WONT OPEN msgbase:'+JSON.stringify(msgbase));
}
} catch (e) {
log(LOG_ERROR,this.code+' cannot be opened (frames):'+e.message);
return undefined;
}
return content;
};
// @todo review // @todo review
/** /**
* Unread messages [1..] * Unread messages [1..]

View File

@ -77,7 +77,7 @@
*/ */
load('ansitex/load/windows.js'); // Our supporting window class load('ansitex/load/windows.js'); // Our supporting window class
require('ansitex/load/msgbases.js','PAGE_LENGTH'); // To read/write to message bases load('ansitex/load/msgbases.js'); // To read/write to message bases
require('sbbsdefs.js','SS_USERON'); // Need for our ANSI colors eg: BG_* require('sbbsdefs.js','SS_USERON'); // Need for our ANSI colors eg: BG_*
/** /**
@ -144,7 +144,7 @@ function Page(debug) {
// isPublic is TRUE - can be viewed by users (if logged in) // isPublic is TRUE - can be viewed by users (if logged in)
key: [], // Key actions key: [], // Key actions
raw: undefined, // Page raw content raw: {}, // Page raw content for each session type
}; };
this.__defaults__ = { this.__defaults__ = {
@ -424,8 +424,14 @@ function Page(debug) {
this.__window__.provider.__properties__.content = provider; this.__window__.provider.__properties__.content = provider;
}); });
Page.prototype.__defineGetter__('raw',function() { Object.defineProperty(this,'raw',{
return this.__properties__.raw; get: function() {
return this.__properties__.raw
},
set: function(value) {
this.__properties__.raw[SESSION_EXT] = value;
}
}); });
Page.prototype.__defineSetter__('showHeader',function(bool) { Page.prototype.__defineSetter__('showHeader',function(bool) {
@ -885,6 +891,21 @@ function Page(debug) {
} }
} }
Page.prototype.file_content = function(filename) {
log(LOG_DEBUG,'|-- Importing frame content: ['+filename+']');
var f = new File(filename);
if (! f.exists || ! f.open('rb',true)) {
log(LOG_ERROR,'|? File doesnt exist: ['+filename+']');
return false;
}
var content = f.read();
f.close();
return content;
};
/** /**
* Load a specific page * Load a specific page
* *
@ -901,7 +922,7 @@ function Page(debug) {
return true; return true;
// Fall back to loading from msgbase // Fall back to loading from msgbase
return FRAMES_MSG_BASE ? this.load(page) : false; return FRAMES_MSG_BASE && this.load(page);
} }
/** /**
@ -924,53 +945,52 @@ function Page(debug) {
* Load a frame from a file * Load a frame from a file
* *
* @param filename - Name of file to load page from (SBBS default dir is CTRL, so relative to it) * @param filename - Name of file to load page from (SBBS default dir is CTRL, so relative to it)
* @param width - Width to build window (not required for ANS)
* @param height - Height to build window (not required for ANS)
* @returns {boolean} * @returns {boolean}
* @todo Dont allow load() to load a Viewdata frame for an ANSItex session and visa-versa.
*/ */
this.import = function(filename,ext,width,height) { Page.prototype.import = function(filename) {
log(LOG_DEBUG,'|- Importing frame: ['+filename+']'); log(LOG_DEBUG,'|- Importing frame: ['+filename+']');
var f = new File(filename); var f = new File(filename);
if (! f.exists || ! f.open('rb',true)) { if (! f.exists || ! f.open('rb',true)) {
log(LOG_ERROR,'|? File doesnt exist: ['+filename+']'); log(LOG_ERROR,'|? File doesnt exist: ['+filename+']');
return null; return false;
} }
var contents = f.read(); var contents = JSON.parse(f.read());
f.close(); f.close();
// Load the page content
if (contents.version === 2)
contents.content = this.file_content(FRAMES_HOME+SESSION_EXT+'/'+this.name.toString()+'.'+CONTENT_EXT);
var valid_sauce = false; var valid_sauce = false;
if (contents.substr(-128, 7) === 'SAUCE00') { if (contents.content.substr(-128, 7) === 'SAUCE00') {
ext = file_getext(filename).substr(1).toLowerCase(); var sauceless_size = ascii(contents.content.substr(-35,1));
var sauceless_size = ascii(contents.substr(-35,1));
sauceless_size <<= 8; sauceless_size <<= 8;
sauceless_size |= ascii(contents.substr(-36,1)); sauceless_size |= ascii(contents.content.substr(-36,1));
sauceless_size <<= 8; sauceless_size <<= 8;
sauceless_size |= ascii(contents.substr(-37,1)); sauceless_size |= ascii(contents.content.substr(-37,1));
sauceless_size <<= 8; sauceless_size <<= 8;
sauceless_size |= ascii(contents.substr(-38,1)); sauceless_size |= ascii(contents.content.substr(-38,1));
var data_type = ascii(contents.substr(-34,1)); var data_type = ascii(contents.content.substr(-34,1));
var file_type = ascii(contents.substr(-33,1)); var file_type = ascii(contents.content.substr(-33,1));
var tinfo1 = ascii(contents.substr(-31,1)); var tinfo1 = ascii(contents.content.substr(-31,1));
tinfo1 <<= 8; tinfo1 <<= 8;
tinfo1 |= ascii(contents.substr(-32,1)); tinfo1 |= ascii(contents.content.substr(-32,1));
var tinfo2 = ascii(contents.substr(-29,1)); var tinfo2 = ascii(contents.content.substr(-29,1));
tinfo2 <<= 8; tinfo2 <<= 8;
tinfo2 |= ascii(contents.substr(-30,1)); tinfo2 |= ascii(contents.content.substr(-30,1));
switch(data_type) { switch(data_type) {
case 1: case 1:
switch(file_type) { switch(file_type) {
// Plain ASCII // Plain ASCII
case 0: case 0:
ext = 'TXT'; var ext = 'TXT';
if (tinfo1) if (tinfo1)
width = tinfo1; width = tinfo1;
if (tinfo2) if (tinfo2)
@ -979,7 +999,7 @@ function Page(debug) {
// ANSI // ANSI
case 1: case 1:
ext = 'ANS'; var ext = 'ANS';
if (tinfo1) if (tinfo1)
width = tinfo1; width = tinfo1;
if (tinfo2) if (tinfo2)
@ -988,7 +1008,7 @@ function Page(debug) {
// Source // Source
case 7: case 7:
ext = 'TXT'; var ext = 'TXT';
break; break;
} }
@ -996,7 +1016,7 @@ function Page(debug) {
break; break;
case 5: case 5:
ext = 'BIN'; var ext = 'BIN';
width = file_type * 2; width = file_type * 2;
height = (sauceless_size / 2) / width; height = (sauceless_size / 2) / width;
valid_sauce = true; valid_sauce = true;
@ -1004,69 +1024,35 @@ function Page(debug) {
} }
if (valid_sauce) if (valid_sauce)
contents = contents.substr(0, sauceless_size); contents.content = contents.content.substr(0, sauceless_size);
} }
return this.preload((['vtx','tex'].indexOf(ext) !== -1) ? JSON.parse(contents) : contents,ext,width,height); return this.preload(contents,SESSION_EXT);
} }
// Load a frame from a message base
this.load = function(page) { this.load = function(page) {
var headers; var page = this.name.toString();
var mb = new MsgAreas().getArea(FRAMES_MSG_BASE)
var mb = new MsgBase(FRAMES_MSG_BASE); var msg = mb.frames
.sort(function(a,b) {
try { if (a.when_imported_time === b.when_imported_time)
if (mb.open()) { return a.number < b.number
headers = mb.get_all_msg_headers(false,false) || []; else
return (a.when_imported_time < b.when_imported_time); })
} else { .filter(function(item) { return item.tags === page; }).pop();
log(LOG_ERROR,'! ['+FRAMES_MSG_BASE+'] cannot be opened ['+mb.error+']');
return false;
}
// @todo It appears if the message base doesnt exist, we dont error?
} catch (e) {
log(LOG_ERROR,'! ['+FRAMES_MSG_BASE+'] cannot be opened ['+e.message+']');
return false;
}
var msg;
// Find existing message with the page number
for (var x in headers) {
if ((!(headers[x].attr&MSG_DELETE)) && (headers[x].to === page.toString()) && (headers[x].from === SESSION_EXT)) {
msg = headers[x];
//break; @todo We'll take the last one that matches, if there are more than one.
// @todo In the case of frames coming via FTN packets, we are not currently deleting old entries
}
}
if (msg === undefined) { if (msg === undefined) {
log(LOG_DEBUG,'|- Frame not found: ['+page.toString()+'] in ['+FRAMES_MSG_BASE+']'); log(LOG_DEBUG,'|- Frame not found: ['+page.toString()+'] in ['+FRAMES_MSG_BASE+']');
return false; return false;
} else { } else {
log(LOG_DEBUG,'|- Loading frame: ['+page.toString()+'] from msgbase ['+msg.number+']'); log(LOG_DEBUG,'|- Loading frame: ['+page.toString()+'] from msgbase ['+msg.number+'] ['+SESSION_EXT+']');
var contents = mb.get_msg_body(false,msg.number,false,false,true,true).split("\r\n"); var contents = mb.getContent(msg.number);
contents.content = contents.content[SESSION_EXT];
var i; return this.preload(contents,SESSION_EXT);
for (var i=0; i<contents.length; i++) {
// Echomail tag line
if (contents[i] === '---' || contents[i].substring(0,4) === '--- ')
break;
}
contents.length = i;
try {
var result = JSON.parse(contents.join(''));
} catch(e) {
alert('Error ' + e + ' parsing JSON');
}
return this.preload(result,SESSION_EXT);
} }
return false; return false;
@ -1109,7 +1095,7 @@ function Page(debug) {
* @param height * @param height
* @returns {boolean|null} * @returns {boolean|null}
*/ */
this.preload = function(contents,ext,width,height) { this.preload = function(contents,ext) {
switch (ext) { switch (ext) {
// Messages // Messages
case 'txt': case 'txt':
@ -1117,7 +1103,7 @@ function Page(debug) {
var page = rawtoattrs(contents,this.width,this.__window__.body.y,this.__window__.body.x,debug); var page = rawtoattrs(contents,this.width,this.__window__.body.y,this.__window__.body.x,debug);
this.__window__.body.__properties__.content = page.content; this.__window__.body.__properties__.content = page.content;
this.__properties__.raw = contents; return contents;
// ANSI files // ANSI files
case 'ans': case 'ans':
@ -1131,7 +1117,7 @@ function Page(debug) {
// Our fields are sorted in x descending order // Our fields are sorted in x descending order
this.input_fields = page.input_fields.sort(function(a,b) { return a.x < b.x ? 1 : -1; }); this.input_fields = page.input_fields.sort(function(a,b) { return a.x < b.x ? 1 : -1; });
this.__properties__.raw = contents; this.raw = contents;
break; break;
@ -1164,7 +1150,7 @@ function Page(debug) {
if (page.input_fields.length) if (page.input_fields.length)
this.input_fields = page.input_fields.sort(function(a,b) { return a.x < b.x ? 1 : -1; }); this.input_fields = page.input_fields.sort(function(a,b) { return a.x < b.x ? 1 : -1; });
this.__properties__.raw = base64_decode(contents[index]); this.raw = base64_decode(contents[index]);
break; break;
@ -1249,21 +1235,7 @@ function Page(debug) {
break; break;
case 2: case 2:
// Load the page content var page = rawtoattrs(contents.content,this.width,this.__window__.body.y,this.__window__.body.x);
var content_file = FRAMES_HOME+SESSION_EXT+'/'+this.name.toString()+'.'+CONTENT_EXT;
log(LOG_DEBUG,'|-- Importing frame content: ['+content_file+']');
var f = new File(content_file);
if (! f.exists || ! f.open('rb',true)) {
log(LOG_ERROR,'|? File doesnt exist: ['+content_file+']');
this.get(new PageObject(FRAME_SYSTEM_ERROR));
break;
}
this.__properties__.raw = f.read();
f.close();
var page = rawtoattrs(this.__properties__.raw,this.width,this.__window__.body.y,this.__window__.body.x);
this.__window__.body.__properties__.content = page.content; this.__window__.body.__properties__.content = page.content;
this.dynamic_fields = page.dynamic_fields; this.dynamic_fields = page.dynamic_fields;
@ -1276,6 +1248,7 @@ function Page(debug) {
this.attrs = contents.attrs; this.attrs = contents.attrs;
this.cost = contents.cost; this.cost = contents.cost;
this.key = contents.key; this.key = contents.key;
this.raw = contents.content;
break; break;
@ -1304,115 +1277,39 @@ function Page(debug) {
* Save the frame to the message base * Save the frame to the message base
*/ */
this.save = function() { this.save = function() {
var mb = new MsgBase(FRAMES_MSG_BASE); var msgbase = new MsgAreas().getArea(FRAMES_MSG_BASE).msgbase;
var headers;
try { if (! msgbase.open()) {
if (mb.open()) { log(LOG_ERROR,'! Message Base cannot be opened (save): ['+msgbase.error+']');
headers = mb.get_all_msg_headers(false,false) || []; return false;
} else {
log(LOG_ERROR,FRAMES_MSG_BASE+' cannot be opened:'+mb.error);
return;
}
} catch (e) {
log(LOG_ERROR,FRAMES_MSG_BASE+' cannot be opened:'+e.message);
return;
} }
// Build the save content var hdr = {
var content = {}; to: this.name,
from: 'SYSTEM',
tags: this.name,
//date: msgs[x].date,
subject: 'Content',
};
for (var index in FRAME_SAVE_ATTRS) { var page = {
switch (FRAME_SAVE_ATTRS[index]) { 'version': 2,
case 'cost': 'attrs': p.attrs,
content[FRAME_SAVE_ATTRS[index]] = this.cost; 'cost': p.cost,
break; 'key': p.key,
'content': p.raw,
};
case 'dynamic_fields': var body = LZString.compressToBase64(JSON.stringify(page));
content[FRAME_SAVE_ATTRS[index]] = this.dynamic_fields;
break;
case 'frame': if (! msgbase.save_msg(hdr,body)) {
content[FRAME_SAVE_ATTRS[index]] = this.name.frame;
break;
case 'index':
content[FRAME_SAVE_ATTRS[index]] = this.name.index;
break;
case 'input_fields':
content[FRAME_SAVE_ATTRS[index]] = this.input_fields;
break;
case 'isAccessible':
content[FRAME_SAVE_ATTRS[index]] = this.__properties__.isAccessible;
break;
case 'isPublic':
content[FRAME_SAVE_ATTRS[index]] = this.__properties__.isPublic;
break;
case 'key':
content[FRAME_SAVE_ATTRS[index]] = this.key;
break;
case 'type':
content[FRAME_SAVE_ATTRS[index]] = this.type;
break;
case 'version':
content[FRAME_SAVE_ATTRS[index]] = 1;
break;
case 'window':
content[FRAME_SAVE_ATTRS[index]] = this.__window__.body.__properties__.content;
break;
default:
log(LOG_ERROR,' ! NOTE Index ['+FRAME_SAVE_ATTRS[index]+'] has been ignored.');
continue;
}
log(LOG_DEBUG,' / Storing ['+FRAME_SAVE_ATTRS[index]+'] with value:'+content[FRAME_SAVE_ATTRS[index]]);
}
// Find existing message with the page number and delete it if defined
var msg;
for (var x in headers) {
if ((headers[x].tags === this.name.toString()) && (!(headers[x].attr&MSG_DELETE))) {
msg = headers[x];
break;
}
}
if (msg === undefined) {
log(LOG_DEBUG,' - Saving NEW frame: ['+this.name.toString()+'] to ['+FRAMES_MSG_BASE+']');
} else {
log(LOG_DEBUG,' - REPLACING frame: ['+this.name.toString()+'] at ['+msg.number+']');
if (! mb.remove_msg(msg.number))
log(LOG_ERROR,' ! Error removing frame: ['+this.name.toString()+'] to ['+msg.number+']');
}
log(LOG_DEBUG,'** Save frame with keys'+JSON.stringify(Object.keys(content)));
if (! mb.save_msg(
{
subject: this.name.toString(),
to: this.name.toString(),
from: SESSION_EXT,
tags: this.name.toString(),
},
JSON.stringify(content)
))
log(LOG_ERROR,' ! Error saving frame: ['+this.name.toString()+']'); log(LOG_ERROR,' ! Error saving frame: ['+this.name.toString()+']');
}
mb.close(); msgbase.close();
// @todo Find old message and delete it?
return true;
} }
this.scroll = function(x,y) { this.scroll = function(x,y) {

View File

@ -8,7 +8,7 @@ if (argv.length !== 1) {
exit(1); exit(1);
} else { } else {
writeln('Showing frames:'+argv[0]); writeln('Showing frame:'+argv[0]);
} }
const SESSION_EXT = 'tex'; const SESSION_EXT = 'tex';

32
tools/frame_import.js Normal file
View File

@ -0,0 +1,32 @@
/**
* Load a frame, and store it in the message base
*/
load('ansitex/load/page.js');
load('ansitex/load/funcs.js');
load('lz-string.js');
/* parse command arguments */
if (argv.length !== 1) {
writeln('ERROR: Need a frame ID');
exit(1);
} else {
writeln('Importing frame:'+argv[0]);
}
var po = new PageObject(argv[0]);
// Load ANSItex frame
var SESSION_EXT = 'tex';
require('ansitex/load/session/ansitex.js','SESSION_ANSITEX');
var p = new Page();
p.get(po);
// Load Viewdata frame
var SESSION_EXT = 'vtx';
require('ansitex/load/session/viewdata.js','SESSION_VIEWDATA');
p.raw = p.file_content(FRAMES_HOME+SESSION_EXT+'/'+po.toString()+'.'+CONTENT_EXT);
p.save();

View File

@ -1,42 +0,0 @@
/**
* Load a frame, optionally with a new ANSI/BIN and load it into the msgbase.
*/
load('ansitex/load/funcs.js');
// Our page handler
load('ansitex/load/page.js');
/* parse command arguments */
if (argv.length !== 3) {
writeln('! ERROR: Need 3 arguments only');
exit(1);
}
var frame = argv.shift();
var index = argv.shift();
var file = argv.shift();
var ext = file_getext(file).substr(1).toLowerCase();
// Type of frame to load
switch (ext) {
case 'tex':
case 'ans':
require('ansitex/load/session/ansitex.js','SESSION_ANSITEX');
break;
case 'vtx':
case 'bin':
require('ansitex/load/session/viewdata.js','SESSION_VIEWDATA');
break;
}
var page = new Page();
if (page.get(new PageObject(frame,index))) {
page.import(file,ext);
page.save();
} else if (['vtx','tex'].indexOf(ext) !== -1) {
page.import(file,ext);
page.save();
}