@mavogel/awscdk-rootmail 0.1.27 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +8 -8
- package/lib/rootmail.js +1 -1
- package/lib/ses-receive.js +1 -1
- package/node_modules/@aws-sdk/checksums/package.json +4 -4
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/CloudWatchLogsClient.d.ts +2 -1
- package/node_modules/@aws-sdk/client-cloudwatch-logs/package.json +5 -5
- package/node_modules/@aws-sdk/client-route-53/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-route-53/dist-types/Route53Client.d.ts +2 -1
- package/node_modules/@aws-sdk/client-route-53/package.json +6 -6
- package/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-s3/dist-types/S3Client.d.ts +2 -1
- package/node_modules/@aws-sdk/client-s3/package.json +9 -9
- package/node_modules/@aws-sdk/client-ses/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-ses/dist-types/SESClient.d.ts +2 -1
- package/node_modules/@aws-sdk/client-ses/package.json +5 -5
- package/node_modules/@aws-sdk/client-ssm/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-ssm/dist-types/SSMClient.d.ts +2 -1
- package/node_modules/@aws-sdk/client-ssm/package.json +5 -5
- package/node_modules/@aws-sdk/core/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-env/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-http/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-ini/package.json +11 -11
- package/node_modules/@aws-sdk/credential-provider-login/package.json +5 -5
- package/node_modules/@aws-sdk/credential-provider-node/package.json +9 -9
- package/node_modules/@aws-sdk/credential-provider-process/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-sso/package.json +6 -6
- package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +5 -5
- package/node_modules/@aws-sdk/middleware-sdk-route53/package.json +2 -2
- package/node_modules/@aws-sdk/middleware-sdk-s3/package.json +5 -5
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/cognito-identity/CognitoIdentityClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/signin/SigninClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso/SSOClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso-oidc/SSOOIDCClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sts/STSClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/package.json +5 -5
- package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +2 -2
- package/node_modules/@aws-sdk/token-providers/package.json +5 -5
- package/node_modules/@aws-sdk/types/dist-types/feature-ids.d.ts +3 -0
- package/node_modules/@aws-sdk/types/dist-types/ts3.4/feature-ids.d.ts +3 -0
- package/node_modules/@aws-sdk/types/package.json +1 -1
- package/node_modules/@smithy/core/dist-cjs/submodules/client/index.js +15 -2
- package/node_modules/@smithy/core/dist-cjs/submodules/event-streams/index.browser.js +10 -0
- package/node_modules/@smithy/core/dist-cjs/submodules/event-streams/index.js +10 -0
- package/node_modules/@smithy/core/dist-cjs/submodules/protocols/index.js +5 -5
- package/node_modules/@smithy/core/dist-es/submodules/client/smithy-client/command.js +16 -2
- package/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/HeaderMarshaller.js +10 -0
- package/node_modules/@smithy/core/dist-es/submodules/protocols/json/codec-v2/JsonShapeSerializer2.js +5 -5
- package/node_modules/@smithy/core/package.json +1 -1
- package/node_modules/@zone-eu/mailsplit/lib/message-splitter.js +39 -27
- package/node_modules/@zone-eu/mailsplit/lib/mime-node.d.ts +1 -1
- package/node_modules/@zone-eu/mailsplit/lib/mime-node.js +38 -61
- package/node_modules/@zone-eu/mailsplit/lib/types.d.ts +1 -1
- package/node_modules/@zone-eu/mailsplit/package.json +2 -2
- package/node_modules/libmime/CHANGELOG.md +36 -0
- package/node_modules/libmime/README.md +40 -3
- package/node_modules/libmime/dist/cjs/charset.d.ts +36 -0
- package/node_modules/libmime/dist/cjs/charset.js +165 -2
- package/node_modules/libmime/dist/cjs/charsets.js +8 -2
- package/node_modules/libmime/dist/cjs/libmime.d.ts +20 -3
- package/node_modules/libmime/dist/cjs/libmime.js +100 -6
- package/node_modules/libmime/dist/cjs/types.d.ts +28 -0
- package/node_modules/libmime/dist/esm/charset.d.ts +36 -0
- package/node_modules/libmime/dist/esm/charset.js +162 -2
- package/node_modules/libmime/dist/esm/charsets.js +8 -2
- package/node_modules/libmime/dist/esm/libmime.d.ts +20 -3
- package/node_modules/libmime/dist/esm/libmime.js +100 -6
- package/node_modules/libmime/dist/esm/types.d.ts +28 -0
- package/node_modules/libmime/package.json +3 -3
- package/node_modules/mailparser/CHANGELOG.md +51 -0
- package/node_modules/mailparser/README.md +32 -1
- package/node_modules/mailparser/dist/cjs/address-header.d.ts +19 -0
- package/node_modules/mailparser/dist/cjs/address-header.js +185 -0
- package/node_modules/mailparser/dist/cjs/index.d.ts +3 -1
- package/node_modules/mailparser/dist/cjs/index.js +4 -2
- package/node_modules/mailparser/dist/cjs/mail-parser.js +36 -183
- package/node_modules/mailparser/dist/cjs/stream-hash.d.ts +5 -4
- package/node_modules/mailparser/dist/cjs/stream-hash.js +8 -5
- package/node_modules/mailparser/dist/cjs/types.d.ts +33 -6
- package/node_modules/mailparser/dist/esm/address-header.d.ts +19 -0
- package/node_modules/mailparser/dist/esm/address-header.js +176 -0
- package/node_modules/mailparser/dist/esm/index.d.ts +3 -1
- package/node_modules/mailparser/dist/esm/index.js +3 -2
- package/node_modules/mailparser/dist/esm/mail-parser.js +36 -183
- package/node_modules/mailparser/dist/esm/stream-hash.d.ts +5 -4
- package/node_modules/mailparser/dist/esm/stream-hash.js +8 -5
- package/node_modules/mailparser/dist/esm/types.d.ts +33 -6
- package/node_modules/mailparser/package.json +6 -7
- package/node_modules/nodemailer/CHANGELOG.md +23 -0
- package/node_modules/nodemailer/dist/cjs/addressparser/index.js +2 -5
- package/node_modules/nodemailer/dist/cjs/dkim/index.js +1 -3
- package/node_modules/nodemailer/dist/cjs/errors.d.ts +19 -0
- package/node_modules/nodemailer/dist/cjs/errors.js +14 -1
- package/node_modules/nodemailer/dist/cjs/fetch/cookies.js +2 -4
- package/node_modules/nodemailer/dist/cjs/fetch/index.js +2 -8
- package/node_modules/nodemailer/dist/cjs/mail-composer/index.js +42 -9
- package/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +5 -6
- package/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +18 -1
- package/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +43 -1
- package/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.js +3 -12
- package/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +34 -1
- package/node_modules/nodemailer/dist/cjs/mime-node/index.js +40 -15
- package/node_modules/nodemailer/dist/cjs/package-info.d.ts +1 -1
- package/node_modules/nodemailer/dist/cjs/package-info.js +1 -1
- package/node_modules/nodemailer/dist/cjs/qp/index.js +3 -12
- package/node_modules/nodemailer/dist/cjs/sendmail-transport/index.js +1 -3
- package/node_modules/nodemailer/dist/cjs/shared/index.js +2 -6
- package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +1 -1
- package/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +6 -0
- package/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +15 -12
- package/node_modules/nodemailer/dist/cjs/smtp-connection/server-message-id.d.ts +14 -0
- package/node_modules/nodemailer/dist/cjs/smtp-connection/server-message-id.js +53 -0
- package/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +11 -0
- package/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +25 -1
- package/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +2 -5
- package/node_modules/nodemailer/dist/esm/addressparser/index.js +2 -5
- package/node_modules/nodemailer/dist/esm/dkim/index.js +1 -3
- package/node_modules/nodemailer/dist/esm/errors.d.ts +19 -0
- package/node_modules/nodemailer/dist/esm/errors.js +12 -0
- package/node_modules/nodemailer/dist/esm/fetch/cookies.js +2 -4
- package/node_modules/nodemailer/dist/esm/fetch/index.js +2 -8
- package/node_modules/nodemailer/dist/esm/mail-composer/index.js +42 -9
- package/node_modules/nodemailer/dist/esm/mailer/mail-message.js +5 -6
- package/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +18 -1
- package/node_modules/nodemailer/dist/esm/mime-funcs/index.js +43 -1
- package/node_modules/nodemailer/dist/esm/mime-funcs/mime-types.js +3 -12
- package/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +34 -1
- package/node_modules/nodemailer/dist/esm/mime-node/index.js +40 -15
- package/node_modules/nodemailer/dist/esm/package-info.d.ts +1 -1
- package/node_modules/nodemailer/dist/esm/package-info.js +1 -1
- package/node_modules/nodemailer/dist/esm/qp/index.js +3 -12
- package/node_modules/nodemailer/dist/esm/sendmail-transport/index.js +1 -3
- package/node_modules/nodemailer/dist/esm/shared/index.js +2 -6
- package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +1 -1
- package/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +6 -0
- package/node_modules/nodemailer/dist/esm/smtp-connection/index.js +16 -13
- package/node_modules/nodemailer/dist/esm/smtp-connection/server-message-id.d.ts +14 -0
- package/node_modules/nodemailer/dist/esm/smtp-connection/server-message-id.js +50 -0
- package/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +11 -0
- package/node_modules/nodemailer/dist/esm/smtp-pool/index.js +25 -1
- package/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js +2 -5
- package/node_modules/nodemailer/package.json +11 -9
- package/package.json +7 -7
- package/node_modules/mailparser/node_modules/iconv-lite/LICENSE +0 -21
- package/node_modules/mailparser/node_modules/iconv-lite/README.md +0 -138
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/dbcs-codec.js +0 -532
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/dbcs-data.js +0 -185
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/index.js +0 -23
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/internal.js +0 -218
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/sbcs-codec.js +0 -75
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/sbcs-data-generated.js +0 -451
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/sbcs-data.js +0 -180
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/big5-added.json +0 -122
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/cp936.json +0 -264
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/cp949.json +0 -273
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/cp950.json +0 -177
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/eucjp.json +0 -182
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/gb18030-ranges.json +0 -1
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/gbk-added.json +0 -56
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/shiftjis.json +0 -125
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/utf16.js +0 -187
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/utf32.js +0 -314
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/utf7.js +0 -283
- package/node_modules/mailparser/node_modules/iconv-lite/lib/bom-handling.js +0 -48
- package/node_modules/mailparser/node_modules/iconv-lite/lib/helpers/merge-exports.js +0 -13
- package/node_modules/mailparser/node_modules/iconv-lite/lib/index.d.ts +0 -129
- package/node_modules/mailparser/node_modules/iconv-lite/lib/index.js +0 -182
- package/node_modules/mailparser/node_modules/iconv-lite/lib/streams.js +0 -105
- package/node_modules/mailparser/node_modules/iconv-lite/package.json +0 -70
- package/node_modules/mailparser/node_modules/iconv-lite/types/encodings.d.ts +0 -425
|
@@ -12,7 +12,7 @@ const pathlib = require('path');
|
|
|
12
12
|
/** @typedef {import('..').PartNumberItem} PartNumberItem */
|
|
13
13
|
/** @typedef {import('..').PartNumber} PartNumber */
|
|
14
14
|
/** @typedef {import('..').SplitterOptions} SplitterOptions */
|
|
15
|
-
/** @typedef {import('libmime').
|
|
15
|
+
/** @typedef {import('libmime').ParsedHeaderValue} StructuredHeader */
|
|
16
16
|
/** @typedef {import('stream').Transform | import('stream').PassThrough} ContentStream */
|
|
17
17
|
/** @typedef {import('..').MimeNode} MimeNodeType */
|
|
18
18
|
|
|
@@ -27,6 +27,9 @@ const HEADER_LINE_MIN_COST = 64;
|
|
|
27
27
|
* `value.replace(/\(.*\)/g, '')`, but in linear time. The regex backtracks quadratically
|
|
28
28
|
* on a value with many `(` characters and no closing `)`.
|
|
29
29
|
*
|
|
30
|
+
* Used for the Content-Transfer-Encoding only. The MIME headers with parameters go through
|
|
31
|
+
* libmime's parseHeaderValue with stripComments, which knows where a comment may stand.
|
|
32
|
+
*
|
|
30
33
|
* @param {string} value
|
|
31
34
|
* @returns {string}
|
|
32
35
|
*/
|
|
@@ -48,59 +51,6 @@ function stripComments(value) {
|
|
|
48
51
|
.join('');
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
/**
|
|
52
|
-
* Lists the parameters a header value gives in RFC 2231 form (`name*=`, `name*0=` or
|
|
53
|
-
* `name*0*=`). libmime decodes those while parsing the header, so the result must not
|
|
54
|
-
* go through `decodeWords` as well: a value like `filename*=utf-8''a%3D%3Futf-8%3FQ%3F%3D2Eexe%3F%3D`
|
|
55
|
-
* would otherwise come out as `a.exe` while a parser that decodes once sees the encoded word.
|
|
56
|
-
*
|
|
57
|
-
* @param {string} value Raw header value.
|
|
58
|
-
* @returns {Set<string>} Lowercased parameter names.
|
|
59
|
-
*/
|
|
60
|
-
function rfc2231ParamNames(value) {
|
|
61
|
-
let names = new Set();
|
|
62
|
-
let quote = false;
|
|
63
|
-
let escaped = false;
|
|
64
|
-
let start = 0;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* @param {number} end End offset of the segment starting at `start`.
|
|
68
|
-
* @returns {void}
|
|
69
|
-
*/
|
|
70
|
-
let addSegment = end => {
|
|
71
|
-
let segment = value.substring(start, end);
|
|
72
|
-
let eq = segment.indexOf('=');
|
|
73
|
-
if (eq < 0) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
let match = segment
|
|
77
|
-
.substring(0, eq)
|
|
78
|
-
.trim()
|
|
79
|
-
.toLowerCase()
|
|
80
|
-
.match(/^(.+?)\*(\d+\*?)?$/);
|
|
81
|
-
if (match) {
|
|
82
|
-
names.add(match[1]);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
for (let i = 0; i < value.length; i++) {
|
|
87
|
-
let chr = value.charAt(i);
|
|
88
|
-
if (escaped) {
|
|
89
|
-
escaped = false;
|
|
90
|
-
} else if (chr === '\\') {
|
|
91
|
-
escaped = true;
|
|
92
|
-
} else if (chr === '"') {
|
|
93
|
-
quote = !quote;
|
|
94
|
-
} else if (chr === ';' && !quote) {
|
|
95
|
-
addSegment(i);
|
|
96
|
-
start = i + 1;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
addSegment(value.length);
|
|
100
|
-
|
|
101
|
-
return names;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
54
|
/**
|
|
105
55
|
* Parsed MIME node with mutable headers and transfer-encoding helpers.
|
|
106
56
|
*/
|
|
@@ -216,8 +166,14 @@ class MimeNode {
|
|
|
216
166
|
this._headersLines = [];
|
|
217
167
|
let headers = this.headers;
|
|
218
168
|
|
|
169
|
+
// The comments of the MIME headers are dropped, so that `boundary=b (comment)` names
|
|
170
|
+
// the boundary `b` that postal-mime and Python's email.policy.default split by. Read as
|
|
171
|
+
// content, it matched no delimiter line and the parts both of them find stayed hidden
|
|
172
|
+
// here. Python's legacy compat32 policy, the default of message_from_bytes() without a
|
|
173
|
+
// policy, keeps the comment and splits by `--b (comment)` lines instead: a split
|
|
174
|
+
// against it is the price of agreeing with the two readers a renderer is built on
|
|
219
175
|
let dispositionHeader = headers.getFirst('Content-Disposition');
|
|
220
|
-
this._parsedContentDisposition = this.libmime.parseHeaderValue(dispositionHeader);
|
|
176
|
+
this._parsedContentDisposition = this.libmime.parseHeaderValue(dispositionHeader, { stripComments: true });
|
|
221
177
|
let parsedContentDisposition = /** @type {StructuredHeader} */ (this._parsedContentDisposition);
|
|
222
178
|
|
|
223
179
|
// if content-type is missing default to plaintext
|
|
@@ -240,9 +196,12 @@ class MimeNode {
|
|
|
240
196
|
}
|
|
241
197
|
}
|
|
242
198
|
|
|
243
|
-
this._parsedContentType = this.libmime.parseHeaderValue(contentHeader);
|
|
199
|
+
this._parsedContentType = this.libmime.parseHeaderValue(contentHeader, { stripComments: true });
|
|
244
200
|
let parsedContentType = /** @type {StructuredHeader} */ (this._parsedContentType);
|
|
245
201
|
|
|
202
|
+
// The encoding is a bare token, and one written in quotes stays quoted, so that
|
|
203
|
+
// "base64" is not decoded, as Python and postal-mime do not decode it. parseHeaderValue
|
|
204
|
+
// would unquote it, so the transfer encoding keeps its own comment stripper
|
|
246
205
|
this.encoding = stripComments(headers.getFirst('Content-Transfer-Encoding')).toLowerCase().trim();
|
|
247
206
|
this.contentType = (parsedContentType.value || '').toLowerCase().trim() || false;
|
|
248
207
|
this.charset = parsedContentType.params.charset || false;
|
|
@@ -259,7 +218,11 @@ class MimeNode {
|
|
|
259
218
|
|
|
260
219
|
this.filename = parsedContentDisposition.params.filename || parsedContentType.params.name || false;
|
|
261
220
|
|
|
262
|
-
|
|
221
|
+
// format=flowed is defined for text/plain (RFC 3676), and a browser never unfolds an
|
|
222
|
+
// html part. Flagged on any text part, a text/html part with delsp=yes had its
|
|
223
|
+
// `<scri \r\npt>` joined into a script tag by the consumer that unfolded it, a tag
|
|
224
|
+
// neither Python nor a browser given the raw bytes sees
|
|
225
|
+
if (this.contentType === 'text/plain' && parsedContentType.params.format && parsedContentType.params.format.toLowerCase().trim() === 'flowed') {
|
|
263
226
|
this.flowed = true;
|
|
264
227
|
if (parsedContentType.params.delsp && parsedContentType.params.delsp.toLowerCase().trim() === 'yes') {
|
|
265
228
|
this.delSp = true;
|
|
@@ -267,10 +230,15 @@ class MimeNode {
|
|
|
267
230
|
}
|
|
268
231
|
|
|
269
232
|
if (this.filename) {
|
|
270
|
-
//
|
|
233
|
+
// A parameter given in RFC 2231 form was decoded by libmime already, which names
|
|
234
|
+
// it in decodedParams, and must not go through decodeWords as well:
|
|
235
|
+
// filename*=utf-8''a%3D%3Futf-8%3FQ%3F%3D2Eexe%3F%3D would otherwise come out as
|
|
236
|
+
// a.exe while a parser that decodes once sees the encoded word. A second scan of
|
|
237
|
+
// the raw header for the name used to decide this, and read `(c)filename*=` as
|
|
238
|
+
// a parameter named `(c)filename` once the comment was dropped from the real one
|
|
271
239
|
let decoded = parsedContentDisposition.params.filename
|
|
272
|
-
?
|
|
273
|
-
:
|
|
240
|
+
? parsedContentDisposition.decodedParams.includes('filename')
|
|
241
|
+
: parsedContentType.decodedParams.includes('name');
|
|
274
242
|
if (!decoded) {
|
|
275
243
|
try {
|
|
276
244
|
this.filename = this.libmime.decodeWords(this.filename);
|
|
@@ -285,7 +253,16 @@ class MimeNode {
|
|
|
285
253
|
this.contentType.substr(0, this.contentType.indexOf('/')) === 'multipart' &&
|
|
286
254
|
this.contentType.substr(this.contentType.indexOf('/') + 1)) ||
|
|
287
255
|
false;
|
|
288
|
-
|
|
256
|
+
// A boundary is ASCII and does not end in whitespace (RFC 2046 5.1.1, bchars), and
|
|
257
|
+
// Python matches no line against one that is not. One holding a non-ASCII character
|
|
258
|
+
// came out of a header read as latin1 or as UTF-8, and matched under `--ab\xC3\xA9cd`
|
|
259
|
+
// lines parts that a scanner built on Python never saw. Such a boundary counts as
|
|
260
|
+
// none, as a boundary parameter that is missing does. Trailing whitespace is dropped
|
|
261
|
+
// as Python drops it, a delimiter line may end in whitespace anyway
|
|
262
|
+
let boundary = (parsedContentType.params.boundary || '').trimEnd();
|
|
263
|
+
// a non-ASCII character takes more than one byte in UTF-8
|
|
264
|
+
let ascii = Buffer.byteLength(boundary) === boundary.length;
|
|
265
|
+
this._boundary = boundary && ascii ? Buffer.from(boundary) : false;
|
|
289
266
|
|
|
290
267
|
this.rfc822 = this.contentType === 'message/rfc822';
|
|
291
268
|
|
|
@@ -107,7 +107,7 @@ export interface MimeNode {
|
|
|
107
107
|
/** Decoded filename from Content-Disposition or Content-Type parameters, or `false` when absent. */
|
|
108
108
|
filename: string | false;
|
|
109
109
|
|
|
110
|
-
/** Whether this node is `text
|
|
110
|
+
/** Whether this node is `text/plain` with `format=flowed`. */
|
|
111
111
|
flowed: boolean;
|
|
112
112
|
|
|
113
113
|
/** Whether flowed text uses `delsp=yes`. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zone-eu/mailsplit",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.29",
|
|
4
4
|
"description": "Split email messages into an object stream",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"license": "(MIT OR EUPL-1.1+)",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"libbase64": "1.4.1",
|
|
28
|
-
"libmime": "5.
|
|
28
|
+
"libmime": "5.6.3",
|
|
29
29
|
"libqp": "3.0.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [5.6.3](https://github.com/nodemailer/libmime/compare/v5.6.2...v5.6.3) (2026-10-22)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* drop what follows a closed quoted string up to the next parameter ([d2324b8](https://github.com/nodemailer/libmime/commit/d2324b8146896c580308a9d81fa539198b963850))
|
|
9
|
+
|
|
10
|
+
## [5.6.2](https://github.com/nodemailer/libmime/compare/v5.6.1...v5.6.2) (2026-10-22)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* continue the token of a parameter value with a parenthesis right behind the equals sign ([9bcc718](https://github.com/nodemailer/libmime/commit/9bcc7187734f7fb9e3573aa488dd7a0c47ae4adf))
|
|
16
|
+
|
|
17
|
+
## [5.6.1](https://github.com/nodemailer/libmime/compare/v5.6.0...v5.6.1) (2026-10-22)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* drop the comments of a MIME header value with the stripComments option ([2c36976](https://github.com/nodemailer/libmime/commit/2c369764904ec1e41535fc010d3b048e605330e3))
|
|
23
|
+
* keep the first value of a duplicated parameter ([c6f9df5](https://github.com/nodemailer/libmime/commit/c6f9df58312ff40a551abc5522a11bac1841a6cf))
|
|
24
|
+
|
|
25
|
+
## [5.6.0](https://github.com/nodemailer/libmime/compare/v5.5.2...v5.6.0) (2026-10-21)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
* add a skipPrototypeKeys option to decodeHeaders() ([cfbf67d](https://github.com/nodemailer/libmime/commit/cfbf67dce5074f954ffcf05b04129473ebd40ef6))
|
|
31
|
+
* add createDecodeStream() for decoding a body in any charset ([dbc96a0](https://github.com/nodemailer/libmime/commit/dbc96a06e0e38f5ca45a30dac602cb525e2b0c02))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Bug Fixes
|
|
35
|
+
|
|
36
|
+
* read the byte order of UTF-16 from the BOM ([a9332ee](https://github.com/nodemailer/libmime/commit/a9332ee23cf0527854cc89f6ea6b438d51ca1e29))
|
|
37
|
+
* resolve the x-mac charset labels and Big5-HKSCS ([40d9eda](https://github.com/nodemailer/libmime/commit/40d9eda949b9d086ccb4c47b34811a439a14a8f8))
|
|
38
|
+
|
|
3
39
|
## [5.5.2](https://github.com/nodemailer/libmime/compare/v5.5.1...v5.5.2) (2026-10-19)
|
|
4
40
|
|
|
5
41
|
|
|
@@ -29,7 +29,7 @@ import { Libmime } from 'libmime';
|
|
|
29
29
|
const mime = new Libmime();
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
The helper modules can be loaded directly as well, for example `libmime/lib/charset` (`encode`, `decode`, `convert`, `normalizeCharset`) and `libmime/lib/mimetypes` (`list`, `extensions`).
|
|
32
|
+
The helper modules can be loaded directly as well, for example `libmime/lib/charset` (`encode`, `decode`, `convert`, `normalizeCharset`, `createDecodeStream`, `DecodeStream`) and `libmime/lib/mimetypes` (`list`, `extensions`).
|
|
33
33
|
|
|
34
34
|
### TypeScript
|
|
35
35
|
|
|
@@ -137,18 +137,27 @@ Parses a block of header lines. Does not decode mime words as every header might
|
|
|
137
137
|
|
|
138
138
|
Return value is an object of headers, where header keys are object keys and values are arrays.
|
|
139
139
|
|
|
140
|
-
libmime.decodeHeaders(headers) → Object
|
|
140
|
+
libmime.decodeHeaders(headers[, options]) → Object
|
|
141
141
|
|
|
142
142
|
- **headers** - Headers string
|
|
143
|
+
- **options** - Optional options object
|
|
144
|
+
- **skipPrototypeKeys** - if `true`, headers named like an `Object.prototype` member (`__proto__`, `constructor`) are left out. By default they are kept as own properties of the result
|
|
143
145
|
|
|
144
146
|
#### #parseHeaderValue
|
|
145
147
|
|
|
146
148
|
Parses a header value with `key=value` arguments into a structured object. Useful when dealing with
|
|
147
149
|
`content-type` and such. Continuation encoded params are joined into mime encoded words.
|
|
148
150
|
|
|
149
|
-
parseHeaderValue(valueString) → Object
|
|
151
|
+
parseHeaderValue(valueString[, options]) → Object
|
|
150
152
|
|
|
151
153
|
- **valueString** - a header value without the key
|
|
154
|
+
- **options** - optional options object
|
|
155
|
+
- **stripComments** - if `true`, RFC 822 comments outside quoted strings are dropped, so `boundary=b (comment)` gives the boundary `b`. A parenthesis right behind the `=` of a parameter or behind a token of its value continues the token, `filename=Invoice(1).pdf` keeps its name and `boundary=(c)b` names the boundary `(c)b`, as both do for Python and postal-mime. A comment that never closes runs to the end of the value, unless a parameter follows it, in which case it is content and the parameter survives. Use it for the MIME headers (`Content-Type`, `Content-Disposition`). By default comments are kept, since a header such as `Authentication-Results` carries information in them
|
|
156
|
+
|
|
157
|
+
A parameter value is a token or a quoted string, so what follows a closed quoted string up to the next `;` is
|
|
158
|
+
dropped (`boundary="b"c` gives `b`), and a parameter that occurs more than once keeps its first value, both as Python and postal-mime read them. An RFC 2231
|
|
159
|
+
continuation overrides the plain parameter of the same name in either order, libmime's own rule after RFC 6266
|
|
160
|
+
section 4.3.
|
|
152
161
|
|
|
153
162
|
**Example**
|
|
154
163
|
|
|
@@ -207,6 +216,34 @@ Content-disposition: attachment; filename*0*=utf-8''filename%20
|
|
|
207
216
|
filename*1*=%C3%B5%C3%A4%C3%B6; filename*2*=%C3%BC.txt
|
|
208
217
|
```
|
|
209
218
|
|
|
219
|
+
### Charsets
|
|
220
|
+
|
|
221
|
+
#### #normalizeCharset
|
|
222
|
+
|
|
223
|
+
Resolves a charset name to its canonical form, eg. `win-1257` becomes `windows-1257`. Unknown names are returned uppercased.
|
|
224
|
+
|
|
225
|
+
libmime.normalizeCharset(charset) → String
|
|
226
|
+
|
|
227
|
+
#### #createDecodeStream
|
|
228
|
+
|
|
229
|
+
Creates a Transform stream that decodes bytes in a charset into UTF-8 Buffers, for example a message body. The output is what decoding the whole input at once gives, however it is split into chunks. The charset name is resolved the same way as for encoded words, the Japanese charsets iconv-lite does not support (ISO-2022-JP and friends) are decoded with encoding-japanese, which is not incremental, so such input is collected until the stream ends. The double byte charsets (Shift_JIS, GBK, GB18030, Big5, EUC-KR, EUC-JP) are decoded up to the last byte below 0x30 (a space, a line break, most ASCII punctuation) of what has arrived, so input without any such byte is held until the stream ends as well.
|
|
230
|
+
|
|
231
|
+
libmime.createDecodeStream(charset) → DecodeStream
|
|
232
|
+
|
|
233
|
+
- **charset** - Charset the input is encoded in, defaults to UTF-8
|
|
234
|
+
|
|
235
|
+
The stream has two extra properties:
|
|
236
|
+
|
|
237
|
+
- **charset** - the canonical charset name
|
|
238
|
+
- **supported** - `false` when the charset is unknown or refused (UTF-7, which could smuggle markup past filters, and the base64 and hex transfer encodings). The input is then decoded as UTF-8 regardless, invalid bytes replaced with U+FFFD, the same fallback encoded words get. Check it before piping when the bytes must not be relabelled as UTF-8, for example to keep the original part as it is
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
const stream = libmime.createDecodeStream('iso-8859-1');
|
|
242
|
+
if (stream.supported) {
|
|
243
|
+
body.pipe(stream).pipe(output);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
210
247
|
### MIME Types
|
|
211
248
|
|
|
212
249
|
#### #detectExtension
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { Transform } from 'node:stream';
|
|
3
|
+
import type { TransformCallback } from 'node:stream';
|
|
2
4
|
/**
|
|
3
5
|
* Encodes an unicode string into an Buffer object as UTF-8
|
|
4
6
|
*
|
|
@@ -34,10 +36,44 @@ export declare function convert(data: string | Buffer, fromCharset?: string): Bu
|
|
|
34
36
|
* @return Canonicalized charset name
|
|
35
37
|
*/
|
|
36
38
|
export declare function normalizeCharset(charset?: unknown): string;
|
|
39
|
+
/**
|
|
40
|
+
* Transform stream that decodes bytes in a charset into UTF-8 Buffers, see createDecodeStream()
|
|
41
|
+
*/
|
|
42
|
+
export declare class DecodeStream extends Transform {
|
|
43
|
+
/** Canonical name of the charset the input was declared in, what normalizeCharset() gives */
|
|
44
|
+
readonly charset: string;
|
|
45
|
+
/**
|
|
46
|
+
* false when the declared charset is unknown, or one that is refused (UTF-7, base64, hex). The
|
|
47
|
+
* input is then decoded as UTF-8, the same fallback decode() applies, so a caller that must
|
|
48
|
+
* not relabel such bytes as UTF-8 checks this before piping anything through
|
|
49
|
+
*/
|
|
50
|
+
readonly supported: boolean;
|
|
51
|
+
private decoder;
|
|
52
|
+
private chunks;
|
|
53
|
+
private highSurrogate;
|
|
54
|
+
constructor(charset?: unknown);
|
|
55
|
+
_transform(chunk: Buffer, _encoding: BufferEncoding, done: TransformCallback): void;
|
|
56
|
+
_flush(done: TransformCallback): void;
|
|
57
|
+
private pushText;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Creates a Transform stream that decodes bytes in the given charset into UTF-8 Buffers. The
|
|
61
|
+
* charset name is resolved with normalizeCharset(), and the output is what decode() gives for
|
|
62
|
+
* the whole input, however it is split into chunks: the Japanese charsets iconv-lite does not
|
|
63
|
+
* support are decoded with encoding-japanese (collected until the input ends, as that decoder
|
|
64
|
+
* is not incremental), and an unknown or refused charset (UTF-7, base64, hex) is decoded as
|
|
65
|
+
* UTF-8 with `supported` set to false on the stream.
|
|
66
|
+
*
|
|
67
|
+
* @param [charset='UTF-8'] Charset the input is encoded in
|
|
68
|
+
* @return Transform stream with `charset` and `supported` properties
|
|
69
|
+
*/
|
|
70
|
+
export declare function createDecodeStream(charset?: unknown): DecodeStream;
|
|
37
71
|
declare const _default: {
|
|
38
72
|
encode: typeof encode;
|
|
39
73
|
decode: typeof decode;
|
|
40
74
|
convert: typeof convert;
|
|
41
75
|
normalizeCharset: typeof normalizeCharset;
|
|
76
|
+
createDecodeStream: typeof createDecodeStream;
|
|
77
|
+
DecodeStream: typeof DecodeStream;
|
|
42
78
|
};
|
|
43
79
|
export default _default;
|
|
@@ -3,11 +3,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DecodeStream = void 0;
|
|
6
7
|
exports.encode = encode;
|
|
7
8
|
exports.decode = decode;
|
|
8
9
|
exports.convert = convert;
|
|
9
10
|
exports.normalizeCharset = normalizeCharset;
|
|
11
|
+
exports.createDecodeStream = createDecodeStream;
|
|
10
12
|
const node_buffer_1 = require("node:buffer");
|
|
13
|
+
const node_stream_1 = require("node:stream");
|
|
14
|
+
const node_string_decoder_1 = require("node:string_decoder");
|
|
11
15
|
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
|
12
16
|
const encoding_japanese_1 = __importDefault(require("encoding-japanese"));
|
|
13
17
|
const charsets_js_1 = __importDefault(require("./charsets.js"));
|
|
@@ -31,6 +35,8 @@ const isUnsupportedCodec = (name) => {
|
|
|
31
35
|
return false;
|
|
32
36
|
}
|
|
33
37
|
};
|
|
38
|
+
// Charsets iconv-lite does not support, decoded with encoding-japanese instead
|
|
39
|
+
const JAPANESE_CHARSET = /^jis|^iso-?2022-?jp|^EUCJP/i;
|
|
34
40
|
// Own entries only, so that a name such as '__proto__' or 'constructor' does not resolve to an
|
|
35
41
|
// inherited Object.prototype member
|
|
36
42
|
const CHARSET_ALIASES = new Map(Object.entries(charsets_js_1.default));
|
|
@@ -63,7 +69,7 @@ function decode(buf, fromCharset) {
|
|
|
63
69
|
return buf.toString();
|
|
64
70
|
}
|
|
65
71
|
try {
|
|
66
|
-
if (
|
|
72
|
+
if (JAPANESE_CHARSET.test(fromCharset)) {
|
|
67
73
|
if (typeof buf === 'string') {
|
|
68
74
|
buf = node_buffer_1.Buffer.from(buf);
|
|
69
75
|
}
|
|
@@ -131,5 +137,162 @@ function normalizeCharset(charset) {
|
|
|
131
137
|
// updated pass
|
|
132
138
|
return CHARSET_ALIASES.get(name) || name.toUpperCase();
|
|
133
139
|
}
|
|
134
|
-
|
|
140
|
+
// The decoder all of iconv-lite's double byte codecs share
|
|
141
|
+
const DBCS_DECODER = iconv_lite_1.default.getCodec('gbk').decoder;
|
|
142
|
+
// The UTF-16 and UTF-32 decoders without a byte order in the name read it from a BOM or guess it
|
|
143
|
+
// from the first 100 characters, but a stream guesses as soon as it has 16 or 32 bytes. Holding
|
|
144
|
+
// back this many bytes makes the stream guess from the same characters as decode()
|
|
145
|
+
const BYTE_ORDER_GUESSING = new Map([
|
|
146
|
+
[iconv_lite_1.default.getCodec('utf-16'), 200],
|
|
147
|
+
[iconv_lite_1.default.getCodec('utf-32'), 400]
|
|
148
|
+
]);
|
|
149
|
+
// iconv-lite 0.7 sizes what a DBCS decoder's write() returns by the length of the chunk, so when
|
|
150
|
+
// the chunk finishes or rejects a character the previous one started, the output can outgrow
|
|
151
|
+
// that size and its end is cut off: an astral GB18030 character split in two loses its low
|
|
152
|
+
// surrogate, a GB18030 lead byte followed by a space loses everything after it. The input is
|
|
153
|
+
// therefore cut where no character can be unfinished, right after a byte below 0x30. No lead,
|
|
154
|
+
// trail or GB18030 digit byte is that low, so such a byte always decodes as itself and the
|
|
155
|
+
// parse starts afresh after it. Every cut is decoded as a whole, with nothing carried over, and
|
|
156
|
+
// the bytes after the last such byte wait for the next chunk
|
|
157
|
+
class LowByteCutDecoder {
|
|
158
|
+
constructor(charset) {
|
|
159
|
+
this.pending = [];
|
|
160
|
+
this.charset = charset;
|
|
161
|
+
}
|
|
162
|
+
write(chunk) {
|
|
163
|
+
let cut = chunk.length;
|
|
164
|
+
while (cut > 0 && chunk[cut - 1] >= 0x30) {
|
|
165
|
+
cut--;
|
|
166
|
+
}
|
|
167
|
+
if (!cut) {
|
|
168
|
+
// copied, the caller may reuse the chunk it wrote
|
|
169
|
+
this.pending.push(node_buffer_1.Buffer.from(chunk));
|
|
170
|
+
return '';
|
|
171
|
+
}
|
|
172
|
+
let text = iconv_lite_1.default.decode(node_buffer_1.Buffer.concat([...this.pending, chunk.subarray(0, cut)]), this.charset);
|
|
173
|
+
this.pending = [node_buffer_1.Buffer.from(chunk.subarray(cut))];
|
|
174
|
+
return text;
|
|
175
|
+
}
|
|
176
|
+
end() {
|
|
177
|
+
let rest = node_buffer_1.Buffer.concat(this.pending);
|
|
178
|
+
this.pending = [];
|
|
179
|
+
return rest.length ? iconv_lite_1.default.decode(rest, this.charset) : undefined;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Passes the input on once its first `size` bytes are in, see BYTE_ORDER_GUESSING
|
|
183
|
+
class HeadBufferedDecoder {
|
|
184
|
+
constructor(decoder, size) {
|
|
185
|
+
this.head = [];
|
|
186
|
+
this.headLength = 0;
|
|
187
|
+
this.decoder = decoder;
|
|
188
|
+
this.size = size;
|
|
189
|
+
}
|
|
190
|
+
write(chunk) {
|
|
191
|
+
if (!this.head) {
|
|
192
|
+
return this.decoder.write(chunk);
|
|
193
|
+
}
|
|
194
|
+
// copied, the caller may reuse the chunk it wrote
|
|
195
|
+
this.head.push(node_buffer_1.Buffer.from(chunk));
|
|
196
|
+
this.headLength += chunk.length;
|
|
197
|
+
return this.headLength < this.size ? '' : this.releaseHead();
|
|
198
|
+
}
|
|
199
|
+
end() {
|
|
200
|
+
return (this.head ? this.releaseHead() : '') + (this.decoder.end() || '');
|
|
201
|
+
}
|
|
202
|
+
releaseHead() {
|
|
203
|
+
let head = node_buffer_1.Buffer.concat(this.head || []);
|
|
204
|
+
this.head = null;
|
|
205
|
+
return this.decoder.write(head);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Picks the decoder for a charset iconv-lite knows
|
|
209
|
+
function createChunkDecoder(charset) {
|
|
210
|
+
let codec = iconv_lite_1.default.getCodec(charset);
|
|
211
|
+
if (codec.decoder === DBCS_DECODER) {
|
|
212
|
+
return new LowByteCutDecoder(charset);
|
|
213
|
+
}
|
|
214
|
+
let headSize = BYTE_ORDER_GUESSING.get(codec);
|
|
215
|
+
return headSize ? new HeadBufferedDecoder(iconv_lite_1.default.getDecoder(charset), headSize) : iconv_lite_1.default.getDecoder(charset);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Transform stream that decodes bytes in a charset into UTF-8 Buffers, see createDecodeStream()
|
|
219
|
+
*/
|
|
220
|
+
class DecodeStream extends node_stream_1.Transform {
|
|
221
|
+
constructor(charset) {
|
|
222
|
+
super();
|
|
223
|
+
// null for the Japanese charsets, which are collected and decoded when the input ends
|
|
224
|
+
this.decoder = null;
|
|
225
|
+
this.chunks = [];
|
|
226
|
+
this.highSurrogate = '';
|
|
227
|
+
this.charset = normalizeCharset(charset || 'UTF-8');
|
|
228
|
+
if (UTF8_COMPATIBLE.test(this.charset)) {
|
|
229
|
+
this.supported = true;
|
|
230
|
+
this.decoder = new node_string_decoder_1.StringDecoder('utf-8');
|
|
231
|
+
}
|
|
232
|
+
else if (isUnsupportedCodec(this.charset) || !(JAPANESE_CHARSET.test(this.charset) || iconv_lite_1.default.encodingExists(this.charset))) {
|
|
233
|
+
this.supported = false;
|
|
234
|
+
this.decoder = new node_string_decoder_1.StringDecoder('utf-8');
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
this.supported = true;
|
|
238
|
+
// encoding-japanese has no incremental decoder and ISO-2022-JP is stateful, so the
|
|
239
|
+
// Japanese charsets are left without one
|
|
240
|
+
this.decoder = JAPANESE_CHARSET.test(this.charset) ? null : createChunkDecoder(this.charset);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
_transform(chunk, _encoding, done) {
|
|
244
|
+
if (!this.decoder) {
|
|
245
|
+
this.chunks.push(chunk);
|
|
246
|
+
return done();
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
this.pushText(this.decoder.write(chunk), false);
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
return done(err);
|
|
253
|
+
}
|
|
254
|
+
done();
|
|
255
|
+
}
|
|
256
|
+
_flush(done) {
|
|
257
|
+
try {
|
|
258
|
+
this.pushText(this.decoder ? this.decoder.end() : decode(node_buffer_1.Buffer.concat(this.chunks), this.charset), true);
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
return done(err);
|
|
262
|
+
}
|
|
263
|
+
this.chunks = [];
|
|
264
|
+
done();
|
|
265
|
+
}
|
|
266
|
+
// A decoder may return the two halves of a surrogate pair from separate writes, and a lone
|
|
267
|
+
// half would turn into U+FFFD on its way to UTF-8, so a trailing high surrogate waits for
|
|
268
|
+
// the rest of its character
|
|
269
|
+
pushText(text, final) {
|
|
270
|
+
text = this.highSurrogate + (text || '');
|
|
271
|
+
this.highSurrogate = '';
|
|
272
|
+
let last = text.charCodeAt(text.length - 1);
|
|
273
|
+
if (!final && last >= 0xd800 && last <= 0xdbff) {
|
|
274
|
+
this.highSurrogate = text.slice(-1);
|
|
275
|
+
text = text.slice(0, -1);
|
|
276
|
+
}
|
|
277
|
+
if (text) {
|
|
278
|
+
this.push(node_buffer_1.Buffer.from(text, 'utf-8'));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
exports.DecodeStream = DecodeStream;
|
|
283
|
+
/**
|
|
284
|
+
* Creates a Transform stream that decodes bytes in the given charset into UTF-8 Buffers. The
|
|
285
|
+
* charset name is resolved with normalizeCharset(), and the output is what decode() gives for
|
|
286
|
+
* the whole input, however it is split into chunks: the Japanese charsets iconv-lite does not
|
|
287
|
+
* support are decoded with encoding-japanese (collected until the input ends, as that decoder
|
|
288
|
+
* is not incremental), and an unknown or refused charset (UTF-7, base64, hex) is decoded as
|
|
289
|
+
* UTF-8 with `supported` set to false on the stream.
|
|
290
|
+
*
|
|
291
|
+
* @param [charset='UTF-8'] Charset the input is encoded in
|
|
292
|
+
* @return Transform stream with `charset` and `supported` properties
|
|
293
|
+
*/
|
|
294
|
+
function createDecodeStream(charset) {
|
|
295
|
+
return new DecodeStream(charset);
|
|
296
|
+
}
|
|
297
|
+
exports.default = { encode, decode, convert, normalizeCharset, createDecodeStream, DecodeStream };
|
|
135
298
|
Object.defineProperty(exports, 'default', { value: exports, enumerable: false, writable: true, configurable: true });
|
|
@@ -113,6 +113,10 @@ const charsets = {
|
|
|
113
113
|
mac: 'macintosh',
|
|
114
114
|
macintosh: 'macintosh',
|
|
115
115
|
'x-mac-roman': 'macintosh',
|
|
116
|
+
// the x-mac-* labels mail clients send, under the names iconv-lite knows them by
|
|
117
|
+
'x-mac-ce': 'maccenteuro',
|
|
118
|
+
'x-mac-cyrillic': 'maccyrillic',
|
|
119
|
+
'x-mac-ukrainian': 'macukraine',
|
|
116
120
|
'dos-874': 'windows-874',
|
|
117
121
|
'iso-8859-11': 'windows-874',
|
|
118
122
|
'iso8859-11': 'windows-874',
|
|
@@ -180,7 +184,7 @@ const charsets = {
|
|
|
180
184
|
'x-gbk': 'GBK',
|
|
181
185
|
gb18030: 'gb18030',
|
|
182
186
|
big5: 'Big5',
|
|
183
|
-
'big5-hkscs': 'Big5',
|
|
187
|
+
'big5-hkscs': 'Big5-HKSCS',
|
|
184
188
|
'cn-big5': 'Big5',
|
|
185
189
|
csbig5: 'Big5',
|
|
186
190
|
'x-x-big5': 'Big5',
|
|
@@ -206,7 +210,9 @@ const charsets = {
|
|
|
206
210
|
ksc_5601: 'EUC-KR',
|
|
207
211
|
'windows-949': 'EUC-KR',
|
|
208
212
|
'utf-16be': 'UTF-16BE',
|
|
209
|
-
|
|
213
|
+
// iconv-lite's UTF-16 decoder reads the byte order from a BOM and guesses it from the
|
|
214
|
+
// content without one, falling back to little endian
|
|
215
|
+
'utf-16': 'UTF-16',
|
|
210
216
|
'utf-16le': 'UTF-16LE'
|
|
211
217
|
};
|
|
212
218
|
exports.default = charsets;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
|
-
import
|
|
2
|
+
import * as libcharset from './charset.js';
|
|
3
|
+
import type { DecodeHeadersOptions, HeaderLine, HeaderObject, HeaderParam, LibmimeConfig, ParsedHeaderValue, ParseHeaderValueOptions, StructuredHeaderValue } from './types.js';
|
|
3
4
|
import type * as types from './types.js';
|
|
4
5
|
declare class Libmime {
|
|
5
6
|
config: LibmimeConfig;
|
|
@@ -69,6 +70,16 @@ declare class Libmime {
|
|
|
69
70
|
* @return {String} Canonical charset name
|
|
70
71
|
*/
|
|
71
72
|
normalizeCharset(charset?: unknown): string;
|
|
73
|
+
/**
|
|
74
|
+
* Creates a Transform stream that decodes a body in the given charset into UTF-8 Buffers,
|
|
75
|
+
* resolving the charset name and handling the Japanese charsets the same way header
|
|
76
|
+
* decoding does. An unknown or refused charset (UTF-7, base64, hex) is decoded as UTF-8,
|
|
77
|
+
* and the stream says so with `supported` set to false.
|
|
78
|
+
*
|
|
79
|
+
* @param {String} [charset='UTF-8'] Charset the input is encoded in
|
|
80
|
+
* @return {DecodeStream} Transform stream with `charset` and `supported` properties
|
|
81
|
+
*/
|
|
82
|
+
createDecodeStream(charset?: unknown): libcharset.DecodeStream;
|
|
72
83
|
/**
|
|
73
84
|
* Decodes the inner payload of a single mime encoded-word into a unicode string.
|
|
74
85
|
* Expects the three components of `=?charset?encoding?text?=` already separated.
|
|
@@ -111,9 +122,11 @@ declare class Libmime {
|
|
|
111
122
|
* header might have its own rules (eg. formatted email addresses and such)
|
|
112
123
|
*
|
|
113
124
|
* @param {String} headers Headers string
|
|
125
|
+
* @param {Object} [options] Options
|
|
126
|
+
* @param {Boolean} [options.skipPrototypeKeys] Leave out headers named like an Object.prototype member, eg. `__proto__` and `constructor`
|
|
114
127
|
* @return {Object} An object of headers, where header keys are object keys and every value is an Array of the values for that key
|
|
115
128
|
*/
|
|
116
|
-
decodeHeaders(headers: string): HeaderObject;
|
|
129
|
+
decodeHeaders(headers: string, options?: DecodeHeadersOptions): HeaderObject;
|
|
117
130
|
/**
|
|
118
131
|
* Joins parsed header value together as 'value; param1=value1; param2=value2'
|
|
119
132
|
* PS: We are following RFC 822 for the list of special characters that we need to keep in quotes.
|
|
@@ -139,9 +152,10 @@ declare class Libmime {
|
|
|
139
152
|
* decoded, so a caller that runs decodeWords() over the params has to leave them out
|
|
140
153
|
*
|
|
141
154
|
* @param {String} str Header value
|
|
155
|
+
* @param {Object} [options] Options, see ParseHeaderValueOptions
|
|
142
156
|
* @return {Object} Header value as a parsed structure
|
|
143
157
|
*/
|
|
144
|
-
parseHeaderValue(str: string): ParsedHeaderValue;
|
|
158
|
+
parseHeaderValue(str: string, options?: ParseHeaderValueOptions): ParsedHeaderValue;
|
|
145
159
|
/**
|
|
146
160
|
* Encodes a string or an Buffer to an UTF-8 Parameter Value Continuation encoding (rfc2231)
|
|
147
161
|
* Useful for splitting long parameter values.
|
|
@@ -206,12 +220,15 @@ declare const libmime: Libmime & {
|
|
|
206
220
|
type LibmimeInstance = Libmime;
|
|
207
221
|
declare namespace libmime {
|
|
208
222
|
type Libmime = LibmimeInstance;
|
|
223
|
+
type DecodeStream = libcharset.DecodeStream;
|
|
224
|
+
type DecodeHeadersOptions = types.DecodeHeadersOptions;
|
|
209
225
|
type HeaderLine = types.HeaderLine;
|
|
210
226
|
type HeaderObject = types.HeaderObject;
|
|
211
227
|
type HeaderParam = types.HeaderParam;
|
|
212
228
|
type LibmimeConfig = types.LibmimeConfig;
|
|
213
229
|
type MimeWordEncoding = types.MimeWordEncoding;
|
|
214
230
|
type ParsedHeaderValue = types.ParsedHeaderValue;
|
|
231
|
+
type ParseHeaderValueOptions = types.ParseHeaderValueOptions;
|
|
215
232
|
type StructuredHeader = types.StructuredHeader;
|
|
216
233
|
type StructuredHeaderValue = types.StructuredHeaderValue;
|
|
217
234
|
}
|