diff --git a/xtrn/oneliners/commands.js b/xtrn/oneliners/commands.js new file mode 100644 index 0000000000000000000000000000000000000000..4b769a05c4b6eb65f604cd371166bf53bdefa5ab --- /dev/null +++ b/xtrn/oneliners/commands.js @@ -0,0 +1,22 @@ +var root = argv[0]; +load(root + "/lib.js"); +var settings = initSettings(root); + +this.QUERY = function(client, packet) { + var openOpers = [ + "SUBSCRIBE", + "UNSUBSCRIBE", + "READ", + "SLICE", + "PUSH" + ]; + if(openOpers.indexOf(packet.oper) >= 0 || admin.verify(client, packet, 90)) + return false; + log(LOG_ERR, + format( + "Invalid command %s from client %s", + packet.oper, client.remote_ip_address + ) + ); + return true; +} \ No newline at end of file diff --git a/xtrn/oneliners/framed.js b/xtrn/oneliners/framed.js new file mode 100644 index 0000000000000000000000000000000000000000..a85d3550f431db798c3fe2bfc633ee0b87bde0f5 --- /dev/null +++ b/xtrn/oneliners/framed.js @@ -0,0 +1,210 @@ +load("frame.js"); +load("inputline.js"); + +var frame, + onelinersFrame, + inputFrame, + inputLine, + oneliners, + inInput = false, + attr = console.attributes, + status = bbs.sys_status; + +var initFrames = function() { + + console.clear(BG_BLACK|LIGHTGRAY); + + frame = new Frame( + 1, + 1, + console.screen_columns, + console.screen_rows, + LIGHTGRAY + ); + + onelinersFrame = new Frame( + frame.x + 1, + frame.y + 2, + frame.width - 2, + frame.height - 4, + LIGHTGRAY, + frame + ); + + inputAliasFrame = new Frame( + onelinersFrame.x, + frame.height - 1, + user.alias.length + system.qwk_id.length + 3, + 1, + LIGHTGRAY, + frame + ); + + inputFrame = new Frame( + onelinersFrame.x + user.alias.length + system.qwk_id.length + 3, + frame.height - 1, + onelinersFrame.width - user.alias.length - system.qwk_id.length - 3, + 1, + BG_BLUE|LIGHTGRAY, + frame + ); + + promptFrame = new Frame( + onelinersFrame.x, + frame.height - 1, + onelinersFrame.width, + 1, + LIGHTCYAN, + frame + ); + + inputAliasFrame.putmsg(user.alias + "\1n\1c@\1b" + system.qwk_id.toLowerCase() + "\1h\1k: "); + promptFrame.putmsg("Add a oneliner to the wall? [Y/\1h\1wN\1h\1c]"); + frame.drawBorder([LIGHTBLUE, CYAN, LIGHTCYAN, WHITE]); + var header = format( + "\1h\1w%s synchronet oneliners %s", + ascii(180), ascii(195) + ); + frame.gotoxy(frame.width - console.strlen(header) - 2, 1); + frame.putmsg(header); + frame.open(); + +} + +var initInput = function() { + inputLine = new InputLine(inputFrame); + inputLine.max_buffer = inputFrame.width; + inputLine.auto_clear = false; + inputLine.attr = BG_BLUE|WHITE; + inputLine.cursor_attr = BG_BLUE|WHITE; +} + +var initJSON = function() { + try { + oneliners = new Oneliners(settings.server, settings.port, putOneliner); + var count = oneliners.count; + if(count > onelinersFrame.height) + var lines = oneliners.read(count - onelinersFrame.height); + else + var lines = oneliners.read(0); + for(var line in lines) + putOneliner(lines[line]); + oneliners.callback = putOneliner; + } catch(err) { + log(LOG_ERR, "Oneliners error: " + err); + exit(); + } +} + +var init = function() { + bbs.sys_status |= SS_MOFF; + initFrames(); + initInput(); + initJSON(); +} + +var putOneliner = function(oneliner) { + onelinersFrame.putmsg( + format( + "\1n\1w%s\1n\1c@\1h\1b%s\1h\1k: \1n\1w%s\r\n", + oneliner.alias, + oneliner.qwkid, + pipeToCtrlA( + ( oneliner.oneliner.length + + + oneliner.alias.length + + + oneliner.qwkid.length + + + 3 + > + onelinersFrame.width + ) + ? + oneliner.oneliner.substr( + 0, + onelinersFrame.width + - + ( oneliner.alias.length + + + oneliner.qwkid.length + + + 3 + ) + ) + : + oneliner.oneliner + ) + ) + ); +} + +var cycle = function() { + try { + oneliners.cycle(); + } catch(err) { + log(LOG_ERR, "Oneliners error: " + err); + } + if(frame.cycle()) + console.gotoxy(console.screen_columns, console.screen_rows); + return (inInput)?inputLine.getkey():console.inkey(K_NONE,5).toUpperCase(); +} + +var main = function() { + var userInput; + while(!js.terminated) { + userInput = cycle(); + if(inInput) { + inputLine.attr = + (inputLine.buffer.length > (80 - user.alias.length - system.qwk_id.length - 3)) + ? + BG_BLUE|RED + : + BG_BLUE|WHITE; + if(typeof userInput != "undefined") { + inInput = false; + inputLine.clear(); + promptFrame.open(); + promptFrame.top(); + userInput = userInput.replace(/\\1/g, ascii(1)); + if(console.strlen(userInput) < 1) + continue; + postOneliner(user.alias, userInput); + } + continue; + } + if(!inInput) { + userInput = userInput.toUpperCase(); + if(userInput == "Y") { + promptFrame.close(); + inputAliasFrame.top(); + inputFrame.top(); + inInput = true; + // A hack to get the cursor (near) to the correct spot + console.ungetstr("*"); + inputLine.getkey(); + console.ungetstr("\x08"); + // So ends the hack. + continue; + } else if(userInput == "N" || ascii(userInput) == 13) { + break; + } + continue; + } + } +} + +var cleanUp = function() { + try { + oneliners.close(); + } catch(err) { + log(LOG_ERR, "Oneliners error: " + err); + } + frame.close(); + console.clear(attr); + bbs.sys_status = status; +} + +init(); +main(); +cleanUp(); \ No newline at end of file diff --git a/xtrn/oneliners/lib.js b/xtrn/oneliners/lib.js new file mode 100644 index 0000000000000000000000000000000000000000..b850ddf883a77271e82fc5daa40ae69e8661b1b4 --- /dev/null +++ b/xtrn/oneliners/lib.js @@ -0,0 +1,78 @@ +load("json-client.js"); + +var initSettings = function(path) { + var f = new File(path + "settings.ini"); + f.open("r"); + var o = f.iniGetObject(); + f.close(); + return o; +} + +var postOneliner = function(alias, userInput) { + try { + oneliners.post(alias, userInput); + } catch(err) { + log(LOG_ERR, "JSON client error: " + err); + exit(); + } +} + +var Oneliners = function(server, port, callback) { + + var jsonClient = new JSONClient(server, port); + + this.__defineGetter__( + 'count', + function() { + return jsonClient.read("ONELINERS", "ONELINERS.length", 1); + } + ); + this.__defineSetter__('count', function() {}); + + this.read = function(start, end) { + return jsonClient.slice( + "ONELINERS", + "ONELINERS", + start, + (typeof end == "undefined") ? undefined : end, + 1 + ); + } + + this.post = function(alias, oneliner) { + var obj = { + 'time' : time(), + 'client' : (typeof client != "undefined") ? client.ip_address : system.inet_addr, + 'alias' : alias, + 'systemName' : system.name, + 'systemHost' : system.inet_addr, + 'qwkid' : system.qwk_id.toLowerCase(), + 'oneliner' : oneliner + }; + jsonClient.push( + "ONELINERS", + "ONELINERS", + obj, + 2 + ); + } + + this.cycle = function() { + jsonClient.cycle(); + } + + this.close = function() { + jsonClient.disconnect(); + } + + if(typeof callback == "function") { + var handler = function(update) { + if(update.location != "LATEST" || update.oper != "WRITE") + return; + callback(update.data); + } + jsonClient.callback = handler; + jsonClient.subscribe("ONELINERS", "LATEST"); + } + +} diff --git a/xtrn/oneliners/oneliners.js b/xtrn/oneliners/oneliners.js new file mode 100644 index 0000000000000000000000000000000000000000..e1c7e33a902cf53a5157b7d4412ee62c28b646c7 --- /dev/null +++ b/xtrn/oneliners/oneliners.js @@ -0,0 +1,9 @@ +load("sbbsdefs.js"); +load(js.exec_dir + "lib.js"); + +var settings = initSettings(js.exec_dir); + +if(console.autoterm&USER_ANSI) + load(js.exec_dir + "framed.js"); +else + load(js.exec_dir + "plain.js"); \ No newline at end of file diff --git a/xtrn/oneliners/plain.js b/xtrn/oneliners/plain.js new file mode 100644 index 0000000000000000000000000000000000000000..0cfb3715ac67aad22f5dea850fb9522ba0399fd5 --- /dev/null +++ b/xtrn/oneliners/plain.js @@ -0,0 +1,86 @@ +var settings, oneliners, attr; + +var init = function() { + oneliners = new Oneliners(settings.server, settings.port); + attr = console.attributes; + console.clear(BG_BLACK|LIGHTGRAY); + console.putmsg("\1h\1wsynchronet oneliners"); + console.crlf(); console.crlf(); +} + +var getOneliners = function() { + var count = oneliners.count; + if(count > console.screen_rows - 4) + var lines = oneliners.read(count - console.screen_rows - 4); + else + var lines = oneliners.read(0); + for(var line in lines) { + console.putmsg( + format( + "\1n\1w%s\1n\1c@\1h\1b%s\1h\1k: \1n\1w%s\r\n", + lines[line].alias, + lines[line].qwkid, + pipeToCtrlA( + ( lines[line].oneliner.length + + + lines[line].alias.length + + + lines[line].qwkid.length + + + 3 + > + console.screen_columns + ) + ? + lines[line].oneliner.substr( + 0, + console.screen_columns + - + ( lines[line].alias.length + + + lines[line].qwkid.length + + + 3 + ) + ) + : + lines[line].oneliner + ) + ) + ); + } +} + +var prompt = function() { + console.crlf(); + return console.noyes("Post a oneliner to the wall? "); +} + +var postOneliner = function() { + console.clearline(); + console.putmsg(user.alias + "@" + system.qwk_id + ": "); + var userInput = console.getstr( + "", + console.screen_columns - user.alias.length - system.qwk_id.length - 3, + K_LINE|K_EDIT + ); + if(console.strlen(userInput) < 1) + return; + oneliners.post(user.alias, userInput); +} + +var cleanUp = function() { + oneliners.close(); + console.attributes = attr; + console.clear(); +} + +try { + init(); + getOneliners(); + if(!prompt()) + postOneliner(); + cleanUp(); +} catch(err) { + log(LOG_ERR, "Oneliners error: " + err); +} \ No newline at end of file diff --git a/xtrn/oneliners/readme.txt b/xtrn/oneliners/readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3cc69ce0f003a6a2ebb75c7e8fde07d2510d190 --- /dev/null +++ b/xtrn/oneliners/readme.txt @@ -0,0 +1,100 @@ +Synchronet Oneliners +by echicken + +Contents + +1) Installation +1.1) Prerequisites +1.2) Connecting to a remote wall +1.3) Hosting your own wall +1.4) External program configuration +2) Rules (there are none) +3) Support +4) To-do list + +1) Installation + +1.1) Prerequisites + +I've only tested this with Synchronet installations up-to-date with the +Synchronet CVS (http://wiki.synchro.net/dev:cvs) as of August 24th, 2014. +You'll want to grab the latest copy of 'exec/load/frame.js', as this module +relies on a recent update to that script. Other updates may be required. + +1.2) Connecting to a remote service + +Connecting to a remote service means accessing a shared, inter-BBS oneliners +wall. Most sysops will likely want to go this route, as it will mean more +activity and "fun" for everybody. + +Edit the 'settings.ini' file in your 'xtrn/oneliners/' directory to read as +follows: + +server=bbs.electronicchicken.com +port=10088 + +Your oneliners scripts will now access the shared wall that I host. + +1.3) Hosting your own wall + +If you'd prefer to host your own wall, just leave the 'settings.ini' file in +your 'xtrn/oneliners/' directory as-is. + +If you want other people to be able to connect to your wall, you'll need to +ensure that the JSON-DB service is enabled on your BBS, and that the port that +you choose for it is open and forwarded to your BBS. To enable the JSON-DB +service (if you haven't already,) add the following section to your +'ctrl/services.ini' file: + +[JSON-Service] +Port=10088 +Options=STATIC|LOOP +Command=json-service.js + +You'll also need to add the following to your 'ctrl/json-service.ini' file: + +[oneliners] +dir=../xtrn/oneliners/ + +1.4) External Program Configuration + +In 'scfg' (that's 'BBS->Configure' from the Synchronet Control Panel in +Windows,) go to 'External Programs->Online Programs (Doors)', select or create +the section you want to add the oneliners program to, select 'Available Online +Programs', hit enter on a blank line, and configure the external program as +follows: + +Online Program Name: Synchronet Oneliners +Internal Code: ONELINER +Start-up Directory: ../xtrn/oneliners +Command Line: ?oneliners.js +Multiple Concurrent Users: Yes + +If you want this program run automatically when a user logs in, set 'Execute +on Event' to 'Logon', and answer 'No' to 'Execute as Event Only.' + +There are a bunch of other options that you can leave in their default states. + +2) Rules (there are none) + +I don't care if people want to spam my shared oneliners wall with profanity +or BBS advertisements. I'm not interested in policing or censoring the +content. Everyone's free to set up their own wall and manage it as they like. + +3) Support + +If you need help, there are a few options: + +- Post a message to 'echicken' in the 'Synchronet Sysops' sub on DOVE-Net +- Send an email to echicken -at- bbs.electronicchicken.com +- Find me in #synchronet on irc.synchro.net + +A oneliners wall is not a great place for support discussions. You can post +your complaints and problems there, but if I see them I'll either ignore them +or ask you to contact me via one of the above methods. + +4) To-do list + +- Make the colours of various elements configurable +- Create an SSJS script to allow listing/posting oneliners via the web +- Create a web API to enable access for non-Synchronet systems \ No newline at end of file diff --git a/xtrn/oneliners/service.js b/xtrn/oneliners/service.js new file mode 100644 index 0000000000000000000000000000000000000000..65fd3590a25cfa2f6a2c75f51501971bc14cb793 --- /dev/null +++ b/xtrn/oneliners/service.js @@ -0,0 +1,66 @@ +var root = argv[0]; +load(root + "lib.js"); +load("json-client.js"); + +var settings, jsonClient, usr; + +var processUpdate = function(update) { + for(var count = jsonClient.read("ONELINERS", "ONELINERS.length", 1); count >= 50; count--) { + jsonClient.push( + "ONELINERS", + "HISTORY", + jsonClient.shift("ONELINERS", "ONELINERS", 2), + 2 + ); + } + if(typeof update != "undefined" && update.oper == "WRITE") { + jsonClient.write("ONELINERS", "LATEST", update.data[update.data.length - 1], 2); + } +} + +var init = function() { + usr = new User(1); + settings = initSettings(root); + var dummy = [ + { 'time' : time(), + 'client' : system.inet_addr, + 'alias' : "oneliners", + 'systemName' : system.name, + 'systemHost' : system.inet_addr, + 'qwkid' : system.qwk_id.toLowerCase(), + 'oneliner' : "Oneliners database initialized." + } + ]; + jsonClient = new JSONClient(settings.server, settings.port); + jsonClient.ident("ADMIN", usr.alias, usr.security.password); + if(!jsonClient.read("ONELINERS", "ONELINERS", 1)) { + if(file_exists(root + "oneliners.json")) + file_copy(root + "oneliners.json", root + "oneliners.bak"); + jsonClient.write("ONELINERS", "ONELINERS", dummy, 2); + jsonClient.write("ONELINERS", "HISTORY", dummy, 2); + jsonClient.write("ONELINERS", "LATEST", dummy[0], 2); + } + jsonClient.subscribe("ONELINERS", "ONELINERS"); + jsonClient.callback = processUpdate; + processUpdate(); +} + +var main = function() { + while(!js.terminated) { + mswait(5); + jsonClient.cycle(); + } +} + +var cleanUp = function() { + jsonClient.disconnect(); +} + +try { + init(); + main(); + cleanUp(); + exit(); +} catch(err) { + log(LOG_ERR, "Oneliners service error: " + err); +} \ No newline at end of file diff --git a/xtrn/oneliners/settings.ini b/xtrn/oneliners/settings.ini new file mode 100644 index 0000000000000000000000000000000000000000..bb8b85d75ec7b822529c8e435b05d8dcd4eb4eab --- /dev/null +++ b/xtrn/oneliners/settings.ini @@ -0,0 +1,2 @@ +server = bbs.electronicchicken.com +port = 10088