Add oputil fb desc

This commit is contained in:
Bryan Ashby 2018-12-21 14:39:57 -07:00
parent f4088303ca
commit c6e176f5bd
5 changed files with 113 additions and 18 deletions

View File

@ -41,7 +41,8 @@ This document attempts to track **major** changes and additions in ENiGMA½. For
* Correly parse oddball `INTL`, `TOPT`, `FMPT`, `Via`, etc. FTN kludge lines * Correly parse oddball `INTL`, `TOPT`, `FMPT`, `Via`, etc. FTN kludge lines
* NetMail support! You can now send and receive NetMail. To send a NetMail address a external user using `Name <address>` format from your personal email menu. For example, `Foo Bar <123:123/123>`. The system also detects other formats such asa `Name @ address` (`Foo Bar@123:123/123`) * NetMail support! You can now send and receive NetMail. To send a NetMail address a external user using `Name <address>` format from your personal email menu. For example, `Foo Bar <123:123/123>`. The system also detects other formats such asa `Name @ address` (`Foo Bar@123:123/123`)
* `oputil.js`: Added `mb areafix` command to quickly send AreaFix messages from the command line. You can manually send them from personal mail as well. * `oputil.js`: Added `mb areafix` command to quickly send AreaFix messages from the command line. You can manually send them from personal mail as well.
* `oputil.js fb rm|remove|del|delete` functionality to remove file base entries * `oputil.js fb rm|remove|del|delete` functionality to remove file base entries.
* `oputil.js fb desc` for setting/updating a file entry description.
* Users can now (re)set File and Message base pointers * Users can now (re)set File and Message base pointers
* Add `--update` option to `oputil.js fb scan` * Add `--update` option to `oputil.js fb scan`
* Fix @watch path support for event scheduler including FTN, e.g. when looking for a `toss!.now` file produced by Binkd. * Fix @watch path support for event scheduler including FTN, e.g. when looking for a `toss!.now` file produced by Binkd.

View File

@ -8,6 +8,12 @@ const fs = require('graceful-fs');
const iconv = require('iconv-lite'); const iconv = require('iconv-lite');
const moment = require('moment'); const moment = require('moment');
// Descriptions found in the wild that mean "no description" /facepalm.
const IgnoredDescriptions = [
'No description available',
'No ID File Found For This Archive File.',
];
module.exports = class FilesBBSFile { module.exports = class FilesBBSFile {
constructor() { constructor() {
this.entries = new Map(); this.entries = new Map();
@ -34,6 +40,10 @@ module.exports = class FilesBBSFile {
const lines = iconv.decode(descData, 'cp437').split(/\r?\n/g); const lines = iconv.decode(descData, 'cp437').split(/\r?\n/g);
const filesBbs = new FilesBBSFile(); const filesBbs = new FilesBBSFile();
const isBadDescription = (desc) => {
return IgnoredDescriptions.find(d => desc.startsWith(d)) ? true : false;
};
// //
// Contrary to popular belief, there is not a FILES.BBS standard. Instead, // Contrary to popular belief, there is not a FILES.BBS standard. Instead,
// many formats have been used over the years. We'll try to support as much // many formats have been used over the years. We'll try to support as much
@ -84,7 +94,7 @@ module.exports = class FilesBBSFile {
const fileName = hdr[1]; const fileName = hdr[1];
const timestamp = moment(hdr[2], 'MM/DD/YY'); const timestamp = moment(hdr[2], 'MM/DD/YY');
if(!timestamp.isValid()) { if(isBadDescription(desc) || !timestamp.isValid()) {
continue; continue;
} }
filesBbs.entries.set(fileName, { timestamp, desc } ); filesBbs.entries.set(fileName, { timestamp, desc } );
@ -121,6 +131,10 @@ module.exports = class FilesBBSFile {
const desc = long.join('\r\n'); const desc = long.join('\r\n');
const fileName = hdr[1]; const fileName = hdr[1];
if(isBadDescription(desc)) {
continue;
}
filesBbs.entries.set(fileName, { desc } ); filesBbs.entries.set(fileName, { desc } );
} }
} }
@ -157,6 +171,10 @@ module.exports = class FilesBBSFile {
const desc = long.join('\r\n'); const desc = long.join('\r\n');
const fileName = hdr[1]; const fileName = hdr[1];
if(isBadDescription(desc)) {
continue;
}
filesBbs.entries.set(fileName, { desc } ); filesBbs.entries.set(fileName, { desc } );
} }
} }
@ -182,10 +200,6 @@ module.exports = class FilesBBSFile {
} }
const firstDescLine = hdr[4].trimRight(); const firstDescLine = hdr[4].trimRight();
// ugly kludge:
if('No ID File Found For This Archive File.' === firstDescLine) {
continue;
}
const long = [ firstDescLine ]; const long = [ firstDescLine ];
for(let j = i + 1; j < lines.length; ++j) { for(let j = i + 1; j < lines.length; ++j) {
line = lines[j]; line = lines[j];
@ -201,7 +215,7 @@ module.exports = class FilesBBSFile {
const size = parseInt(hdr[2]); const size = parseInt(hdr[2]);
const timestamp = moment(hdr[3], 'MM-DD-YY'); const timestamp = moment(hdr[3], 'MM-DD-YY');
if(isNaN(size) || !timestamp.isValid()) { if(isBadDescription(desc) || isNaN(size) || !timestamp.isValid()) {
continue; continue;
} }
@ -235,7 +249,7 @@ module.exports = class FilesBBSFile {
const fileName = hdr[1].trim(); const fileName = hdr[1].trim();
const desc = hdr[2].trim(); const desc = hdr[2].trim();
if(desc) { if(desc && !isBadDescription(desc)) {
filesBbs.entries.set(fileName, { desc } ); filesBbs.entries.set(fileName, { desc } );
} }
}); });

