diff --git a/web/root/qwk.ssjs b/web/root/qwk.ssjs new file mode 100644 index 0000000000000000000000000000000000000000..b2e143a04aae7450ae8768752bf14b8565a56e54 --- /dev/null +++ b/web/root/qwk.ssjs @@ -0,0 +1,116 @@ +// $Id$ +// vi: tabstop=4 + +// Support QWK packet transfers (uploads of REP packets and downloads of QWK packets) +// in the Synchronet Web Server (e.g. using exec/qnet-http.js) + +const pack_timeout = 60; // seconds +var qwkfile = system.data_dir + format("file/%04u.qwk", user.number); + +function get(query) +{ + var semfile = system.data_dir + format("pack%04u.now", user.number); + + if(!file_exists(qwkfile)) { + file_touch(semfile); + var start = time(); + while(file_exists(semfile)) { + if(js.terminated) + return "503 server terminated"; + if(time() - start >= pack_timeout) + break; + } + if(file_exists(semfile)) { + log(LOG_WARNING, "timeout generating QWK packet: " + qwkfile); + return "503 timeout generating QWK packet"; + } + if(!file_exists(qwkfile)) { + mswait(500); + if(!file_exists(qwkfile)) { + log(LOG_INFO, "No QWK packet created: " + qwkfile); + return "204 No QWK packet created (no new messages?)"; + } + } + } + var file = new File(qwkfile); + if(!file.open("rb")) { + log(LOG_ERR, "error " + file.error + " opening QWK packet: " + file.name); + return "503 failed open QWK packet"; + } + http_reply.header["Content-Type"] = "application/octet-stream"; + http_reply.header["Content-Disposition"] = format('inline; filename="%s.qwk"', system.qwk_id); + while(!file.eof) { + log(LOG_DEBUG, "!eof " + file.name); + var data = file.read(); + if(!data.length) + break; + log(LOG_DEBUG, "read " + data.length + " from " + file.name); + write(data); + log(LOG_DEBUG, "wrote to ringbuf"); + } + log(LOG_DEBUG, "closing " + file.name); + file.close(); + return "200 here's a QWK packet for you"; +} + +function post(query) +{ + log(LOG_INFO, "query: " + JSON.stringify(query)); + if(query["received"]) { + var size = parseInt(query["received"], 10); + var qwksize = file_size(qwkfile); + if(size == qwksize) { + log(LOG_INFO, "Received confirmation of successful QWK packet receipt"); + if(file_remove(qwkfile)) + return "204 Gotcha, QWK packet removed"; + return "503 Could not remove QWK packet!"; + } + log(LOG_WARNING + ,format("Receive mismatch QWK packet receipt size (%lu), expected: %lu", size, qwksize)); + return "400 recipe size mismatch, expected: " + qwksize; + } + + if(!http_request.post_data) { + log(LOG_ERR, "no post data provided"); + return "500 No post data provided"; + } + log(LOG_INFO, "received REP packet: " + http_request.post_data.length + " bytes"); + + var repfile = system.data_dir + format("file/%04u.rep", user.number); + + if(file_exists(repfile)) { + log(LOG_ERR, file.name + " already exists"); + return "409 REP packet already pending"; + } + + var file = new File(repfile); + if(!file.open("wb")) { + log(LOG_ERR, "error " + file.error + " opening REP packet: " + file.name); + return "409 error creating REP packet"; + } + file.write(http_request.post_data); + file.close(); + return "200 bitchen"; +} + +function main() +{ + if(!user.number) { + http_reply.status = "403 Must auth first"; + return; + } + switch(http_request.method) { + case "GET": + http_reply.status = get(http_request.query); + break; + case "POST": + http_reply.status = post(http_request.query); + break; + default: + http_reply.status = "404 method not supported"; + break; + } +} + +main(); +