diff --git a/core/servers/content/gopher.js b/core/servers/content/gopher.js index 240236d1..37cd9adb 100644 --- a/core/servers/content/gopher.js +++ b/core/servers/content/gopher.js @@ -17,6 +17,7 @@ const { } = require('../../message_area.js'); const { sortAreasOrConfs } = require('../../conf_area_util.js'); const AnsiPrep = require('../../ansi_prep.js'); +const { wordWrapText } = require('../../word_wrap.js'); // deps const net = require('net'); @@ -27,9 +28,10 @@ const moment = require('moment'); const ModuleInfo = exports.moduleInfo = { name : 'Gopher', - desc : 'Gopher Server', + desc : 'A RFC-1436-ish Gopher Server', author : 'NuSkooler', packageName : 'codes.l33t.enigma.gopher.server', + notes : 'https://tools.ietf.org/html/rfc1436', }; const Message = require('../../message.js'); @@ -158,7 +160,7 @@ exports.getModule = class GopherModule extends ServerModule { defaultGenerator(selectorMatch, cb) { this.log.debug( { selector : selectorMatch[0] }, 'Serving default content'); - let bannerFile = _.get(Config(), 'contentServers.gopher.bannerFile', 'startup_banner.asc'); + let bannerFile = _.get(Config(), 'contentServers.gopher.bannerFile', 'gopher_banner.asc'); bannerFile = paths.isAbsolute(bannerFile) ? bannerFile : paths.join(__dirname, '../../../misc', bannerFile); fs.readFile(bannerFile, 'utf8', (err, banner) => { if(err) { @@ -182,21 +184,43 @@ exports.getModule = class GopherModule extends ServerModule { } prepareMessageBody(body, cb) { + // + // From RFC-1436: + // "User display strings are intended to be displayed on a line on a + // typical screen for a user's viewing pleasure. While many screens can + // accommodate 80 character lines, some space is needed to display a tag + // of some sort to tell the user what sort of item this is. Because of + // this, the user display string should be kept under 70 characters in + // length. Clients may truncate to a length convenient to them." + // + // Messages on BBSes however, have generally been <= 79 characters. If we + // start wrapping earlier, things will generally be OK except: + // * When we're doing with FTN-style quoted lines + // * When dealing with ANSI/ASCII art + // + // Anyway, the spec says "should" and not MUST or even SHOULD! ...so, to + // to follow the KISS principle: Wrap at 79. + // + const WordWrapColumn = 79; if(isAnsi(body)) { AnsiPrep( body, { - cols : 79, // Gopher std. wants 70, but we'll have to deal with it. - forceLineTerm : true, // ensure each line is term'd - asciiMode : true, // export to ASCII - fillLines : false, // don't fill up to |cols| + cols : WordWrapColumn, // See notes above + forceLineTerm : true, // Ensure each line is term'd + asciiMode : true, // Export to ASCII + fillLines : false, // Don't fill up to |cols| }, (err, prepped) => { return cb(prepped || body); } ); } else { - return cb(cleanControlCodes(body, { all : true } )); + const prepped = splitTextAtTerms(cleanControlCodes(body, { all : true } ) ) + .map(l => (wordWrapText(l, { width : WordWrapColumn } ).wrapped || []).join('\n')) + .join('\n'); + + return cb(prepped); } } diff --git a/misc/config_template.in.hjson b/misc/config_template.in.hjson index 8a474779..ab1b37b8 100644 --- a/misc/config_template.in.hjson +++ b/misc/config_template.in.hjson @@ -211,6 +211,9 @@ port: XXXXX enabled: false + // bannerFile path in misc/ by default. Full paths allowed. + bannerFile: XXXXX + // // The Gopher Content Server can export message base // conferences and areas via the "messageConferences" key. diff --git a/misc/gopher_banner.asc b/misc/gopher_banner.asc new file mode 100644 index 00000000..b758e066 --- /dev/null +++ b/misc/gopher_banner.asc @@ -0,0 +1,9 @@ +_____________________ _____ ____________________ __________\_ / +\__ ____/\_ ____ \ /____/ / _____ __ \ / ______/ // /___jp! +// __|___// | \// |// | \// | | \// \ /___ /_____ +/____ _____| __________ ___|__| ____| \ / _____ \ +---- \______\ -- |______\ ------ /______/ ---- |______\ - |______\ /__/ // ___/ + /__ _\ + <*> ENiGMA½ // HTTPS://GITHUB.COM/NUSKOOLER/ENIGMA-BBS <*> /__/ + +-------------------------------------------------------------------------------