diff --git a/README.md b/README.md index 83fb50ea..93752343 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ ENiGMA½ is a modern BBS software with a nostalgic flair! * Renegade style pipe color codes * [SQLite](http://sqlite.org/) storage of users, message areas, and so on * Strong [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) backed password encryption - * [Door support](docs/doors.md) including common dropfile formats for legacy DOS doors. Built in [BBSLink](http://bbslink.net/), [DoorParty](http://forums.throwbackbbs.com/), and [Exodus](https://oddnetwork.org/exodus/) support! + * [Door support](docs/doors.md) including common dropfile formats for legacy DOS doors. Built in [BBSLink](http://bbslink.net/), [DoorParty](http://forums.throwbackbbs.com/), [Exodus](https://oddnetwork.org/exodus/) and [CombatNet](http://combatnet.us/) support! * [Bunyan](https://github.com/trentm/node-bunyan) logging * [Message networks](docs/msg_networks.md) with FidoNet Type Network (FTN) + BinkleyTerm Style Outbound (BSO) message import/export * [Gazelle](https://github.com/WhatCD/Gazelle) inspirted File Bases including fast fully indexed full text search (FTS), #tags, and HTTP(S) temporary download URLs using a built in [web server](docs/web_server.md). Legacy X/Y/Z modem also supported! diff --git a/core/combatnet.js b/core/combatnet.js new file mode 100644 index 00000000..6cde9c7b --- /dev/null +++ b/core/combatnet.js @@ -0,0 +1,115 @@ +/* jslint node: true */ +'use strict'; + +// enigma-bbs +const MenuModule = require('../core/menu_module.js').MenuModule; +const resetScreen = require('../core/ansi_term.js').resetScreen; + +// deps +const async = require('async'); +const _ = require('lodash'); +const RLogin = require('rlogin'); + +exports.moduleInfo = { + name : 'CombatNet', + desc : 'CombatNet Access Module', + author : 'Dave Stephens', +}; + +exports.getModule = class CombatNetModule extends MenuModule { + constructor(options) { + super(options); + + // establish defaults + this.config = options.menuConfig.config; + this.config.host = this.config.host || 'bbs.combatnet.us'; + this.config.rloginPort = this.config.rloginPort || 4513; + } + + initSequence() { + const self = this; + + async.series( + [ + function validateConfig(callback) { + if(!_.isString(self.config.password)) { + return callback(new Error('Config requires "password"!')); + } + if(!_.isString(self.config.bbsTag)) { + return callback(new Error('Config requires "bbsTag"!')); + } + return callback(null); + }, + function establishRloginConnection(callback) { + self.client.term.write(resetScreen()); + self.client.term.write('Connecting to CombatNet, please wait...\n'); + + const restorePipeToNormal = function() { + self.client.term.output.removeListener('data', sendToRloginBuffer); + }; + + const rlogin = new RLogin( + { 'clientUsername' : self.config.password, + 'serverUsername' : `${self.config.bbsTag}${self.client.user.username}`, + 'host' : self.config.host, + 'port' : self.config.rloginPort, + 'terminalType' : self.client.term.termClient, + 'terminalSpeed' : 57600 + } + ); + + // If there was an error ... + rlogin.on('error', err => { + self.client.log.info(`CombatNet rlogin client error: ${err.message}`); + restorePipeToNormal(); + callback(err); + }); + + // If we've been disconnected ... + rlogin.on('disconnect', () => { + self.client.log.info(`Disconnected from CombatNet`); + restorePipeToNormal(); + callback(null); + }); + + function sendToRloginBuffer(buffer) { + rlogin.send(buffer); + }; + + rlogin.on("connect", + /* The 'connect' event handler will be supplied with one argument, + a boolean indicating whether or not the connection was established. */ + + function(state) { + if(state) { + self.client.log.info('Connected to CombatNet'); + self.client.term.output.on('data', sendToRloginBuffer); + + } else { + return callback(new Error('Failed to establish establish CombatNet connection')); + } + } + ); + + // If data (a Buffer) has been received from the server ... + rlogin.on("data", (data) => { + self.client.term.rawWrite(data); + }); + + // connect... + rlogin.connect(); + + // note: no explicit callback() until we're finished! + } + ], + err => { + if(err) { + self.client.log.warn( { error : err.message }, 'CombatNet error'); + } + + // if the client is still here, go to previous + self.prevMenu(); + } + ); + } +}; diff --git a/docs/doors.md b/docs/doors.md index 702d75d9..0ca55c23 100644 --- a/docs/doors.md +++ b/docs/doors.md @@ -194,6 +194,22 @@ doorParty: { Fill in `username`, `password`, and `bbsTag` with credentials provided to you and you should be in business! +## The CombatNet Module +The `combatnet` module provides native support for [CombatNet](http://combatnet.us/). Add the following to your menu config: + +````hjson +combatNet: { + desc: Using CombatNet + module: @systemModule:combatnet + config: { + bbsTag: CBNxxx + password: XXXXXXXXX + } +} +```` +Update `bbsTag` (in the format CBNxxx) and `password` with the details provided when you register, then +you should be ready to rock! + # Resources ### DOSBox diff --git a/mods/menu.hjson b/mods/menu.hjson index 0dffdcbb..b445ec85 100644 --- a/mods/menu.hjson +++ b/mods/menu.hjson @@ -1646,6 +1646,10 @@ action: @menu:doorParty } { + value: { command: "CN" } + action: @menu:combatNet + } + { value: { command: "AGENT" } action: @menu:telnetBridgeAgency } @@ -1689,7 +1693,7 @@ } } - // DoorParty! support. You'll need to registger to obtain credentials + // DoorParty! support. You'll need to register to obtain credentials doorParty: { desc: Using DoorParty! module: @systemModule:door_party @@ -1700,6 +1704,16 @@ } } + // CombatNet support. You'll need to register at http://combatnet.us/ to obtain credentials + combatNet: { + desc: Using CombatNet + module: @systemModule:combatnet + config: { + bbsTag: CBNxxx + password: XXXXXXXXX + } + } + telnetBridgeAgency: { desc: Connected to HappyLand BBS module: telnet_bridge diff --git a/package.json b/package.json index 232e1dca..29bd16da 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "node-glob": "^1.2.0", "nodemailer": "^4.1.0", "ptyw.js": "NuSkooler/ptyw.js", + "rlogin": "^1.0.0", "sane": "^2.2.0", "sanitize-filename": "^1.6.1", "sqlite3": "^3.1.9",