View File

@ -413,11 +413,11 @@ function dumpFileInfo(shaOrFileId, cb) {
); );
} }
function displayFileAreaInfo() { function displayFileOrAreaInfo() {
// AREA_TAG[@STORAGE_TAG] // AREA_TAG[@STORAGE_TAG]
// SHA256|PARTIAL // SHA256|PARTIAL|FILE_ID|FILENAME_WILDCARD
// if sha: dump file info // if sha: dump file info
// if area/stoarge dump area(s) + // if area/storage dump area(s) +
async.series( async.series(
[ [
@ -908,6 +908,75 @@ function importFileAreas() {
); );
} }
function setFileDescription() {
//
// ./oputil.js fb set-desc CRITERIA # will prompt
// ./oputil.js fb set-desc CRITERIA "The new description"
//
let fileCriteria;
let desc;
if(argv._.length > 3) {
fileCriteria = argv._[argv._.length - 2];
desc = argv._[argv._.length - 1];
} else {
fileCriteria = argv._[argv._.length - 1];
}
async.waterfall(
[
(callback) => {
return initConfigAndDatabases(callback);
},
(callback) => {
getFileEntries(fileCriteria, (err, entries) => {
if(err) {
return callback(err);
}
if(entries.length > 1) {
return callback(Errors.General('Criteria not specific enough.'));
}
return callback(null, entries[0]);
});
},
(fileEntry, callback) => {
if(desc) {
return callback(null, fileEntry, desc);
}
getAnswers([
{
name : 'userDesc',
message : 'Description:',
type : 'editor',
}
],
answers => {
if(!answers.userDesc) {
return callback(Errors.General('User canceled'));
}
return callback(null, fileEntry, answers.userDesc);
});
},
(fileEntry, newDesc, callback) => {
fileEntry.desc = newDesc;
fileEntry.persist(true, err => { // true=isUpdate
return callback(err);
});
}
],
err => {
if(err) {
process.exitCode = ExitCodes.ERROR;
console.error(err.message);
} else {
console.info('Description updated.');
}
}
);
}
function handleFileBaseCommand() { function handleFileBaseCommand() {
function errUsage() { function errUsage() {
@ -924,7 +993,7 @@ function handleFileBaseCommand() {
const action = argv._[1]; const action = argv._[1];
return ({ return ({
info : displayFileAreaInfo, info : displayFileOrAreaInfo,
scan : scanFileAreas, scan : scanFileAreas,
mv : moveFiles, mv : moveFiles,
@ -936,5 +1005,8 @@ function handleFileBaseCommand() {
delete : removeFiles, delete : removeFiles,
'import-areas' : importFileAreas, 'import-areas' : importFileAreas,
desc : setFileDescription,
description : setFileDescription,
}[action] || errUsage)(); }[action] || errUsage)();
} }

View File

@ -57,9 +57,7 @@ actions:
for example: scan some_area *.zip for example: scan some_area *.zip
info CRITERIA display information about areas and/or files info CRITERIA display information about areas and/or files
where CRITERIA is one of the following: matching CRITERIA.
AREA_TAG|SHA|FILE_ID|FILENAME_WC
SHA may be a full or partial SHA-256
mv SRC [SRC...] DST move entry(s) from SRC to DST mv SRC [SRC...] DST move entry(s) from SRC to DST
SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG] SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG]
@ -67,6 +65,9 @@ actions:
rm SRC [SRC...] remove entry(s) from the system matching SRC rm SRC [SRC...] remove entry(s) from the system matching SRC
SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG] SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG]
desc CRITERIA sets a new file description for file base entry
matching CRITERIA. Launches an external editor using
$VISUAL, $EDITOR, or vim/notepad.
import-areas FILEGATE.ZXX import file base areas using FileGate RAID type format import-areas FILEGATE.ZXX import file base areas using FileGate RAID type format
scan args: scan args:
@ -94,6 +95,9 @@ general information:
AREA_TAG[@STORAGE_TAG] can specify an area tag and optionally, a storage specific tag AREA_TAG[@STORAGE_TAG] can specify an area tag and optionally, a storage specific tag
example: retro@bbs example: retro@bbs
CRITERIA file base entry criteria. in general, can be AREA_TAG, SHA,
FILE_ID, or FILENAME_WC.
FILENAME_WC filename with * and ? wildcard support. may match 0:n entries FILENAME_WC filename with * and ? wildcard support. may match 0:n entries
SHA full or partial SHA-256 SHA full or partial SHA-256
FILE_ID a file identifier. see file.sqlite3 FILE_ID a file identifier. see file.sqlite3

View File

@ -99,9 +99,7 @@ actions:
for example: scan some_area *.zip for example: scan some_area *.zip
info CRITERIA display information about areas and/or files info CRITERIA display information about areas and/or files
where CRITERIA is one of the following: matching CRITERIA.
AREA_TAG|SHA|FILE_ID|FILENAME_WC
SHA may be a full or partial SHA-256
mv SRC [SRC...] DST move entry(s) from SRC to DST mv SRC [SRC...] DST move entry(s) from SRC to DST
SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG] SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG]
@ -109,6 +107,9 @@ actions:
rm SRC [SRC...] remove entry(s) from the system matching SRC rm SRC [SRC...] remove entry(s) from the system matching SRC
SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG] SRC: FILENAME_WC|SHA|FILE_ID|AREA_TAG[@STORAGE_TAG]
desc CRITERIA sets a new file description for file base entry
matching CRITERIA. Launches an external editor using
$VISUAL, $EDITOR, or vim/notepad.
import-areas FILEGATE.ZXX import file base areas using FileGate RAID type format import-areas FILEGATE.ZXX import file base areas using FileGate RAID type format
scan args: scan args:
@ -134,6 +135,9 @@ general information:
AREA_TAG[@STORAGE_TAG] can specify an area tag and optionally, a storage specific tag AREA_TAG[@STORAGE_TAG] can specify an area tag and optionally, a storage specific tag
example: retro@bbs example: retro@bbs
CRITERIA file base entry criteria. in general, can be AREA_TAG, SHA,
FILE_ID, or FILENAME_WC.
FILENAME_WC filename with * and ? wildcard support. may match 0:n entries FILENAME_WC filename with * and ? wildcard support. may match 0:n entries
SHA full or partial SHA-256 SHA full or partial SHA-256
FILE_ID a file identifier. see file.sqlite3 FILE_ID a file identifier. see file.sqlite3