Skip to content
Snippets Groups Projects
Commit a17c9c6a authored by rswindell's avatar rswindell
Browse files

Added support for import/export of shared avatar bin files (libraries of

avatars).
The library (from where the user picks stock/shared avatars) is
text/avatars/*.bin.
Network-shared avatars .bin files (meeting the requirements) are imported
as <qwk-id>.<filename.bin> in this directory.
The sysop chooses which locally created avatar libraries to share
with the "export=<sub> -f=<filename>".
There's no de-duplication at this time.
Move some functions from avatar_lib.js to avatars.js.
parent 6f22fa7b
Branches
Tags
No related merge requests found
......@@ -4,10 +4,12 @@ var REVISION = "$Revision$".split(' ')[1];
load('sbbsdefs.js');
load("lz-string.js");
var lib = load({}, 'avatar_lib.js');
var SAUCE = load({}, 'sauce_lib.js');
const to_name = 'SBBS Avatars';
const user_avatars = 'SBBS User Avatars';
const shared_avatars = 'SBBS Shared Avatars';
function parse_msg(text)
function parse_user_msg(text)
{
var i;
var json_begin;
......@@ -41,13 +43,115 @@ function parse_msg(text)
return false;
}
function parse_file_msg(text)
{
var i;
var bin_begin;
var bin_end;
// Terminate at tear-line
text=text.split("\r\n");
for(i=0; i<text.length; i++) {
if(text[i]=="---" || text[i].substring(0,4)=="--- ")
break;
}
text.length=i;
// Parse JSON block
for(i=0; i<text.length; i++) {
if(text[i].toLowerCase()=="bin-lz-begin")
bin_begin=i+1;
else if(text[i].toLowerCase()=="bin-lz-end")
bin_end=i;
}
if(bin_begin && bin_end > bin_begin) {
text = text.splice(bin_begin, bin_end-bin_begin);
return LZString.decompressFromBase64(text.join('').replace(/\s+/g, ''));
}
return false;
}
function find_name(objs, name)
{
for(var i=0; i < objs.length; i++)
if(objs[i].name.toLowerCase() == name.toLowerCase())
return i;
return -1;
}
function import_netuser_list(hdr, list)
{
var objs = [];
var file = new File(this.netuser_fname(hdr.from_netaddr));
if(file.open("r")) {
objs = file.iniGetAllObjects();
file.close();
}
for(var i in list) {
for(var u in list[i]) {
var index = find_name(objs, list[i][u]);
if(index >= 0) {
if(objs[index].data != i) {
objs[index].data = i;
objs[index].updated = new Date();
}
} else
objs.push({ name: list[i][u], data: i, created: new Date() });
}
}
if(!file.open("w"))
return false;
file.writeln(format(";from %s at %s (%s) on %s"
, hdr.from, hdr.subj, hdr.from_net_addr, new Date().toISOString()));
var result = file.iniSetAllObjects(objs);
file.close();
return result;
}
function import_shared_file(hdr, body)
{
var data = parse_file_msg(body);
if(!data)
return false;
var filename = format("%s.%s", hdr.msg_net_addr, file_getname(hdr.subject));
if(file_getext(filename).toLowerCase() != '.bin')
filename += '.bin';
var file = new File(format("%sqnet/%s", system.data_dir, filename));
if(!file.open("wb")) {
alert("ERROR " + file.error + " opening " + file.name);
return false;
}
file.write(data);
file.close();
print(file.name + " created successfully");
var sauce = SAUCE.read(file.name);
if(!sauce) {
alert(file.name + " has no SAUCE!");
return false;
}
if(sauce.datatype != SAUCE.defs.datatype.bin
|| sauce.cols != lib.defs.width) {
alert(format("%s has invalid SAUCE! (%u %u)"
,file.name, sauce.datatype, sauce.cols));
return false;
}
var new_path = format("%savatars/%s", system.text_dir, filename);
var result = file_copy(file.name, new_path);
if(!result)
alert("ERROR copying " + file.name + " to " + new_path);
return result;
}
function import_from_msgbase(msgbase, import_ptr, limit, all)
{
var i;
var count=0;
var highest;
var avatars_crc=crc16_calc(to_name.toLowerCase());
var users_crc=crc16_calc(user_avatars.toLowerCase());
var shared_crc=crc16_calc(shared_avatars.toLowerCase());
var ini = new File(msgbase.file + ".ini");
if(import_ptr == undefined) {
......@@ -71,26 +175,29 @@ function import_from_msgbase(msgbase, import_ptr, limit, all)
}
if(idx.number <= import_ptr)
continue;
if(idx.to != avatars_crc) {
if(idx.to != users_crc && idx.to != shared_crc) {
continue;
}
if(idx.number > highest)
highest = idx.number;
var hdr = msgbase.get_msg_header(/* by_offset: */true, i);
if(hdr.to.toLowerCase() != to_name.toLowerCase())
continue;
var l;
var msg_from = hdr.from;
if(all != true && !hdr.from_net_type) // Skip locally posted messages
continue;
var body = msgbase.get_msg_body(/* by_offset: */true, i
,/* strip Ctrl-A */true, /* rfc822-encoded: */false, /* include tails: */false);
var avatars = parse_msg(body);
if(!avatars)
continue;
list = decompress_list(avatars);
import_list(hdr.from_net_addr, avatars);
printf("Importing msg #%u from %s: ", hdr.number, hdr.from);
var success = false;
var body = msgbase.get_msg_body(/* by_offset: */true, i
,/* strip Ctrl-A */true, /* rfc822-encoded: */false, /* include tails: */false);
if(hdr.to.toLowerCase() == user_avatars.toLowerCase()) {
var l;
var avatars = parse_user_msg(body);
if(!avatars)
continue;
success = import_netuser_list(hdr, decompress_list(avatars));
} else {
// Shared avatars
success = import_shared_file(hdr, body);
}
printf("%s\r\n", success ? "success" : "FAILED");
count++;
if(limit && count >= limit)
break;
......@@ -113,6 +220,55 @@ function decompress_list(list)
return new_list;
}
function export_users(msgbase, realnames)
{
var last_user = system.lastuser;
var list = {};
for(var n = 1; n <= last_user && !js.terminated; n++) {
if(!file_exists(lib.localuser_fname(n)))
continue;
if(!system.username(n))
continue;
var u = new User(n);
if(u.settings&USER_DELETED)
continue;
var avatar = lib.read_localuser(n);
if(!avatar)
continue;
var data = LZString.compressToBase64(base64_decode(avatar.data));
if(!list[data])
list[data] = [];
list[data].push(u.alias);
if(realnames)
list[data].push(u.name);
}
for(var i in list)
list[i].sort();
var body = "json-begin\r\n";
body += JSON.stringify(list, null, 1) + "\r\n";
body += "json-end\r\n";
body += "--- " + js.exec_file + " " + REVISION + "\r\n";
return msgbase.save_msg({ to:user_avatars, from:system.operator, subject:system.name }, body);
}
function export_file(msgbase, filename)
{
var file = new File(filename);
if(!file.open("rb")) {
alert("Error " + file.error + " opening " + filename);
return false;
}
var data = file.read();
file.close();
data = LZString.compressToBase64(data);
var body = "bin-lz-begin\r\n";
body += data.match(/([\x00-\xff]{1,72})/g).join("\r\n");
body += "\r\nbin-lz-end\r\n";
body += "--- " + js.exec_file + " " + REVISION + "\r\n";
return msgbase.save_msg({ to:shared_avatars, from:system.operator, subject:file_getname(filename) }, body);
}
function main()
{
var optval={};
......@@ -123,6 +279,8 @@ function main()
var realnames = false;
var ptr;
var limit;
var all;
var users = false;
for(i in argv) {
var arg = argv[i];
......@@ -142,12 +300,18 @@ function main()
case '-offset':
offset = val;
break;
case '-users':
users = true;
break;
case '-realnames':
realnames = true;
break;
case "-ptr":
ptr = val;
break;
case "-all":
all = true;
break;
default:
if(parseInt(arg) < 0)
limit = -parseInt(arg);
......@@ -173,23 +337,9 @@ function main()
alert("Error " + msgbase.error + " opening msgbase: " + msgbase.file);
exit(-1);
}
import_from_msgbase(msgbase, ptr, limit);
import_from_msgbase(msgbase, ptr, limit, all);
msgbase.close();
break;
case "import_msg":
var file = new File(filename);
if(!file.open("r")) {
alert("failure opening " + file.name);
return 1;
}
var msg = file.read();
// print(msg);
var list = parse_msg(lfexpand(msg));
print(JSON.stringify(list, null, 1));
list = decompress_list(list);
var success = lib.import_list(optval[cmd], list);
printf("%s\r\n", success ? "Successful" : "FAILED!");
break;
case "export":
var msgbase = new MsgBase(optval[cmd]);
print("Opening msgbase " + msgbase.file);
......@@ -197,43 +347,37 @@ function main()
alert("Error " + msgbase.error + " opening msgbase: " + msgbase.file);
exit(-1);
}
var last_user = system.lastuser;
var list = {};
var count = 0;
for(var n = 1; n <= last_user && !js.terminated; n++) {
if(!file_exists(lib.local_fname(n)))
continue;
if(!system.username(n))
continue;
var u = new User(n);
if(u.settings&USER_DELETED)
continue;
var avatar = lib.read_local(n);
if(!avatar)
continue;
var data = LZString.compressToBase64(base64_decode(avatar.data));
if(!list[data])
list[data] = [];
list[data].push(u.alias);
if(realnames)
list[data].push(u.name);
count++;
if(limit && count > limit)
break;
var success = true;
if(users) {
printf("Exporting user avatars\n");
success = export_users(msgbase, realnames);
}
if(success && filename) {
printf("Exporting avatar file: %s\n", filename);
success = export_file(msgbase, filename);
}
for(var i in list)
list[i].sort();
var body = "json-begin\r\n";
body += JSON.stringify(list, null, 1) + "\r\n";
body += "json-end\r\n";
body += "--- " + js.exec_file + " " + REVISION + "\r\n";
success = msgbase.save_msg({ to:to_name, from:system.operator, subject:system.name + ' Avatars' }, body);
printf("%s\r\n", success ? "Successful" : "FAILED: " + msgbase.last_error);
break;
case "dump":
var obj = lib.read_local(optval[cmd]);
var usernum = optval[cmd];
if(!usernum)
usernum = user.number;
var obj = lib.read_localuser(usernum);
print(JSON.stringify(obj));
break;
case "draw": // Uses Graphic.draw()
var usernum = optval[cmd];
if(!usernum)
usernum = user.number;
console.clear();
var obj = lib.draw(usernum);
break;
case "show": // Uses console.write()
var usernum = optval[cmd];
if(!usernum)
usernum = user.number;
var obj = lib.show(usernum);
break;
}
}
}
......
......@@ -7,19 +7,24 @@ const defs = {
height: 6,
};
function local_fname(usernum)
function local_library()
{
return format("%savatars/", system.text_dir);
}
function localuser_fname(usernum)
{
return format("%suser/%04u.ini", system.data_dir, usernum);
}
function qnet_fname(netaddr)
function netuser_fname(netaddr)
{
return format("%sqnet/%s.avatars.ini", system.data_dir, file_getname(netaddr));
}
function write_local(usernum, obj)
function write_localuser(usernum, obj)
{
var file = new File(this.local_fname(usernum));
var file = new File(this.localuser_fname(usernum));
if(!file.open(file.exists ? 'r+':'w+')) {
return false;
}
......@@ -28,21 +33,20 @@ function write_local(usernum, obj)
return result;
}
function write_qnet(username, netaddr, obj)
function write_netuser(username, netaddr, obj)
{
var file = new File(this.qnet_fname(netaddr));
var file = new File(this.netuser_fname(netaddr));
if(!file.open(file.exists ? 'r+':'w+')) {
return false;
}
var result = file.iniSetObject(username, obj);
file.close();
return result;
}
function read_local(usernum)
function read_localuser(usernum)
{
var file = new File(this.local_fname(usernum));
var file = new File(this.localuser_fname(usernum));
if(!file.open("r")) {
return false;
}
......@@ -51,9 +55,9 @@ function read_local(usernum)
return obj;
}
function read_qnet(username, netaddr)
function read_netuser(username, netaddr)
{
var file = new File(this.qnet_fname(netaddr));
var file = new File(this.netuser_fname(netaddr));
if(!file.open("r")) {
return false;
}
......@@ -65,19 +69,19 @@ function read_qnet(username, netaddr)
function read(usernum, username, netaddr)
{
if(parseInt(usernum) >= 1)
return read_local(usernum);
return read_localuser(usernum);
else
return read_qnet(username, netaddr);
return read_netuser(username, netaddr);
}
function update_local(usernum, data)
function update_localuser(usernum, data)
{
var obj = read_local(usernum);
var obj = read_localuser(usernum);
if(obj == false)
obj = { created: new Date() };
obj.data = data;
obj.updated = new Date();
return write_local(usernum, obj);
return write_localuser(usernum, obj);
}
function import_file(usernum, filename, offset)
......@@ -86,67 +90,54 @@ function import_file(usernum, filename, offset)
var graphic = new Graphic(this.defs.width, this.defs.height);
if(!graphic.load(filename, offset))
return false;
return update_local(usernum, base64_encode(graphic.BIN));
}
function find_name(objs, name)
{
for(var i=0; i < objs.length; i++)
if(objs[i].name.toLowerCase() == name.toLowerCase())
return i;
return -1;
return update_localuser(usernum, base64_encode(graphic.BIN));
}
function import_list(netaddr, list)
// Uses Graphic.draw() at an absolute screen coordinate
function draw(usernum, username, netaddr, above, right)
{
var objs = [];
var file = new File(this.qnet_fname(netaddr));
if(file.open("r")) {
objs = file.iniGetAllObjects();
file.close();
}
for(var i in list) {
for(var u in list[i]) {
var index = find_name(objs, list[i][u]);
if(index >= 0) {
if(objs[index].data != i) {
objs[index].data = i;
objs[index].updated = new Date();
}
} else
objs.push({ name: list[i][u], data: i, created: new Date() });
}
}
if(!file.open("w"))
var avatar = this.read(usernum, username, netaddr);
if(!avatar)
return false;
var result = file.iniSetAllObjects(objs);
file.close();
return result;
load('graphic.js');
var graphic = new Graphic(this.defs.width, this.defs.height);
try {
graphic.BIN = base64_decode([avatar.data]);
var lncntr = console.line_counter;
var pos = console.getxy();
var x = pos.x;
var y = pos.y;
if(above)
y -= this.defs.height;
if(right)
x = console.screen_columns - (this.defs.width + 1);
graphic.attr_mask = ~graphic.defs.BLINK; // Disable blink attribute (consider iCE colors?)
graphic.draw(x, y, this.defs.width, this.defs.height);
console.gotoxy(pos);
console.line_counter = lncntr;
} catch(e) {
return false;
};
return true;
}
function draw(usernum, username, netaddr, above, right)
// Uses console.write() where-ever the cursor happens to be
function show(usernum, username, netaddr)
{
var avatar = this.read(usernum, username, netaddr);
if(avatar) {
load('graphic.js');
var graphic = new Graphic(this.defs.width, this.defs.height);
try {
graphic.BIN = base64_decode([avatar.data]);
var lncntr = console.line_counter;
var pos = console.getxy();
var x = pos.x;
var y = pos.y;
if(above)
y -= this.defs.height;
if(right)
x = console.screen_columns - (this.defs.width + 1);
graphic.attr_mask = ~graphic.defs.BLINK; // Disable blink attribute (consider iCE colors?)
graphic.draw(x, y, this.defs.width, this.defs.height);
console.gotoxy(pos);
console.line_counter = lncntr;
} catch(e) {
};
}
if(!avatar)
return false;
load('graphic.js');
var graphic = new Graphic(this.defs.width, this.defs.height);
graphic.attr_mask = ~graphic.defs.BLINK; // Disable blink attribute (consider iCE colors?)
try {
graphic.BIN = base64_decode([avatar.data]);
console.write(graphic.ANSI);
} catch(e) {
return false;
};
return true;
}
this;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment