wildduck/lib/mbox-export.js
2019-11-21 16:23:18 +02:00

114 lines
3.8 KiB
JavaScript

'use strict';
const log = require('npmlog');
const Newlines = require('./newlines');
const MboxStream = require('./mbox-stream');
const HeaderSplitter = require('./header-splitter');
const PassThrough = require('stream').PassThrough;
async function mboxExport(auditHandler, audit) {
let outputStream = new PassThrough();
let processExport = async () => {
let cursor = await auditHandler.gridfs
.collection('audit.files')
.find({ 'metadata.audit': audit })
.project({ _id: true, metadata: true })
.sort({ 'metadata.date': 1 });
let messageData;
let counter = 0;
while ((messageData = await cursor.next())) {
try {
let sourceStream = await auditHandler.retrieve(messageData._id);
if (!sourceStream) {
log.error('Audit', `Missing source for ${messageData._id} from ${audit}`);
continue;
}
await writeEmailToMboxStream(sourceStream, outputStream, {
from: messageData.metadata && messageData.metadata.info && messageData.metadata.info.from,
date: messageData.metadata && ((messageData.metadata.info && messageData.metadata.info.time) || messageData.metadata.date),
draft: !!(messageData.metadata && messageData.metadata.draft),
mailboxPath: messageData.metadata && messageData.metadata.mailboxPath
});
counter++;
} catch (err) {
// ignore?
log.error('Audit', `Failed exporting ${messageData._id} from ${audit}: ${err.message}`);
}
}
log.error('Audit', `Exported ${counter} messages from ${audit}`);
await cursor.close();
};
setImmediate(() => {
processExport()
.then(() => {
try {
outputStream.end();
} catch (err) {
// ignore at this point
}
})
.catch(err => {
try {
outputStream.end('\n' + err.message);
} catch (err) {
//ignore
}
});
});
return outputStream;
}
async function writeEmailToMboxStream(sourceStream, outputStream, mboxOptions) {
await new Promise((resolve, reject) => {
let headerSplitter = new HeaderSplitter();
mboxOptions = mboxOptions || {};
let newlines = new Newlines();
let mboxStream = new MboxStream(mboxOptions);
sourceStream.once('error', err => {
sourceStream.unpipe(headerSplitter);
mboxStream.unpipe(outputStream);
reject(err);
});
mboxStream.once('end', () => resolve());
headerSplitter.on('headers', data => {
data.headers.remove('X-Export-Draft');
if (mboxOptions.draft) {
data.headers.add('X-Export-Draft', 'Yes', 0);
}
data.headers.remove('X-Export-Mailbox');
if (mboxOptions.mailboxPath) {
data.headers.add('X-Export-Mailbox', mboxOptions.mailboxPath, 0);
}
// remove existing MBOX headers
data.headers.remove('Content-Length');
data.headers.remove('X-Status');
data.headers.remove('Status');
data.headers.remove('X-GM-THRID');
data.headers.remove('X-Gmail-Labels');
return data.done();
});
sourceStream
.pipe(headerSplitter)
// remove 0x0D, keep 0x0A
.pipe(newlines)
.pipe(mboxStream)
.pipe(outputStream, {
end: false
});
});
}
module.exports = mboxExport;