diff --git a/exec/avatars.js b/exec/avatars.js index eb7bd29d7d943af6d01bef5708b747c29562a7f3..a09f591ca543f0927cdb024b30f6758c29bb8680 100644 --- a/exec/avatars.js +++ b/exec/avatars.js @@ -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; } } } diff --git a/exec/load/avatar_lib.js b/exec/load/avatar_lib.js index ce777cfefd358b57b4f991597ceb22bfb2373981..24f94448c8d17ea0d8682fae08aeb0ca25db4b2a 100644 --- a/exec/load/avatar_lib.js +++ b/exec/load/avatar_lib.js @@ -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;