sbbs/load/msgbases.js

433 lines
10 KiB
JavaScript

const PAGE_LENGTH = 4; // The size of our page tag as stored in the msgbase for echomail/netmail
const PAGE_LAST_KEY = 'last_page'; // Last page which has the latest message
const MAX_PAGE_NUM = 9999; // Maximum page number. @todo Can this be changed to '9'.repeat(PAGE_LENGTH)?
// Our message bases
function MsgAreas() {
'use strict';
this.areas = [];
this.areas_excluded = [];
var zone_id;
var zone_name;
var ma;
for(var g in msg_area.grp_list) {
if (msg_area.grp_list[g].name.indexOf(':') !== -1) {
zone_id = msg_area.grp_list[g].name.split(':')[0];
zone_name = msg_area.grp_list[g].name.split(':')[1];
for (var a in msg_area.grp_list[g].sub_list) {
if (msg_area.grp_list[g].sub_list[a].name.indexOf(':') !== -1) {
ma = new MsgArea();
ma.zone_id = zone_id;
ma.zone_name = zone_name;
ma.area_id = msg_area.grp_list[g].sub_list[a].name.split(':')[0];
ma.area_name = msg_area.grp_list[g].sub_list[a].name.split(':')[1];
ma.code = msg_area.grp_list[g].sub_list[a].code;
this.areas.push(ma);
} else {
this.areas_excluded.push(zone_name+':'+msg_area.grp_list[g].sub_list[a].name);
}
}
} else {
zone_name = msg_area.grp_list[g].name;
for (var a in msg_area.grp_list[g].sub_list) {
this.areas_excluded.push(zone_name+':'+msg_area.grp_list[g].sub_list[a].name);
}
}
}
Object.defineProperty(this,'list',{
get: function() {
writeln('Areas that we are NOT managing mail:'+this.areas_excluded.length);
writeln('Areas that we ARE managing mail:'+this.areas.length);
for(var x in this.areas_excluded) {
/*
writeln(this.areas_excluded[x].area_name = undefined
? JSON.stringify(this.areas_excluded[x])
: this.areas_excluded[x].area_name);
*/
writeln(JSON.stringify(this.areas_excluded[x]));
exit();
}
}
});
}
function MsgArea() {
this.zone_id = undefined;
this.zone_name = undefined;
this.area_id = undefined;
this.area_name = undefined;
this.msgbase = undefined;
this.headers = undefined;
this.tagged_list = undefined;
this.untagged_list = undefined;
this.grp_number = undefined;
this.subnum = undefined;
/**
* Build a MsgArea once we are given the code
*/
Object.defineProperty(this,'code',{
set: function(code) {
this.msgbase = new MsgBase(code);
try {
if (this.msgbase.open()) {
headers = this.msgbase.get_all_msg_headers(false,false) || [];
// Just take the last MAX_MESSAGES
this.headers = Object.keys(headers).slice(-(MAX_PAGE_NUM+1)).map(function(key) { return headers[key]; });
headers = undefined;
this.msgbase.close();
} else {
log(LOG_ERROR,code+' cannot be opened:'+this.msgbase.error);
this.headers = [];
}
} catch (e) {
log(LOG_ERROR,code+' cannot be opened:'+e.message);
this.headers = [];
}
}
});
// Get Area's full name
Object.defineProperty(this,'full_name',{
get: function() {
return this.zone_name+':'+this.area_name;
}
});
// Total tagged messages
Object.defineProperty(this,'list_tagged',{
get: function() {
if (this.tagged_list === undefined) {
this.tagged_list = [];
if (! this.headers)
return this.tagged_list;
for(var x in this.headers) {
if (this.headers[x].tags && (this.headers[x].tags.length === PAGE_LENGTH)) {
this.tagged_list.push(this.headers[x]);
write(); // @todo This is needed for this to work?
}
}
}
return this.tagged_list;
}
});
// List untagged messages
Object.defineProperty(this,'list_untagged',{
get: function() {
if (this.untagged_list === undefined) {
this.untagged_list = [];
if (! this.headers)
return this.untagged_list;
for(var x in this.headers) {
if ((! this.headers[x].tags) || (this.headers[x].tags.length !== PAGE_LENGTH)) {
this.untagged_list.push(this.headers[x]);
write(); // @todo This is needed for this to work?
}
}
}
return this.untagged_list;
}
});
// Get Next page number
Object.defineProperty(this,'page_next',{
get: function() {
var f = new File(file_cfgname(system.mods_dir,'ansitex/ctrl/videotex.ini'));
if (! f.open('r')) {
writeln('Unable to open ini file');
exit(2);
}
var page = f.iniGetValue('prefix:'+this.page_prefix,PAGE_LAST_KEY)
f.close();
return page ? page : '0'.repeat(PAGE_LENGTH);
},
set: function(page) {
var f = new File(file_cfgname(system.mods_dir,'ansitex/ctrl/videotex.ini'));
if (! f.open('r+')) {
writeln('Unable to open ini file');
exit(2);
}
f.iniSetValue('prefix:'+this.page_prefix,PAGE_LAST_KEY,(''+page).padStart(4,'0'));
f.close();
}
});
// Our page prefix for this msg area
Object.defineProperty(this,'page_prefix',{
get: function() {
return ''+this.zone_id+this.area_id;
},
});
}
/**
* Unread messages [1..]
* Array key 0 returns the last read message
*
* @returns {*[]}
*/
MsgArea.prototype.newMsgs = function() {
var msgs = [];
var stats = this.getUserStats();
//log(LOG_DEBUG,'Users last_read pointer: '+JSON.stringify(stats.last_read));
for(var x in this.list_tagged) {
// Advance past our last scan_ptr
if (this.list_tagged[x].number <= stats.last_read)
continue;
msgs.push(this.list_tagged[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();
var last = null;
//log(LOG_DEBUG,'Users scan_ptr pointer: '+JSON.stringify(stats.scan_ptr));
for(var x in this.list_tagged) {
// Advance past our last scan_ptr
if (this.list_tagged[x].number <= stats.scan_ptr) {
if ((this.list_tagged[x].to === user.name) || (this.list_tagged[x].to === user.alias))
last = x;
continue;
}
// Add our previous to me message
if (msgs.length === 0)
msgs.push(last !== null ? this.list_tagged[last] : []);
if ((this.list_tagged[x].to === user.name) || (this.list_tagged[x].to === user.alias))
msgs.push(this.list_tagged[x]);
write(); // @todo This is needed for this to work?
}
return msgs;
}
/**
* Get a specific message with a tag
*/
MsgArea.prototype.getMessage = function(page) {
var msg = undefined;
for(var x in this.list_tagged) {
if (this.list_tagged[x].tags === page) {
msg = this.list_tagged[x];
break;
}
write(); // @todo This is needed for this to work?
}
if (! msg)
return undefined;
if (! this.msgbase.open()) {
writeln(code+' cannot be opened:'+this.msgbase.error);
return undefined;
}
msg.grp_number = this.msgbase.cfg.grp_number;
var cfg = this.msgbase.cfg;
msg.subnum = msg_area.grp_list[cfg.grp_number].sub_list.filter(function(x) { return x.number === cfg.number; }).pop().index;
msg.content = this.msgbase.get_msg_body(false,msg.number,false,false,true,true);
this.msgbase.close();
return msg;
}
/**
* Get a message page by pointer
*
* @param number
* @returns {string}
*/
MsgArea.prototype.getMessagePage = function(number) {
log(LOG_DEBUG,'Get Message Page with number ['+number+']');
var r;
for (var x in this.list_tagged) {
if (this.list_tagged[x].number === number) {
r = this.list_tagged[x];
break;
}
}
if (! r || r.tags === undefined)
return null;
return '1'+this.zone_id+this.area_id+r.tags;
}
MsgArea.prototype.getUserStats = function() {
return this.msgbase.cfg ? msg_area.grp_list[this.msgbase.cfg.grp_number].sub_list[msg_area.sub[this.msgbase.cfg.code].index] : [];
}
MsgArea.prototype.MessageNext = function(page) {
var x = null;
if (! page)
return undefined;
var msgid = page.substr(7,4);
for(x in this.list_tagged) {
if (this.list_tagged[x].tags === msgid) {
break;
}
write(); // @todo This is needed for this to work?
}
//log(LOG_DEBUG,'- Next Message is:'+JSON.stringify(this.list_tagged[(parseInt(x)+1)])+', msgid:'+msgid+', page:'+page+', x:'+x);
/*
= Our next message is either
+ x+1 if x < this.list_tagged.length
+ x=0 if x == this.list_tagged.length (-1)
+ null if this.list_tagged.length == null; (thus no messages)
*/
return x === null ? null : this.list_tagged[(parseInt(x) === this.list_tagged.length-1) ? 0 : (parseInt(x)+1)];
}
MsgArea.prototype.MessagePrev = function(page) {
var prev = null;
var x = null;
if (! page)
return undefined;
var msgid = page.substr(7,4);
for(x in this.list_tagged) {
if (this.list_tagged[x].tags === msgid) {
break;
} else {
prev = x;
}
write(); // @todo This is needed for this to work?
}
/*
= Our previous message is either
+ prev if a tag was found, unless
+ prev is null, in which case it is this.list_tagged.length -1
+ null if x is still null (thus no messages)
*/
// If prev is still null, then our last message must be the last one, unless x is null then there are no messages
return x === null ? null : this.list_tagged[(prev === null) ? this.list_tagged.length-1 : parseInt(prev)];
}
/**
* Tag messages with a frame number
* @note: May need to run jsexec with -m 32MB to overcome memory issues
*
* @returns {boolean}
*/
MsgArea.prototype.tag_msgs = function() {
var msgs = this.list_untagged;
writeln("We have "+msgs.length+" messages to tag.");
// See if we need to tag something
if (! msgs.length)
return;
if (! this.msgbase.open()) {
writeln(code+' cannot be opened:'+this.msgbase.error);
return false;
}
var page_next = this.page_next;
for(var x in msgs) {
msgs[x].tags = (''+(page_next)).padStart(4,'0');
if(! this.msgbase.put_msg_header(msgs[x].number,msgs[x])) {
writeln('ERROR:'+this.msgbase.error);
} else {
page_next++;
if (page_next > MAX_PAGE_NUM)
page_next = 0;
}
}
this.msgbase.close();
this.page_next = page_next;
return true;
}
MsgArea.prototype.page = function(msgid) {
return '1'+this.page_prefix+msgid;
}
MsgAreas.prototype.getArea = function(area) {
log(LOG_DEBUG,'- AREA:'+JSON.stringify(area));
if (area === undefined)
return undefined;
var zone = (''+area).substr(1,4);
var echo = (''+area).substr(5,2);
log(LOG_DEBUG,' - zone:'+zone);
log(LOG_DEBUG,' - echo:'+echo);
return this.areas.filter(function(x) {
return x.zone_id === zone && x.area_id === echo;
})[0]
}
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;
}