2019-11-21 22:15:25 +08:00
|
|
|
'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')
|
2021-04-16 18:29:52 +08:00
|
|
|
.find({ 'metadata.audit': audit }, { noCursorTimeout: true })
|
2019-11-21 22:15:25 +08:00
|
|
|
.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()
|
2019-11-21 22:23:18 +08:00
|
|
|
.then(() => {
|
2019-11-21 22:15:25 +08:00
|
|
|
try {
|
2019-11-21 22:23:18 +08:00
|
|
|
outputStream.end();
|
2019-11-21 22:15:25 +08:00
|
|
|
} catch (err) {
|
2019-11-21 22:23:18 +08:00
|
|
|
// ignore at this point
|
2019-11-21 22:15:25 +08:00
|
|
|
}
|
|
|
|
})
|
2019-11-21 22:23:18 +08:00
|
|
|
.catch(err => {
|
2019-11-21 22:15:25 +08:00
|
|
|
try {
|
2019-11-21 22:23:18 +08:00
|
|
|
outputStream.end('\n' + err.message);
|
2019-11-21 22:15:25 +08:00
|
|
|
} catch (err) {
|
2019-11-21 22:23:18 +08:00
|
|
|
//ignore
|
2019-11-21 22:15:25 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
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;
|