dockerized_openAger/nodered/rootfs/data/node_modules/mailsplit/lib/mime-node.js
2020-10-17 18:42:50 +02:00

236 lines
7.3 KiB
JavaScript

'use strict';
const Headers = require('./headers');
const libmime = require('libmime');
const libqp = require('libqp');
const libbase64 = require('libbase64');
const PassThrough = require('stream').PassThrough;
class MimeNode {
constructor(parentNode, config) {
this.type = 'node';
this.root = !parentNode;
this.parentNode = parentNode;
this._parentBoundary = this.parentNode && this.parentNode._boundary;
this._headersLines = [];
this._headerlen = 0;
this._parsedContentType = false;
this._boundary = false;
this.multipart = false;
this.encoding = false;
this.headers = false;
this.contentType = false;
this.flowed = false;
this.delSp = false;
this.config = config || {};
this.libmime = new libmime.Libmime({ Iconv: this.config.Iconv });
this.parentPartNumber = (parentNode && this.partNr) || [];
this.partNr = false; // resolved later
this.childPartNumbers = 0;
}
getPartNr(provided) {
if (provided) {
return []
.concat(this.partNr || [])
.filter(nr => !isNaN(nr))
.concat(provided);
}
let childPartNr = ++this.childPartNumbers;
return []
.concat(this.partNr || [])
.filter(nr => !isNaN(nr))
.concat(childPartNr);
}
addHeaderChunk(line) {
if (!line) {
return;
}
this._headersLines.push(line);
this._headerlen += line.length;
}
parseHeaders() {
if (this.headers) {
return;
}
this.headers = new Headers(Buffer.concat(this._headersLines, this._headerlen), this.config);
this._parsedContentType = this.libmime.parseHeaderValue(this.headers.getFirst('Content-Type'));
this._parsedContentDisposition = this.libmime.parseHeaderValue(this.headers.getFirst('Content-Disposition'));
this.encoding = this.headers
.getFirst('Content-Transfer-Encoding')
.replace(/\(.*\)/g, '')
.toLowerCase()
.trim();
this.contentType = (this._parsedContentType.value || '').toLowerCase().trim() || false;
this.charset = this._parsedContentType.params.charset || false;
this.disposition = (this._parsedContentDisposition.value || '').toLowerCase().trim() || false;
this.filename = this._parsedContentDisposition.params.filename || this._parsedContentType.params.name || false;
if (this._parsedContentType.params.format && this._parsedContentType.params.format.toLowerCase().trim() === 'flowed') {
this.flowed = true;
if (this._parsedContentType.params.delsp && this._parsedContentType.params.delsp.toLowerCase().trim() === 'yes') {
this.delSp = true;
}
}
if (this.filename) {
try {
this.filename = this.libmime.decodeWords(this.filename);
} catch (E) {
// failed to parse filename, keep as is (most probably an unknown charset is used)
}
}
this.multipart =
(this.contentType &&
this.contentType.substr(0, this.contentType.indexOf('/')) === 'multipart' &&
this.contentType.substr(this.contentType.indexOf('/') + 1)) ||
false;
this._boundary = (this._parsedContentType.params.boundary && Buffer.from(this._parsedContentType.params.boundary)) || false;
this.rfc822 = this.contentType === 'message/rfc822';
if (!this.parentNode || this.parentNode.rfc822) {
this.partNr = this.parentNode ? this.parentNode.getPartNr('TEXT') : ['TEXT'];
} else {
this.partNr = this.parentNode ? this.parentNode.getPartNr() : [];
}
}
getHeaders() {
if (!this.headers) {
this.parseHeaders();
}
return this.headers.build();
}
setContentType(contentType) {
if (!this.headers) {
this.parseHeaders();
}
contentType = (contentType || '').toLowerCase().trim();
if (contentType) {
this._parsedContentType.value = contentType;
}
if (!this.flowed && this._parsedContentType.params.format) {
delete this._parsedContentType.params.format;
}
if (!this.delSp && this._parsedContentType.params.delsp) {
delete this._parsedContentType.params.delsp;
}
this.headers.update('Content-Type', this.libmime.buildHeaderValue(this._parsedContentType));
}
setCharset(charset) {
if (!this.headers) {
this.parseHeaders();
}
charset = (charset || '').toLowerCase().trim();
if (charset === 'ascii') {
charset = '';
}
if (!charset) {
if (!this._parsedContentType.value) {
// nothing to set or update
return;
}
delete this._parsedContentType.params.charset;
} else {
this._parsedContentType.params.charset = charset;
}
if (!this._parsedContentType.value) {
this._parsedContentType.value = 'text/plain';
}
this.headers.update('Content-Type', this.libmime.buildHeaderValue(this._parsedContentType));
}
setFilename(filename) {
if (!this.headers) {
this.parseHeaders();
}
this.filename = (filename || '').toLowerCase().trim();
if (this._parsedContentType.params.name) {
delete this._parsedContentType.params.name;
this.headers.update('Content-Type', this.libmime.buildHeaderValue(this._parsedContentType));
}
if (!this.filename) {
if (!this._parsedContentDisposition.value) {
// nothing to set or update
return;
}
delete this._parsedContentDisposition.params.filename;
} else {
this._parsedContentDisposition.params.filename = this.filename;
}
if (!this._parsedContentDisposition.value) {
this._parsedContentDisposition.value = 'attachment';
}
this.headers.update('Content-Disposition', this.libmime.buildHeaderValue(this._parsedContentDisposition));
}
getDecoder() {
if (!this.headers) {
this.parseHeaders();
}
switch (this.encoding) {
case 'base64':
return new libbase64.Decoder();
case 'quoted-printable':
return new libqp.Decoder();
default:
return new PassThrough();
}
}
getEncoder(encoding) {
if (!this.headers) {
this.parseHeaders();
}
encoding = (encoding || '')
.toString()
.toLowerCase()
.trim();
if (encoding && encoding !== this.encoding) {
this.headers.update('Content-Transfer-Encoding', encoding);
} else {
encoding = this.encoding;
}
switch (encoding) {
case 'base64':
return new libbase64.Encoder();
case 'quoted-printable':
return new libqp.Encoder();
default:
return new PassThrough();
}
}
}
module.exports = MimeNode;