enigma-bbs/core/transfer_file.js

133 lines
3.3 KiB
JavaScript

/* jslint node: true */
'use strict';
// enigma-bbs
const MenuModule = require('./menu_module.js').MenuModule;
const Config = require('./config.js').config;
const stringFormat = require('./string_format.js');
// deps
const async = require('async');
const _ = require('lodash');
const pty = require('ptyw.js');
/*
Resources
ZModem
* http://gallium.inria.fr/~doligez/zmodem/zmodem.txt
* https://github.com/protomouse/synchronet/blob/master/src/sbbs3/zmodem.c
*/
exports.moduleInfo = {
name : 'Transfer file',
desc : 'Sends or receives a file(s)',
author : 'NuSkooler',
};
exports.getModule = class TransferFileModule extends MenuModule {
constructor(options) {
super(options);
this.config = this.menuConfig.config || {};
this.config.protocol = this.config.protocol || 'zmodem8kSz';
this.config.direction = this.config.direction || 'send';
this.protocolConfig = Config.fileTransferProtocols[this.config.protocol];
// :TODO: bring in extraArgs for path(s) to send when sending; Allow to hard code in config (e.g. for info pack/static downloads)
}
restorePipeAfterExternalProc(pipe) {
if(!this.pipeRestored) {
this.pipeRestored = true;
this.client.term.output.unpipe(pipe);
this.client.term.output.resume();
}
}
sendFiles(cb) {
async.eachSeries(this.sendQueue, (filePath, next) => {
// :TODO: built in protocols
// :TODO: use protocol passed in
this.executeExternalProtocolHandler(filePath, err => {
return next(err);
});
}, err => {
return cb(err);
});
}
executeExternalProtocolHandler(filePath, cb) {
const external = this.protocolConfig.external;
const cmd = external[`${this.config.direction}Cmd`];
const args = external[`${this.config.direction}Args`].map(arg => {
return stringFormat(arg, {
filePath : filePath,
});
});
/*this.client.term.rawWrite(new Buffer(
[
255, 253, 0, // IAC DO TRANSMIT_BINARY
255, 251, 0, // IAC WILL TRANSMIT_BINARY
]
));*/
const externalProc = pty.spawn(cmd, args, {
cols : this.client.term.termWidth,
rows : this.client.term.termHeight,
// :TODO: cwd
// :TODO: anything else??
//env : self.exeInfo.env,
});
this.client.term.output.pipe(externalProc);
/*this.client.term.output.on('data', data => {
// let tmp = data.toString('binary').replace(/\xff\xff/g, '\xff');
// proc.write(new Buffer(tmp, 'binary'));
proc.write(data);
});
*/
externalProc.on('data', data => {
// needed for things like sz/rz
if(external.escapeTelnet) {
const tmp = data.toString('binary').replace(/\xff/g, '\xff\xff');
this.client.term.rawWrite(new Buffer(tmp, 'binary'));
} else {
this.client.term.rawWrite(data);
}
});
externalProc.once('close', () => {
return this.restorePipeAfterExternalProc(externalProc);
});
externalProc.once('exit', exitCode => {
this.restorePipeAfterExternalProc(externalProc);
externalProc.removeAllListeners();
return cb(null);
});
}
initSequence() {
const self = this;
async.series(
[
function validateConfig(callback) {
// :TODO:
return callback(null);
},
function transferFiles(callback) {
self.sendQueue = [ '/home/nuskooler/Downloads/fdoor100.zip' ]; // :TODO: testing of course
return self.sendFiles(callback);
}
]
);
}
};