eml-parser-qaap 1.1.15
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/LICENSE +21 -0
- package/README.md +55 -0
- package/dist/addressparser.d.ts +46 -0
- package/dist/charset.d.ts +24 -0
- package/dist/index.d.ts +76 -0
- package/dist/interface.d.ts +103 -0
- package/dist/utils.d.ts +32 -0
- package/lib/bundle.amd.js +1427 -0
- package/lib/bundle.cjs.js +1428 -0
- package/lib/bundle.esm.js +1404 -0
- package/lib/bundle.iife.js +1431 -0
- package/lib/bundle.umd.js +1431 -0
- package/package.json +107 -0
- package/src/addressparser.ts +317 -0
- package/src/charset.ts +72 -0
- package/src/index.ts +983 -0
- package/src/interface.ts +118 -0
- package/src/utils.ts +198 -0
|
@@ -0,0 +1,1428 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsBase64 = require('js-base64');
|
|
6
|
+
var textEncoding = require('@sinonjs/text-encoding');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Encodes an unicode string into an Uint8Array object as UTF-8
|
|
10
|
+
*
|
|
11
|
+
* @param {String} str String to be encoded
|
|
12
|
+
* @return {Uint8Array} UTF-8 encoded typed array
|
|
13
|
+
*/
|
|
14
|
+
var encode = function (str, fromCharset) {
|
|
15
|
+
if (fromCharset === void 0) { fromCharset = 'utf-8'; }
|
|
16
|
+
return new textEncoding.TextEncoder(fromCharset).encode(str);
|
|
17
|
+
};
|
|
18
|
+
var arr2str = function (arr) {
|
|
19
|
+
var CHUNK_SZ = 0x8000;
|
|
20
|
+
var strs = [];
|
|
21
|
+
for (var i = 0; i < arr.length; i += CHUNK_SZ) {
|
|
22
|
+
strs.push(String.fromCharCode.apply(null, arr.subarray(i, i + CHUNK_SZ)));
|
|
23
|
+
}
|
|
24
|
+
return strs.join('');
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Decodes a string from Uint8Array to an unicode string using specified encoding
|
|
28
|
+
*
|
|
29
|
+
* @param {Uint8Array} buf Binary data to be decoded
|
|
30
|
+
* @param {String} Binary data is decoded into string using this charset
|
|
31
|
+
* @return {String} Decoded string
|
|
32
|
+
*/
|
|
33
|
+
function decode(buf, fromCharset) {
|
|
34
|
+
if (fromCharset === void 0) { fromCharset = 'utf-8'; }
|
|
35
|
+
var charsets = [
|
|
36
|
+
{ charset: normalizeCharset(fromCharset), fatal: false },
|
|
37
|
+
{ charset: 'utf-8', fatal: true },
|
|
38
|
+
{ charset: 'iso-8859-15', fatal: false },
|
|
39
|
+
];
|
|
40
|
+
for (var _i = 0, charsets_1 = charsets; _i < charsets_1.length; _i++) {
|
|
41
|
+
var _a = charsets_1[_i], charset = _a.charset, fatal = _a.fatal;
|
|
42
|
+
try {
|
|
43
|
+
return new textEncoding.TextDecoder(charset, { fatal: fatal }).decode(buf);
|
|
44
|
+
// eslint-disable-next-line no-empty
|
|
45
|
+
}
|
|
46
|
+
catch (e) { }
|
|
47
|
+
}
|
|
48
|
+
return arr2str(buf); // all else fails, treat it as binary
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Convert a string from specific encoding to UTF-8 Uint8Array
|
|
52
|
+
*
|
|
53
|
+
* @param {String|Uint8Array} data Data to be encoded
|
|
54
|
+
* @param {String} Source encoding for the string (optional for data of type String)
|
|
55
|
+
* @return {Uint8Array} UTF-8 encoded typed array
|
|
56
|
+
*/
|
|
57
|
+
var convert = function (data, fromCharset) {
|
|
58
|
+
return typeof data === 'string' ? encode(data) : encode(decode(data, fromCharset));
|
|
59
|
+
};
|
|
60
|
+
function normalizeCharset(charset) {
|
|
61
|
+
if (charset === void 0) { charset = 'utf-8'; }
|
|
62
|
+
var match;
|
|
63
|
+
if ((match = charset.match(/^utf[-_]?(\d+)$/i))) {
|
|
64
|
+
return 'UTF-' + match[1];
|
|
65
|
+
}
|
|
66
|
+
if ((match = charset.match(/^win[-_]?(\d+)$/i))) {
|
|
67
|
+
return 'WINDOWS-' + match[1];
|
|
68
|
+
}
|
|
69
|
+
if ((match = charset.match(/^latin[-_]?(\d+)$/i))) {
|
|
70
|
+
return 'ISO-8859-' + match[1];
|
|
71
|
+
}
|
|
72
|
+
return charset;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Gets the boundary name
|
|
77
|
+
* @param contentType - string
|
|
78
|
+
*/
|
|
79
|
+
function getBoundary(contentType) {
|
|
80
|
+
var match = /(?:B|b)oundary=(?:'|")?(.+?)(?:'|")?(\s*;[\s\S]*)?$/g.exec(contentType);
|
|
81
|
+
return match ? match[1] : undefined;
|
|
82
|
+
}
|
|
83
|
+
//Gets the character encoding name for iconv, e.g. 'iso-8859-2' -> 'iso88592'
|
|
84
|
+
function getCharsetName(charset) {
|
|
85
|
+
return charset.toLowerCase().replace(/[^0-9a-z]/g, '');
|
|
86
|
+
}
|
|
87
|
+
//Generates a random id
|
|
88
|
+
function guid() {
|
|
89
|
+
return 'xxxxxxxxxxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
|
90
|
+
.replace(/[xy]/g, function (c) {
|
|
91
|
+
var r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
|
|
92
|
+
return v.toString(16);
|
|
93
|
+
})
|
|
94
|
+
.replace('-', '');
|
|
95
|
+
}
|
|
96
|
+
//Word-wrap the string 's' to 'i' chars per row
|
|
97
|
+
function wrap(s, i) {
|
|
98
|
+
var a = [];
|
|
99
|
+
do {
|
|
100
|
+
a.push(s.substring(0, i));
|
|
101
|
+
} while ((s = s.substring(i, s.length)) != '');
|
|
102
|
+
return a.join('\r\n');
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Decodes mime encoded string to an unicode string
|
|
106
|
+
*
|
|
107
|
+
* @param {String} str Mime encoded string
|
|
108
|
+
* @param {String} [fromCharset='UTF-8'] Source encoding
|
|
109
|
+
* @return {String} Decoded unicode string
|
|
110
|
+
*/
|
|
111
|
+
function mimeDecode(str, fromCharset) {
|
|
112
|
+
if (str === void 0) { str = ''; }
|
|
113
|
+
if (fromCharset === void 0) { fromCharset = 'UTF-8'; }
|
|
114
|
+
var encodedBytesCount = (str.match(/=[\da-fA-F]{2}/g) || []).length;
|
|
115
|
+
var buffer = new Uint8Array(str.length - encodedBytesCount * 2);
|
|
116
|
+
for (var i = 0, len = str.length, bufferPos = 0; i < len; i++) {
|
|
117
|
+
var hex = str.substr(i + 1, 2);
|
|
118
|
+
var chr = str.charAt(i);
|
|
119
|
+
if (chr === '=' && hex && /[\da-fA-F]{2}/.test(hex)) {
|
|
120
|
+
buffer[bufferPos++] = parseInt(hex, 16);
|
|
121
|
+
i += 2;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
buffer[bufferPos++] = chr.charCodeAt(0);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return decode(buffer, fromCharset);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* converting strings from gbk to utf-8
|
|
131
|
+
*/
|
|
132
|
+
var GB2312UTF8 = {
|
|
133
|
+
Dig2Dec: function (s) {
|
|
134
|
+
var retV = 0;
|
|
135
|
+
if (s.length == 4) {
|
|
136
|
+
for (var i = 0; i < 4; i++) {
|
|
137
|
+
retV += eval(s.charAt(i)) * Math.pow(2, 3 - i);
|
|
138
|
+
}
|
|
139
|
+
return retV;
|
|
140
|
+
}
|
|
141
|
+
return -1;
|
|
142
|
+
},
|
|
143
|
+
Hex2Utf8: function (s) {
|
|
144
|
+
var retS = '';
|
|
145
|
+
var tempS = '';
|
|
146
|
+
var ss = '';
|
|
147
|
+
if (s.length == 16) {
|
|
148
|
+
tempS = '1110' + s.substring(0, 4);
|
|
149
|
+
tempS += '10' + s.substring(4, 10);
|
|
150
|
+
tempS += '10' + s.substring(10, 16);
|
|
151
|
+
var sss = '0123456789ABCDEF';
|
|
152
|
+
for (var i = 0; i < 3; i++) {
|
|
153
|
+
retS += '%';
|
|
154
|
+
ss = tempS.substring(i * 8, (eval(i.toString()) + 1) * 8);
|
|
155
|
+
retS += sss.charAt(this.Dig2Dec(ss.substring(0, 4)));
|
|
156
|
+
retS += sss.charAt(this.Dig2Dec(ss.substring(4, 8)));
|
|
157
|
+
}
|
|
158
|
+
return retS;
|
|
159
|
+
}
|
|
160
|
+
return '';
|
|
161
|
+
},
|
|
162
|
+
Dec2Dig: function (n1) {
|
|
163
|
+
var s = '';
|
|
164
|
+
var n2 = 0;
|
|
165
|
+
for (var i = 0; i < 4; i++) {
|
|
166
|
+
n2 = Math.pow(2, 3 - i);
|
|
167
|
+
if (n1 >= n2) {
|
|
168
|
+
s += '1';
|
|
169
|
+
n1 = n1 - n2;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
s += '0';
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return s;
|
|
176
|
+
},
|
|
177
|
+
Str2Hex: function (s) {
|
|
178
|
+
var c = '';
|
|
179
|
+
var n;
|
|
180
|
+
var ss = '0123456789ABCDEF';
|
|
181
|
+
var digS = '';
|
|
182
|
+
for (var i = 0; i < s.length; i++) {
|
|
183
|
+
c = s.charAt(i);
|
|
184
|
+
n = ss.indexOf(c);
|
|
185
|
+
digS += this.Dec2Dig(eval(n.toString()));
|
|
186
|
+
}
|
|
187
|
+
return digS;
|
|
188
|
+
},
|
|
189
|
+
GB2312ToUTF8: function (s1) {
|
|
190
|
+
var s = escape(s1);
|
|
191
|
+
var sa = s.split('%');
|
|
192
|
+
var retV = '';
|
|
193
|
+
if (sa[0] != '') {
|
|
194
|
+
retV = sa[0];
|
|
195
|
+
}
|
|
196
|
+
for (var i = 1; i < sa.length; i++) {
|
|
197
|
+
if (sa[i].substring(0, 1) == 'u') {
|
|
198
|
+
retV += this.Hex2Utf8(this.Str2Hex(sa[i].substring(1, 5)));
|
|
199
|
+
if (sa[i].length) {
|
|
200
|
+
retV += sa[i].substring(5);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
retV += unescape('%' + sa[i]);
|
|
205
|
+
if (sa[i].length) {
|
|
206
|
+
retV += sa[i].substring(5);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return retV;
|
|
211
|
+
},
|
|
212
|
+
UTF8ToGB2312: function (str1) {
|
|
213
|
+
var substr = '';
|
|
214
|
+
var a = '';
|
|
215
|
+
var b = '';
|
|
216
|
+
var c = '';
|
|
217
|
+
var i = -1;
|
|
218
|
+
i = str1.indexOf('%');
|
|
219
|
+
if (i == -1) {
|
|
220
|
+
return str1;
|
|
221
|
+
}
|
|
222
|
+
while (i != -1) {
|
|
223
|
+
if (i < 3) {
|
|
224
|
+
substr = substr + str1.substr(0, i - 1);
|
|
225
|
+
str1 = str1.substr(i + 1, str1.length - i);
|
|
226
|
+
a = str1.substr(0, 2);
|
|
227
|
+
str1 = str1.substr(2, str1.length - 2);
|
|
228
|
+
if ((parseInt('0x' + a) & 0x80) === 0) {
|
|
229
|
+
substr = substr + String.fromCharCode(parseInt('0x' + a));
|
|
230
|
+
}
|
|
231
|
+
else if ((parseInt('0x' + a) & 0xe0) === 0xc0) {
|
|
232
|
+
//two byte
|
|
233
|
+
b = str1.substr(1, 2);
|
|
234
|
+
str1 = str1.substr(3, str1.length - 3);
|
|
235
|
+
var widechar = (parseInt('0x' + a) & 0x1f) << 6;
|
|
236
|
+
widechar = widechar | (parseInt('0x' + b) & 0x3f);
|
|
237
|
+
substr = substr + String.fromCharCode(widechar);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
b = str1.substr(1, 2);
|
|
241
|
+
str1 = str1.substr(3, str1.length - 3);
|
|
242
|
+
c = str1.substr(1, 2);
|
|
243
|
+
str1 = str1.substr(3, str1.length - 3);
|
|
244
|
+
var widechar = (parseInt('0x' + a) & 0x0f) << 12;
|
|
245
|
+
widechar = widechar | ((parseInt('0x' + b) & 0x3f) << 6);
|
|
246
|
+
widechar = widechar | (parseInt('0x' + c) & 0x3f);
|
|
247
|
+
substr = substr + String.fromCharCode(widechar);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
substr = substr + str1.substring(0, i);
|
|
252
|
+
str1 = str1.substring(i);
|
|
253
|
+
}
|
|
254
|
+
i = str1.indexOf('%');
|
|
255
|
+
}
|
|
256
|
+
return substr + str1;
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Converts tokens for a single address into an address object
|
|
262
|
+
*
|
|
263
|
+
* @param {Array} tokens Tokens object
|
|
264
|
+
* @return {Object} Address object
|
|
265
|
+
*/
|
|
266
|
+
function _handleAddress(tokens) {
|
|
267
|
+
var token;
|
|
268
|
+
var isGroup = false;
|
|
269
|
+
var state = 'text';
|
|
270
|
+
var address;
|
|
271
|
+
var addresses = [];
|
|
272
|
+
var data = {
|
|
273
|
+
address: [],
|
|
274
|
+
comment: [],
|
|
275
|
+
group: [],
|
|
276
|
+
text: [],
|
|
277
|
+
};
|
|
278
|
+
var i;
|
|
279
|
+
var len;
|
|
280
|
+
// Filter out <addresses>, (comments) and regular text
|
|
281
|
+
for (i = 0, len = tokens.length; i < len; i++) {
|
|
282
|
+
token = tokens[i];
|
|
283
|
+
if (token.type === 'operator') {
|
|
284
|
+
switch (token.value) {
|
|
285
|
+
case '<':
|
|
286
|
+
state = 'address';
|
|
287
|
+
break;
|
|
288
|
+
case '(':
|
|
289
|
+
state = 'comment';
|
|
290
|
+
break;
|
|
291
|
+
case ':':
|
|
292
|
+
state = 'group';
|
|
293
|
+
isGroup = true;
|
|
294
|
+
break;
|
|
295
|
+
default:
|
|
296
|
+
state = 'text';
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
else if (token.value) {
|
|
300
|
+
if (state === 'address') {
|
|
301
|
+
// handle use case where unquoted name includes a "<"
|
|
302
|
+
// Apple Mail truncates everything between an unexpected < and an address
|
|
303
|
+
// and so will we
|
|
304
|
+
token.value = token.value.replace(/^[^<]*<\s*/, '');
|
|
305
|
+
}
|
|
306
|
+
data[state].push(token.value);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// If there is no text but a comment, replace the two
|
|
310
|
+
if (!data.text.length && data.comment.length) {
|
|
311
|
+
data.text = data.comment;
|
|
312
|
+
data.comment = [];
|
|
313
|
+
}
|
|
314
|
+
if (isGroup) {
|
|
315
|
+
// http://tools.ietf.org/html/rfc2822#appendix-A.1.3
|
|
316
|
+
data.text = data.text.join(' ');
|
|
317
|
+
addresses.push({
|
|
318
|
+
name: data.text || (address && address.name),
|
|
319
|
+
group: data.group.length ? addressparser(data.group.join(',')) : [],
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
// If no address was found, try to detect one from regular text
|
|
324
|
+
if (!data.address.length && data.text.length) {
|
|
325
|
+
for (i = data.text.length - 1; i >= 0; i--) {
|
|
326
|
+
if (data.text[i].match(/^[^@\s]+@[^@\s]+$/)) {
|
|
327
|
+
data.address = data.text.splice(i, 1);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
var _regexHandler = function (address) {
|
|
332
|
+
if (!data.address.length) {
|
|
333
|
+
data.address = [address.trim()];
|
|
334
|
+
return ' ';
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
return address;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
// still no address
|
|
341
|
+
if (!data.address.length) {
|
|
342
|
+
for (i = data.text.length - 1; i >= 0; i--) {
|
|
343
|
+
// fixed the regex to parse email address correctly when email address has more than one @
|
|
344
|
+
data.text[i] = data.text[i].replace(/\s*\b[^@\s]+@[^\s]+\b\s*/, _regexHandler).trim();
|
|
345
|
+
if (data.address.length) {
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// If there's still is no text but a comment exixts, replace the two
|
|
352
|
+
if (!data.text.length && data.comment.length) {
|
|
353
|
+
data.text = data.comment;
|
|
354
|
+
data.comment = [];
|
|
355
|
+
}
|
|
356
|
+
// Keep only the first address occurence, push others to regular text
|
|
357
|
+
if (data.address.length > 1) {
|
|
358
|
+
data.text = data.text.concat(data.address.splice(1));
|
|
359
|
+
}
|
|
360
|
+
// Join values with spaces
|
|
361
|
+
data.text = data.text.join(' ');
|
|
362
|
+
data.address = data.address.join(' ');
|
|
363
|
+
if (!data.address && isGroup) {
|
|
364
|
+
return [];
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
address = {
|
|
368
|
+
address: data.address || data.text || '',
|
|
369
|
+
name: data.text || data.address || '',
|
|
370
|
+
};
|
|
371
|
+
if (address.address === address.name) {
|
|
372
|
+
if ((address.address || '').match(/@/)) {
|
|
373
|
+
address.name = '';
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
address.address = '';
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
addresses.push(address);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return addresses;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Creates a Tokenizer object for tokenizing address field strings
|
|
386
|
+
*
|
|
387
|
+
* @constructor
|
|
388
|
+
* @param {String} str Address field string
|
|
389
|
+
*/
|
|
390
|
+
var Tokenizer = /** @class */ (function () {
|
|
391
|
+
function Tokenizer(str) {
|
|
392
|
+
this.str = (str || '').toString();
|
|
393
|
+
this.operatorCurrent = '';
|
|
394
|
+
this.operatorExpecting = '';
|
|
395
|
+
this.node = null;
|
|
396
|
+
this.escaped = false;
|
|
397
|
+
this.list = [];
|
|
398
|
+
/**
|
|
399
|
+
* Operator tokens and which tokens are expected to end the sequence
|
|
400
|
+
*/
|
|
401
|
+
this.operators = {
|
|
402
|
+
'"': '"',
|
|
403
|
+
'(': ')',
|
|
404
|
+
'<': '>',
|
|
405
|
+
',': '',
|
|
406
|
+
':': ';',
|
|
407
|
+
// Semicolons are not a legal delimiter per the RFC2822 grammar other
|
|
408
|
+
// than for terminating a group, but they are also not valid for any
|
|
409
|
+
// other use in this context. Given that some mail clients have
|
|
410
|
+
// historically allowed the semicolon as a delimiter equivalent to the
|
|
411
|
+
// comma in their UI, it makes sense to treat them the same as a comma
|
|
412
|
+
// when used outside of a group.
|
|
413
|
+
';': '',
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Tokenizes the original input string
|
|
418
|
+
*
|
|
419
|
+
* @return {Array} An array of operator|text tokens
|
|
420
|
+
*/
|
|
421
|
+
Tokenizer.prototype.tokenize = function () {
|
|
422
|
+
var chr, list = [];
|
|
423
|
+
for (var i = 0, len = this.str.length; i < len; i++) {
|
|
424
|
+
chr = this.str.charAt(i);
|
|
425
|
+
this.checkChar(chr);
|
|
426
|
+
}
|
|
427
|
+
this.list.forEach(function (node) {
|
|
428
|
+
node.value = (node.value || '').toString().trim();
|
|
429
|
+
if (node.value) {
|
|
430
|
+
list.push(node);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
return list;
|
|
434
|
+
};
|
|
435
|
+
/**
|
|
436
|
+
* Checks if a character is an operator or text and acts accordingly
|
|
437
|
+
*
|
|
438
|
+
* @param {String} chr Character from the address field
|
|
439
|
+
*/
|
|
440
|
+
Tokenizer.prototype.checkChar = function (chr) {
|
|
441
|
+
if (this.escaped) ;
|
|
442
|
+
else if (chr === this.operatorExpecting) {
|
|
443
|
+
this.node = {
|
|
444
|
+
type: 'operator',
|
|
445
|
+
value: chr,
|
|
446
|
+
};
|
|
447
|
+
this.list.push(this.node);
|
|
448
|
+
this.node = null;
|
|
449
|
+
this.operatorExpecting = '';
|
|
450
|
+
this.escaped = false;
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
else if (!this.operatorExpecting && chr in this.operators) {
|
|
454
|
+
this.node = {
|
|
455
|
+
type: 'operator',
|
|
456
|
+
value: chr,
|
|
457
|
+
};
|
|
458
|
+
this.list.push(this.node);
|
|
459
|
+
this.node = null;
|
|
460
|
+
this.operatorExpecting = this.operators[chr];
|
|
461
|
+
this.escaped = false;
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
else if (['"', "'"].includes(this.operatorExpecting) && chr === '\\') {
|
|
465
|
+
this.escaped = true;
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (!this.node) {
|
|
469
|
+
this.node = {
|
|
470
|
+
type: 'text',
|
|
471
|
+
value: '',
|
|
472
|
+
};
|
|
473
|
+
this.list.push(this.node);
|
|
474
|
+
}
|
|
475
|
+
if (chr === '\n') {
|
|
476
|
+
// Convert newlines to spaces. Carriage return is ignored as \r and \n usually
|
|
477
|
+
// go together anyway and there already is a WS for \n. Lone \r means something is fishy.
|
|
478
|
+
chr = ' ';
|
|
479
|
+
}
|
|
480
|
+
if (chr.charCodeAt(0) >= 0x21 || [' ', '\t'].includes(chr)) {
|
|
481
|
+
// skip command bytes
|
|
482
|
+
this.node.value += chr;
|
|
483
|
+
}
|
|
484
|
+
this.escaped = false;
|
|
485
|
+
};
|
|
486
|
+
return Tokenizer;
|
|
487
|
+
}());
|
|
488
|
+
/**
|
|
489
|
+
* Parses structured e-mail addresses from an address field
|
|
490
|
+
*
|
|
491
|
+
* Example:
|
|
492
|
+
*
|
|
493
|
+
* 'Name <address@domain>'
|
|
494
|
+
*
|
|
495
|
+
* will be converted to
|
|
496
|
+
*
|
|
497
|
+
* [{name: 'Name', address: 'address@domain'}]
|
|
498
|
+
*
|
|
499
|
+
* @param {String} str Address field
|
|
500
|
+
* @return {Array} An array of address objects
|
|
501
|
+
*/
|
|
502
|
+
function addressparser(str, options) {
|
|
503
|
+
options = options || {};
|
|
504
|
+
var tokenizer = new Tokenizer(str);
|
|
505
|
+
var tokens = tokenizer.tokenize();
|
|
506
|
+
var addresses = [];
|
|
507
|
+
var address = [];
|
|
508
|
+
var parsedAddresses = [];
|
|
509
|
+
tokens.forEach(function (token) {
|
|
510
|
+
if (token.type === 'operator' && (token.value === ',' || token.value === ';')) {
|
|
511
|
+
if (address.length) {
|
|
512
|
+
addresses.push(address);
|
|
513
|
+
}
|
|
514
|
+
address = [];
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
address.push(token);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
if (address.length) {
|
|
521
|
+
addresses.push(address);
|
|
522
|
+
}
|
|
523
|
+
addresses.forEach(function (address) {
|
|
524
|
+
address = _handleAddress(address);
|
|
525
|
+
if (address.length) {
|
|
526
|
+
parsedAddresses = parsedAddresses.concat(address);
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
if (options.flatten) {
|
|
530
|
+
var addresses_1 = [];
|
|
531
|
+
var walkAddressList_1 = function (list) {
|
|
532
|
+
list.forEach(function (address) {
|
|
533
|
+
if (address.group) {
|
|
534
|
+
return walkAddressList_1(address.group);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
addresses_1.push(address);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
};
|
|
541
|
+
walkAddressList_1(parsedAddresses);
|
|
542
|
+
return addresses_1;
|
|
543
|
+
}
|
|
544
|
+
return parsedAddresses;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* @author superchow
|
|
549
|
+
* @emil superchow@live.cn
|
|
550
|
+
*/
|
|
551
|
+
/**
|
|
552
|
+
* log for test
|
|
553
|
+
*/
|
|
554
|
+
var verbose = false;
|
|
555
|
+
var defaultCharset = 'utf-8';
|
|
556
|
+
/**
|
|
557
|
+
* create a boundary
|
|
558
|
+
*/
|
|
559
|
+
function createBoundary() {
|
|
560
|
+
return '----=' + guid();
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Builds e-mail address string, e.g. { name: 'PayPal', email: 'noreply@paypal.com' } => 'PayPal' <noreply@paypal.com>
|
|
564
|
+
* @param {String|EmailAddress|EmailAddress[]|null} data
|
|
565
|
+
*/
|
|
566
|
+
function toEmailAddress(data) {
|
|
567
|
+
var email = '';
|
|
568
|
+
if (typeof data === 'undefined') ;
|
|
569
|
+
else if (typeof data === 'string') {
|
|
570
|
+
email = data;
|
|
571
|
+
}
|
|
572
|
+
else if (typeof data === 'object') {
|
|
573
|
+
if (Array.isArray(data)) {
|
|
574
|
+
email += data
|
|
575
|
+
.map(function (item) {
|
|
576
|
+
var str = '';
|
|
577
|
+
if (item.name) {
|
|
578
|
+
str += '"' + item.name.replace(/^"|"\s*$/g, '') + '" ';
|
|
579
|
+
}
|
|
580
|
+
if (item.email) {
|
|
581
|
+
str += '<' + item.email + '>';
|
|
582
|
+
}
|
|
583
|
+
return str;
|
|
584
|
+
})
|
|
585
|
+
.filter(function (a) { return a; })
|
|
586
|
+
.join(', ');
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
if (data) {
|
|
590
|
+
if (data.name) {
|
|
591
|
+
email += '"' + data.name.replace(/^"|"\s*$/g, '') + '" ';
|
|
592
|
+
}
|
|
593
|
+
if (data.email) {
|
|
594
|
+
email += '<' + data.email + '>';
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return email;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Gets character set name, e.g. contentType='.....charset='iso-8859-2'....'
|
|
603
|
+
* @param {String} contentType
|
|
604
|
+
* @returns {String|undefined}
|
|
605
|
+
*/
|
|
606
|
+
function getCharset(contentType) {
|
|
607
|
+
var match = /charset\s*=\W*([\w\-]+)/g.exec(contentType);
|
|
608
|
+
return match ? match[1] : undefined;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Gets name and e-mail address from a string, e.g. 'PayPal' <noreply@paypal.com> => { name: 'PayPal', email: 'noreply@paypal.com' }
|
|
612
|
+
* @param {String} raw
|
|
613
|
+
* @returns { EmailAddress | EmailAddress[] | null}
|
|
614
|
+
*/
|
|
615
|
+
function getEmailAddress(rawStr) {
|
|
616
|
+
var raw = unquoteString(rawStr);
|
|
617
|
+
var parseList = addressparser(raw);
|
|
618
|
+
var list = parseList.map(function (v) { return ({ name: v.name, email: v.address }); });
|
|
619
|
+
//Return result
|
|
620
|
+
if (list.length === 0) {
|
|
621
|
+
return null; //No e-mail address
|
|
622
|
+
}
|
|
623
|
+
if (list.length === 1) {
|
|
624
|
+
return list[0]; //Only one record, return as object, required to preserve backward compatibility
|
|
625
|
+
}
|
|
626
|
+
return list; //Multiple e-mail addresses as array
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* decode one joint
|
|
630
|
+
* @param {String} str
|
|
631
|
+
* @returns {String}
|
|
632
|
+
*/
|
|
633
|
+
function decodeJoint(str) {
|
|
634
|
+
var match = /=\?([^?]+)\?(B|Q)\?(.+?)(\?=)/gi.exec(str);
|
|
635
|
+
if (match) {
|
|
636
|
+
var charset = getCharsetName(match[1] || defaultCharset); //eq. match[1] = 'iso-8859-2'; charset = 'iso88592'
|
|
637
|
+
var type = match[2].toUpperCase();
|
|
638
|
+
var value = match[3];
|
|
639
|
+
if (type === 'B') {
|
|
640
|
+
//Base64
|
|
641
|
+
if (charset === 'utf8') {
|
|
642
|
+
return decode(encode(jsBase64.Base64.fromBase64(value.replace(/\r?\n/g, ''))), 'utf8');
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
return decode(jsBase64.Base64.toUint8Array(value.replace(/\r?\n/g, '')), charset);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
else if (type === 'Q') {
|
|
649
|
+
//Quoted printable
|
|
650
|
+
return unquotePrintable(value, charset, true);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return str;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* decode section
|
|
657
|
+
* @param {String} str
|
|
658
|
+
* @returns {String}
|
|
659
|
+
*/
|
|
660
|
+
function unquoteString(str) {
|
|
661
|
+
var regex = /=\?([^?]+)\?(B|Q)\?(.+?)(\?=)/gi;
|
|
662
|
+
var decodedString = str || '';
|
|
663
|
+
var spinOffMatch = decodedString.match(regex);
|
|
664
|
+
if (spinOffMatch) {
|
|
665
|
+
spinOffMatch.forEach(function (spin) {
|
|
666
|
+
decodedString = decodedString.replace(spin, decodeJoint(spin));
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
return decodedString.replace(/\r?\n/g, '');
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Decodes 'quoted-printable'
|
|
673
|
+
* @param {String} value
|
|
674
|
+
* @param {String} charset
|
|
675
|
+
* @param {String} qEncoding whether the encoding is RFC-2047’s Q-encoding, meaning special handling of underscores.
|
|
676
|
+
* @returns {String}
|
|
677
|
+
*/
|
|
678
|
+
function unquotePrintable(value, charset, qEncoding) {
|
|
679
|
+
//Convert =0D to '\r', =20 to ' ', etc.
|
|
680
|
+
// if (!charset || charset == "utf8" || charset == "utf-8") {
|
|
681
|
+
// return value
|
|
682
|
+
// .replace(/=([\w\d]{2})=([\w\d]{2})=([\w\d]{2})/gi, function (matcher, p1, p2, p3, offset, string) {
|
|
683
|
+
if (qEncoding === void 0) { qEncoding = false; }
|
|
684
|
+
// })
|
|
685
|
+
// .replace(/=([\w\d]{2})=([\w\d]{2})/gi, function (matcher, p1, p2, offset, string) {
|
|
686
|
+
// })
|
|
687
|
+
// .replace(/=([\w\d]{2})/gi, function (matcher, p1, offset, string) { return String.fromCharCode(parseInt(p1, 16)); })
|
|
688
|
+
// .replace(/=\r?\n/gi, ""); //Join line
|
|
689
|
+
// } else {
|
|
690
|
+
// return value
|
|
691
|
+
// .replace(/=([\w\d]{2})=([\w\d]{2})/gi, function (matcher, p1, p2, offset, string) {
|
|
692
|
+
// })
|
|
693
|
+
// .replace(/=([\w\d]{2})/gi, function (matcher, p1, offset, string) {
|
|
694
|
+
// })
|
|
695
|
+
// .replace(/=\r?\n/gi, ''); //Join line
|
|
696
|
+
// }
|
|
697
|
+
var rawString = value
|
|
698
|
+
.replace(/[\t ]+$/gm, '') // remove invalid whitespace from the end of lines
|
|
699
|
+
.replace(/=(?:\r?\n|$)/g, ''); // remove soft line breaks
|
|
700
|
+
if (qEncoding) {
|
|
701
|
+
rawString = rawString.replace(/_/g, decode(new Uint8Array([0x20]), charset));
|
|
702
|
+
}
|
|
703
|
+
return mimeDecode(rawString, charset);
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Parses EML file content and returns object-oriented representation of the content.
|
|
707
|
+
* @param {String} eml
|
|
708
|
+
* @param {OptionOrNull | CallbackFn<ParsedEmlJson>} options
|
|
709
|
+
* @param {CallbackFn<ParsedEmlJson>} callback
|
|
710
|
+
* @returns {string | Error | ParsedEmlJson}
|
|
711
|
+
*/
|
|
712
|
+
function parse(eml, options, callback) {
|
|
713
|
+
//Shift arguments
|
|
714
|
+
if (typeof options === 'function' && typeof callback === 'undefined') {
|
|
715
|
+
callback = options;
|
|
716
|
+
options = null;
|
|
717
|
+
}
|
|
718
|
+
if (typeof options !== 'object') {
|
|
719
|
+
options = { headersOnly: false };
|
|
720
|
+
}
|
|
721
|
+
var error;
|
|
722
|
+
var result = {};
|
|
723
|
+
try {
|
|
724
|
+
if (typeof eml !== 'string') {
|
|
725
|
+
throw new Error('Argument "eml" expected to be string!');
|
|
726
|
+
}
|
|
727
|
+
var lines = eml.split(/\r?\n/);
|
|
728
|
+
result = parseRecursive(lines, 0, result, options);
|
|
729
|
+
}
|
|
730
|
+
catch (e) {
|
|
731
|
+
error = e;
|
|
732
|
+
}
|
|
733
|
+
callback && callback(error, result);
|
|
734
|
+
return error || result || new Error('read EML failed!');
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Parses EML file content.
|
|
738
|
+
* @param {String[]} lines
|
|
739
|
+
* @param {Number} start
|
|
740
|
+
* @param {Options} options
|
|
741
|
+
* @returns {ParsedEmlJson}
|
|
742
|
+
*/
|
|
743
|
+
function parseRecursive(lines, start, parent, options) {
|
|
744
|
+
var boundary = null;
|
|
745
|
+
var lastHeaderName = '';
|
|
746
|
+
var findBoundary = '';
|
|
747
|
+
var insideBody = false;
|
|
748
|
+
var insideBoundary = false;
|
|
749
|
+
var isMultiHeader = false;
|
|
750
|
+
var isMultipart = false;
|
|
751
|
+
var checkedForCt = false;
|
|
752
|
+
var ctInBody = false;
|
|
753
|
+
parent.headers = {};
|
|
754
|
+
//parent.body = null;
|
|
755
|
+
function complete(boundary) {
|
|
756
|
+
//boundary.part = boundary.lines.join("\r\n");
|
|
757
|
+
boundary.part = {};
|
|
758
|
+
parseRecursive(boundary.lines, 0, boundary.part, options);
|
|
759
|
+
delete boundary.lines;
|
|
760
|
+
}
|
|
761
|
+
//Read line by line
|
|
762
|
+
for (var i = start; i < lines.length; i++) {
|
|
763
|
+
var line = lines[i];
|
|
764
|
+
//Header
|
|
765
|
+
if (!insideBody) {
|
|
766
|
+
//Search for empty line
|
|
767
|
+
if (line == '') {
|
|
768
|
+
insideBody = true;
|
|
769
|
+
if (options && options.headersOnly) {
|
|
770
|
+
break;
|
|
771
|
+
}
|
|
772
|
+
//Expected boundary
|
|
773
|
+
var ct = parent.headers['Content-Type'] || parent.headers['Content-type'];
|
|
774
|
+
if (!ct) {
|
|
775
|
+
if (checkedForCt) {
|
|
776
|
+
insideBody = !ctInBody;
|
|
777
|
+
}
|
|
778
|
+
else {
|
|
779
|
+
checkedForCt = true;
|
|
780
|
+
var lineClone = Array.from(lines);
|
|
781
|
+
var string = lineClone.splice(i).join('\r\n');
|
|
782
|
+
var trimmedStrin = string.trim();
|
|
783
|
+
if (trimmedStrin.indexOf('Content-Type') === 0 || trimmedStrin.indexOf('Content-type') === 0) {
|
|
784
|
+
insideBody = false;
|
|
785
|
+
ctInBody = true;
|
|
786
|
+
}
|
|
787
|
+
else {
|
|
788
|
+
console.warn('Warning: undefined Content-Type');
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
else if (/^multipart\//g.test(ct)) {
|
|
793
|
+
var b = getBoundary(ct);
|
|
794
|
+
if (b && b.length) {
|
|
795
|
+
findBoundary = b;
|
|
796
|
+
isMultipart = true;
|
|
797
|
+
parent.body = [];
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
//Header value with new line
|
|
803
|
+
var match = /^\s+([^\r\n]+)/g.exec(line);
|
|
804
|
+
if (match) {
|
|
805
|
+
if (isMultiHeader) {
|
|
806
|
+
parent.headers[lastHeaderName][parent.headers[lastHeaderName].length - 1] += '\r\n' + match[1];
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
parent.headers[lastHeaderName] += '\r\n' + match[1];
|
|
810
|
+
}
|
|
811
|
+
continue;
|
|
812
|
+
}
|
|
813
|
+
//Header name and value
|
|
814
|
+
match = /^([\w\d\-]+):\s*([^\r\n]*)/gi.exec(line);
|
|
815
|
+
if (match) {
|
|
816
|
+
lastHeaderName = match[1];
|
|
817
|
+
if (parent.headers[lastHeaderName]) {
|
|
818
|
+
//Multiple headers with the same name
|
|
819
|
+
isMultiHeader = true;
|
|
820
|
+
if (typeof parent.headers[lastHeaderName] == 'string') {
|
|
821
|
+
parent.headers[lastHeaderName] = [parent.headers[lastHeaderName]];
|
|
822
|
+
}
|
|
823
|
+
parent.headers[lastHeaderName].push(match[2]);
|
|
824
|
+
}
|
|
825
|
+
else {
|
|
826
|
+
//Header first appeared here
|
|
827
|
+
isMultiHeader = false;
|
|
828
|
+
parent.headers[lastHeaderName] = match[2];
|
|
829
|
+
}
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
//Body
|
|
834
|
+
else {
|
|
835
|
+
//Multipart body
|
|
836
|
+
if (isMultipart) {
|
|
837
|
+
//Search for boundary start
|
|
838
|
+
//Updated on 2019-10-12: A line before the boundary marker is not required to be an empty line
|
|
839
|
+
//if (lines[i - 1] == "" && line.indexOf("--" + findBoundary) == 0 && !/\-\-(\r?\n)?$/g.test(line)) {
|
|
840
|
+
if (line.indexOf('--' + findBoundary) == 0 && !/\-\-(\r?\n)?$/g.test(line)) {
|
|
841
|
+
insideBoundary = true;
|
|
842
|
+
//Complete the previous boundary
|
|
843
|
+
if (boundary && boundary.lines) {
|
|
844
|
+
complete(boundary);
|
|
845
|
+
}
|
|
846
|
+
//Start a new boundary
|
|
847
|
+
var match = /^\-\-([^\r\n]+)(\r?\n)?$/g.exec(line);
|
|
848
|
+
boundary = { boundary: match[1], lines: [] };
|
|
849
|
+
parent.body.push(boundary);
|
|
850
|
+
continue;
|
|
851
|
+
}
|
|
852
|
+
if (insideBoundary) {
|
|
853
|
+
//Search for boundary end
|
|
854
|
+
if ((boundary === null || boundary === void 0 ? void 0 : boundary.boundary) && lines[i - 1] == '' && line.indexOf('--' + findBoundary + '--') == 0) {
|
|
855
|
+
insideBoundary = false;
|
|
856
|
+
complete(boundary);
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
if ((boundary === null || boundary === void 0 ? void 0 : boundary.boundary) && line.indexOf('--' + findBoundary + '--') == 0) {
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
boundary === null || boundary === void 0 ? void 0 : boundary.lines.push(line);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
//Solid string body
|
|
867
|
+
parent.body = lines.splice(i).join('\r\n');
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
//Complete the last boundary
|
|
873
|
+
if (parent.body && parent.body.length && parent.body[parent.body.length - 1].lines) {
|
|
874
|
+
complete(parent.body[parent.body.length - 1]);
|
|
875
|
+
}
|
|
876
|
+
return parent;
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Convert BoundaryRawData to BoundaryConvertedData
|
|
880
|
+
* @param {BoundaryRawData} boundary
|
|
881
|
+
* @returns {BoundaryConvertedData} Obj
|
|
882
|
+
*/
|
|
883
|
+
function completeBoundary(boundary) {
|
|
884
|
+
if (!boundary || !boundary.boundary) {
|
|
885
|
+
return null;
|
|
886
|
+
}
|
|
887
|
+
var lines = boundary.lines || [];
|
|
888
|
+
var result = {
|
|
889
|
+
boundary: boundary.boundary,
|
|
890
|
+
part: {
|
|
891
|
+
headers: {},
|
|
892
|
+
},
|
|
893
|
+
};
|
|
894
|
+
var lastHeaderName = '';
|
|
895
|
+
var insideBody = false;
|
|
896
|
+
var childBoundary;
|
|
897
|
+
for (var index = 0; index < lines.length; index++) {
|
|
898
|
+
var line = lines[index];
|
|
899
|
+
if (!insideBody) {
|
|
900
|
+
if (line === '') {
|
|
901
|
+
insideBody = true;
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
var match = /^([\w\d\-]+):\s*([^\r\n]*)/gi.exec(line);
|
|
905
|
+
if (match) {
|
|
906
|
+
lastHeaderName = match[1];
|
|
907
|
+
result.part.headers[lastHeaderName] = match[2];
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
910
|
+
//Header value with new line
|
|
911
|
+
var lineMatch = /^\s+([^\r\n]+)/g.exec(line);
|
|
912
|
+
if (lineMatch) {
|
|
913
|
+
result.part.headers[lastHeaderName] += '\r\n' + lineMatch[1];
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
else {
|
|
918
|
+
// part.body
|
|
919
|
+
var match = /^\-\-([^\r\n]+)(\r?\n)?$/g.exec(line);
|
|
920
|
+
var childBoundaryStr = getBoundary(result.part.headers['Content-Type'] || result.part.headers['Content-type']);
|
|
921
|
+
if (match && line.indexOf('--' + childBoundaryStr) === 0 && !childBoundary) {
|
|
922
|
+
childBoundary = { boundary: match ? match[1] : '', lines: [] };
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
else if (!!childBoundary && childBoundary.boundary) {
|
|
926
|
+
if (lines[index - 1] === '' && line.indexOf('--' + childBoundary.boundary) === 0) {
|
|
927
|
+
var child = completeBoundary(childBoundary);
|
|
928
|
+
if (child) {
|
|
929
|
+
if (Array.isArray(result.part.body)) {
|
|
930
|
+
result.part.body.push(child);
|
|
931
|
+
}
|
|
932
|
+
else {
|
|
933
|
+
result.part.body = [child];
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
else {
|
|
937
|
+
result.part.body = childBoundary.lines.join('\r\n');
|
|
938
|
+
}
|
|
939
|
+
// next line child
|
|
940
|
+
if (!!lines[index + 1]) {
|
|
941
|
+
childBoundary.lines = [];
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
// end line child And this boundary's end
|
|
945
|
+
if (line.indexOf('--' + childBoundary.boundary + '--') === 0 && lines[index + 1] === '') {
|
|
946
|
+
childBoundary = undefined;
|
|
947
|
+
break;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
childBoundary.lines.push(line);
|
|
951
|
+
}
|
|
952
|
+
else {
|
|
953
|
+
result.part.body = lines.splice(index).join('\r\n');
|
|
954
|
+
break;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return result;
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* buid EML file by ReadedEmlJson or EML file content
|
|
962
|
+
* @param {ReadedEmlJson} data
|
|
963
|
+
* @param {BuildOptions | CallbackFn<string> | null} options
|
|
964
|
+
* @param {CallbackFn<string>} callback
|
|
965
|
+
*/
|
|
966
|
+
function build(data, options, callback) {
|
|
967
|
+
//Shift arguments
|
|
968
|
+
if (typeof options === 'function' && typeof callback === 'undefined') {
|
|
969
|
+
callback = options;
|
|
970
|
+
options = null;
|
|
971
|
+
}
|
|
972
|
+
var error;
|
|
973
|
+
var eml = '';
|
|
974
|
+
var EOL = '\r\n'; //End-of-line
|
|
975
|
+
try {
|
|
976
|
+
if (!data) {
|
|
977
|
+
throw new Error('Argument "data" expected to be an object! or string');
|
|
978
|
+
}
|
|
979
|
+
if (typeof data === 'string') {
|
|
980
|
+
var readResult = read(data);
|
|
981
|
+
if (typeof readResult === 'string') {
|
|
982
|
+
throw new Error(readResult);
|
|
983
|
+
}
|
|
984
|
+
else if (readResult instanceof Error) {
|
|
985
|
+
throw readResult;
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
data = readResult;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
if (!data.headers) {
|
|
992
|
+
throw new Error('Argument "data" expected to be has headers');
|
|
993
|
+
}
|
|
994
|
+
if (typeof data.subject === 'string') {
|
|
995
|
+
data.headers['Subject'] = data.subject;
|
|
996
|
+
}
|
|
997
|
+
if (typeof data.from !== 'undefined') {
|
|
998
|
+
data.headers['From'] = toEmailAddress(data.from);
|
|
999
|
+
}
|
|
1000
|
+
if (typeof data.to !== 'undefined') {
|
|
1001
|
+
data.headers['To'] = toEmailAddress(data.to);
|
|
1002
|
+
}
|
|
1003
|
+
if (typeof data.cc !== 'undefined') {
|
|
1004
|
+
data.headers['Cc'] = toEmailAddress(data.cc);
|
|
1005
|
+
}
|
|
1006
|
+
// if (!data.headers['To']) {
|
|
1007
|
+
// throw new Error('Missing "To" e-mail address!');
|
|
1008
|
+
// }
|
|
1009
|
+
var emlBoundary = getBoundary(data.headers['Content-Type'] || data.headers['Content-type'] || '');
|
|
1010
|
+
var hasBoundary = false;
|
|
1011
|
+
var boundary = createBoundary();
|
|
1012
|
+
var multipartBoundary = '';
|
|
1013
|
+
if (data.multipartAlternative) {
|
|
1014
|
+
multipartBoundary = '' + (getBoundary(data.multipartAlternative['Content-Type']) || '');
|
|
1015
|
+
hasBoundary = true;
|
|
1016
|
+
}
|
|
1017
|
+
if (emlBoundary) {
|
|
1018
|
+
boundary = emlBoundary;
|
|
1019
|
+
hasBoundary = true;
|
|
1020
|
+
}
|
|
1021
|
+
else {
|
|
1022
|
+
data.headers['Content-Type'] = data.headers['Content-type'] || 'multipart/mixed;' + EOL + 'boundary="' + boundary + '"';
|
|
1023
|
+
// Restrained
|
|
1024
|
+
// hasBoundary = true;
|
|
1025
|
+
}
|
|
1026
|
+
//Build headers
|
|
1027
|
+
var keys = Object.keys(data.headers);
|
|
1028
|
+
for (var i = 0; i < keys.length; i++) {
|
|
1029
|
+
var key = keys[i];
|
|
1030
|
+
var value = data.headers[key];
|
|
1031
|
+
if (typeof value === 'undefined') {
|
|
1032
|
+
continue; //Skip missing headers
|
|
1033
|
+
}
|
|
1034
|
+
else if (typeof value === 'string') {
|
|
1035
|
+
eml += key + ': ' + value.replace(/\r?\n/g, EOL + ' ') + EOL;
|
|
1036
|
+
}
|
|
1037
|
+
else {
|
|
1038
|
+
//Array
|
|
1039
|
+
for (var j = 0; j < value.length; j++) {
|
|
1040
|
+
eml += key + ': ' + value[j].replace(/\r?\n/g, EOL + ' ') + EOL;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
if (data.multipartAlternative) {
|
|
1045
|
+
eml += EOL;
|
|
1046
|
+
eml += '--' + emlBoundary + EOL;
|
|
1047
|
+
eml += 'Content-Type: ' + data.multipartAlternative['Content-Type'].replace(/\r?\n/g, EOL + ' ') + EOL;
|
|
1048
|
+
}
|
|
1049
|
+
//Start the body
|
|
1050
|
+
eml += EOL;
|
|
1051
|
+
//Plain text content
|
|
1052
|
+
if (data.text) {
|
|
1053
|
+
// Encode opened and self headers keeped
|
|
1054
|
+
if (typeof options === 'object' && !!options && options.encode && data.textheaders) {
|
|
1055
|
+
eml += '--' + boundary + EOL;
|
|
1056
|
+
for (var key in data.textheaders) {
|
|
1057
|
+
if (data.textheaders.hasOwnProperty(key)) {
|
|
1058
|
+
eml += key + ": " + data.textheaders[key].replace(/\r?\n/g, EOL + ' ');
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
else if (hasBoundary) {
|
|
1063
|
+
// else Assembly
|
|
1064
|
+
eml += '--' + (multipartBoundary ? multipartBoundary : boundary) + EOL;
|
|
1065
|
+
eml += 'Content-Type: text/plain; charset="utf-8"' + EOL;
|
|
1066
|
+
}
|
|
1067
|
+
eml += EOL + data.text;
|
|
1068
|
+
eml += EOL;
|
|
1069
|
+
}
|
|
1070
|
+
//HTML content
|
|
1071
|
+
if (data.html) {
|
|
1072
|
+
// Encode opened and self headers keeped
|
|
1073
|
+
if (typeof options === 'object' && !!options && options.encode && data.textheaders) {
|
|
1074
|
+
eml += '--' + boundary + EOL;
|
|
1075
|
+
for (var key in data.textheaders) {
|
|
1076
|
+
if (data.textheaders.hasOwnProperty(key)) {
|
|
1077
|
+
eml += key + ": " + data.textheaders[key].replace(/\r?\n/g, EOL + ' ');
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
else if (hasBoundary) {
|
|
1082
|
+
eml += '--' + (multipartBoundary ? multipartBoundary : boundary) + EOL;
|
|
1083
|
+
eml += 'Content-Type: text/html; charset="utf-8"' + EOL;
|
|
1084
|
+
}
|
|
1085
|
+
if (verbose) {
|
|
1086
|
+
console.info("line 765 " + hasBoundary + ", emlBoundary: " + emlBoundary + ", multipartBoundary: " + multipartBoundary + ", boundary: " + boundary);
|
|
1087
|
+
}
|
|
1088
|
+
eml += EOL + data.html;
|
|
1089
|
+
eml += EOL;
|
|
1090
|
+
}
|
|
1091
|
+
//Append attachments
|
|
1092
|
+
if (data.attachments) {
|
|
1093
|
+
for (var i = 0; i < data.attachments.length; i++) {
|
|
1094
|
+
var attachment = data.attachments[i];
|
|
1095
|
+
eml += '--' + boundary + EOL;
|
|
1096
|
+
eml += 'Content-Type: ' + (attachment.contentType.replace(/\r?\n/g, EOL + ' ') || 'application/octet-stream') + EOL;
|
|
1097
|
+
eml += 'Content-Transfer-Encoding: base64' + EOL;
|
|
1098
|
+
eml +=
|
|
1099
|
+
'Content-Disposition: ' +
|
|
1100
|
+
(attachment.inline ? 'inline' : 'attachment') +
|
|
1101
|
+
'; filename="' +
|
|
1102
|
+
(attachment.filename || attachment.name || 'attachment_' + (i + 1)) +
|
|
1103
|
+
'"' +
|
|
1104
|
+
EOL;
|
|
1105
|
+
if (attachment.cid) {
|
|
1106
|
+
eml += 'Content-ID: <' + attachment.cid + '>' + EOL;
|
|
1107
|
+
}
|
|
1108
|
+
eml += EOL;
|
|
1109
|
+
if (typeof attachment.data === 'string') {
|
|
1110
|
+
var content = jsBase64.Base64.toBase64(attachment.data);
|
|
1111
|
+
eml += wrap(content, 72) + EOL;
|
|
1112
|
+
}
|
|
1113
|
+
else {
|
|
1114
|
+
//Buffer
|
|
1115
|
+
// Uint8Array to string by new TextEncoder
|
|
1116
|
+
var content = decode(attachment.data);
|
|
1117
|
+
eml += wrap(content, 72) + EOL;
|
|
1118
|
+
}
|
|
1119
|
+
eml += EOL;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
//Finish the boundary
|
|
1123
|
+
if (hasBoundary) {
|
|
1124
|
+
eml += '--' + boundary + '--' + EOL;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
catch (e) {
|
|
1128
|
+
error = e;
|
|
1129
|
+
}
|
|
1130
|
+
callback && callback(error, eml);
|
|
1131
|
+
return error || eml;
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* Parses EML file content and return user-friendly object.
|
|
1135
|
+
* @param {String | ParsedEmlJson} eml EML file content or object from 'parse'
|
|
1136
|
+
* @param { OptionOrNull | CallbackFn<ReadedEmlJson>} options EML parse options
|
|
1137
|
+
* @param {CallbackFn<ReadedEmlJson>} callback Callback function(error, data)
|
|
1138
|
+
*/
|
|
1139
|
+
function read(eml, options, callback) {
|
|
1140
|
+
//Shift arguments
|
|
1141
|
+
if (typeof options === 'function' && typeof callback === 'undefined') {
|
|
1142
|
+
callback = options;
|
|
1143
|
+
options = null;
|
|
1144
|
+
}
|
|
1145
|
+
var error;
|
|
1146
|
+
var result;
|
|
1147
|
+
//Appends the boundary to the result
|
|
1148
|
+
function _append(headers, content, result) {
|
|
1149
|
+
var contentType = headers['Content-Type'] || headers['Content-type'];
|
|
1150
|
+
var contentDisposition = headers['Content-Disposition'];
|
|
1151
|
+
var charset = getCharsetName(getCharset(contentType) || defaultCharset);
|
|
1152
|
+
var encoding = headers['Content-Transfer-Encoding'] || headers['Content-transfer-encoding'];
|
|
1153
|
+
if (typeof encoding === 'string') {
|
|
1154
|
+
encoding = encoding.toLowerCase();
|
|
1155
|
+
}
|
|
1156
|
+
if (encoding === 'base64') {
|
|
1157
|
+
if (contentType && contentType.indexOf('gbk') >= 0) {
|
|
1158
|
+
// is work? I'm not sure
|
|
1159
|
+
content = encode(GB2312UTF8.GB2312ToUTF8(content.replace(/\r?\n/g, '')));
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
// string to Uint8Array by TextEncoder
|
|
1163
|
+
content = encode(content.replace(/\r?\n/g, ''));
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
else if (encoding === 'quoted-printable') {
|
|
1167
|
+
content = unquotePrintable(content, charset);
|
|
1168
|
+
}
|
|
1169
|
+
else if (encoding && charset !== 'utf8' && encoding.search(/binary|8bit/) === 0) {
|
|
1170
|
+
//'8bit', 'binary', '8bitmime', 'binarymime'
|
|
1171
|
+
content = decode(content, charset);
|
|
1172
|
+
}
|
|
1173
|
+
if (!contentDisposition && contentType && contentType.indexOf('text/html') >= 0) {
|
|
1174
|
+
if (typeof content !== 'string') {
|
|
1175
|
+
content = decode(content, charset);
|
|
1176
|
+
}
|
|
1177
|
+
var htmlContent = content.replace(/\r\n|(")/g, '').replace(/\"/g, "\"");
|
|
1178
|
+
try {
|
|
1179
|
+
if (encoding === 'base64') {
|
|
1180
|
+
htmlContent = jsBase64.Base64.decode(htmlContent);
|
|
1181
|
+
}
|
|
1182
|
+
else if (jsBase64.Base64.btoa(jsBase64.Base64.atob(htmlContent)) == htmlContent) {
|
|
1183
|
+
htmlContent = jsBase64.Base64.atob(htmlContent);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
catch (error) {
|
|
1187
|
+
console.error(error);
|
|
1188
|
+
}
|
|
1189
|
+
if (result.html) {
|
|
1190
|
+
result.html += htmlContent;
|
|
1191
|
+
}
|
|
1192
|
+
else {
|
|
1193
|
+
result.html = htmlContent;
|
|
1194
|
+
}
|
|
1195
|
+
result.htmlheaders = {
|
|
1196
|
+
'Content-Type': contentType,
|
|
1197
|
+
'Content-Transfer-Encoding': encoding || '',
|
|
1198
|
+
};
|
|
1199
|
+
// self boundary Not used at conversion
|
|
1200
|
+
}
|
|
1201
|
+
else if (!contentDisposition && contentType && contentType.indexOf('text/plain') >= 0) {
|
|
1202
|
+
if (typeof content !== 'string') {
|
|
1203
|
+
content = decode(content, charset);
|
|
1204
|
+
}
|
|
1205
|
+
if (encoding === 'base64') {
|
|
1206
|
+
content = jsBase64.Base64.decode(content);
|
|
1207
|
+
}
|
|
1208
|
+
//Plain text message
|
|
1209
|
+
if (result.text) {
|
|
1210
|
+
result.text += content;
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
result.text = content;
|
|
1214
|
+
}
|
|
1215
|
+
result.textheaders = {
|
|
1216
|
+
'Content-Type': contentType,
|
|
1217
|
+
'Content-Transfer-Encoding': encoding || '',
|
|
1218
|
+
};
|
|
1219
|
+
// self boundary Not used at conversion
|
|
1220
|
+
}
|
|
1221
|
+
else {
|
|
1222
|
+
//Get the attachment
|
|
1223
|
+
if (!result.attachments) {
|
|
1224
|
+
result.attachments = [];
|
|
1225
|
+
}
|
|
1226
|
+
var attachment = {};
|
|
1227
|
+
var id = headers['Content-ID'] || headers['Content-Id'];
|
|
1228
|
+
if (id) {
|
|
1229
|
+
attachment.id = id;
|
|
1230
|
+
}
|
|
1231
|
+
var qaaapId = headers['X-Qaap-Object-Id'];
|
|
1232
|
+
if (qaaapId) {
|
|
1233
|
+
attachment.qaapId = qaaapId;
|
|
1234
|
+
}
|
|
1235
|
+
var NameContainer = ['Content-Disposition', 'Content-Type', 'Content-type'];
|
|
1236
|
+
var result_name = void 0;
|
|
1237
|
+
for (var _i = 0, NameContainer_1 = NameContainer; _i < NameContainer_1.length; _i++) {
|
|
1238
|
+
var key = NameContainer_1[_i];
|
|
1239
|
+
var name = headers[key];
|
|
1240
|
+
if (name) {
|
|
1241
|
+
result_name = name
|
|
1242
|
+
.replace(/(\s|'|utf-8|\*[0-9]\*)/g, '')
|
|
1243
|
+
.split(';')
|
|
1244
|
+
.map(function (v) { return /name[\*]?="?(.+?)"?$/gi.exec(v); })
|
|
1245
|
+
.reduce(function (a, b) {
|
|
1246
|
+
if (b && b[1]) {
|
|
1247
|
+
a += b[1];
|
|
1248
|
+
}
|
|
1249
|
+
return a;
|
|
1250
|
+
}, '');
|
|
1251
|
+
if (result_name) {
|
|
1252
|
+
break;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (result_name) {
|
|
1257
|
+
attachment.name = decodeURI(result_name);
|
|
1258
|
+
}
|
|
1259
|
+
var ct = headers['Content-Type'] || headers['Content-type'];
|
|
1260
|
+
if (ct) {
|
|
1261
|
+
attachment.contentType = ct;
|
|
1262
|
+
}
|
|
1263
|
+
var cd = headers['Content-Disposition'];
|
|
1264
|
+
if (cd) {
|
|
1265
|
+
attachment.inline = /^\s*inline/g.test(cd);
|
|
1266
|
+
}
|
|
1267
|
+
attachment.data = content;
|
|
1268
|
+
attachment.data64 = decode(content, charset);
|
|
1269
|
+
result.attachments.push(attachment);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
function _read(data) {
|
|
1273
|
+
if (!data) {
|
|
1274
|
+
return 'no data';
|
|
1275
|
+
}
|
|
1276
|
+
try {
|
|
1277
|
+
var result_1 = {};
|
|
1278
|
+
if (!data.headers) {
|
|
1279
|
+
throw new Error("data does't has headers");
|
|
1280
|
+
}
|
|
1281
|
+
if (data.headers['Date']) {
|
|
1282
|
+
result_1.date = new Date(data.headers['Date']);
|
|
1283
|
+
}
|
|
1284
|
+
if (data.headers['Subject']) {
|
|
1285
|
+
result_1.subject = unquoteString(data.headers['Subject']);
|
|
1286
|
+
}
|
|
1287
|
+
if (data.headers['From']) {
|
|
1288
|
+
result_1.from = getEmailAddress(data.headers['From']);
|
|
1289
|
+
}
|
|
1290
|
+
if (data.headers['To']) {
|
|
1291
|
+
result_1.to = getEmailAddress(data.headers['To']);
|
|
1292
|
+
}
|
|
1293
|
+
if (data.headers['CC']) {
|
|
1294
|
+
result_1.cc = getEmailAddress(data.headers['CC']);
|
|
1295
|
+
}
|
|
1296
|
+
if (data.headers['Cc']) {
|
|
1297
|
+
result_1.cc = getEmailAddress(data.headers['Cc']);
|
|
1298
|
+
}
|
|
1299
|
+
result_1.headers = data.headers;
|
|
1300
|
+
//Content mime type
|
|
1301
|
+
var boundary = null;
|
|
1302
|
+
var ct = data.headers['Content-Type'] || data.headers['Content-type'];
|
|
1303
|
+
if (ct && /^multipart\//g.test(ct)) {
|
|
1304
|
+
var b = getBoundary(ct);
|
|
1305
|
+
if (b && b.length) {
|
|
1306
|
+
boundary = b;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
if (boundary && Array.isArray(data.body)) {
|
|
1310
|
+
for (var i = 0; i < data.body.length; i++) {
|
|
1311
|
+
var boundaryBlock = data.body[i];
|
|
1312
|
+
if (!boundaryBlock) {
|
|
1313
|
+
continue;
|
|
1314
|
+
}
|
|
1315
|
+
//Get the message content
|
|
1316
|
+
if (typeof boundaryBlock.part === 'undefined') {
|
|
1317
|
+
verbose && console.warn('Warning: undefined b.part');
|
|
1318
|
+
}
|
|
1319
|
+
else if (typeof boundaryBlock.part === 'string') {
|
|
1320
|
+
result_1.data = boundaryBlock.part;
|
|
1321
|
+
}
|
|
1322
|
+
else {
|
|
1323
|
+
if (typeof boundaryBlock.part.body === 'undefined') {
|
|
1324
|
+
verbose && console.warn('Warning: undefined b.part.body');
|
|
1325
|
+
}
|
|
1326
|
+
else if (typeof boundaryBlock.part.body === 'string') {
|
|
1327
|
+
_append(boundaryBlock.part.headers, boundaryBlock.part.body, result_1);
|
|
1328
|
+
}
|
|
1329
|
+
else {
|
|
1330
|
+
// keep multipart/alternative
|
|
1331
|
+
var currentHeaders = boundaryBlock.part.headers;
|
|
1332
|
+
var currentHeadersContentType = currentHeaders['Content-Type'] || currentHeaders['Content-type'];
|
|
1333
|
+
if (verbose) {
|
|
1334
|
+
console.log("line 969 currentHeadersContentType: " + currentHeadersContentType);
|
|
1335
|
+
}
|
|
1336
|
+
// Hasmore ?
|
|
1337
|
+
if (currentHeadersContentType && currentHeadersContentType.indexOf('multipart') >= 0 && !result_1.multipartAlternative) {
|
|
1338
|
+
result_1.multipartAlternative = {
|
|
1339
|
+
'Content-Type': currentHeadersContentType,
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
for (var j = 0; j < boundaryBlock.part.body.length; j++) {
|
|
1343
|
+
var selfBoundary = boundaryBlock.part.body[j];
|
|
1344
|
+
if (typeof selfBoundary === 'string') {
|
|
1345
|
+
result_1.data = selfBoundary;
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1348
|
+
var headers = selfBoundary.part.headers;
|
|
1349
|
+
var content = selfBoundary.part.body;
|
|
1350
|
+
if (Array.isArray(content)) {
|
|
1351
|
+
content.forEach(function (bound) {
|
|
1352
|
+
_append(bound.part.headers, bound.part.body, result_1);
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
else {
|
|
1356
|
+
_append(headers, content, result_1);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
else if (typeof data.body === 'string') {
|
|
1364
|
+
_append(data.headers, data.body, result_1);
|
|
1365
|
+
}
|
|
1366
|
+
return result_1;
|
|
1367
|
+
}
|
|
1368
|
+
catch (e) {
|
|
1369
|
+
return e;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
if (typeof eml === 'string') {
|
|
1373
|
+
var parseResult = parse(eml, options);
|
|
1374
|
+
if (typeof parseResult === 'string' || parseResult instanceof Error) {
|
|
1375
|
+
error = parseResult;
|
|
1376
|
+
}
|
|
1377
|
+
else {
|
|
1378
|
+
var readResult = _read(parseResult);
|
|
1379
|
+
if (typeof readResult === 'string' || readResult instanceof Error) {
|
|
1380
|
+
error = readResult;
|
|
1381
|
+
}
|
|
1382
|
+
else {
|
|
1383
|
+
result = readResult;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
else if (typeof eml === 'object') {
|
|
1388
|
+
var readResult = _read(eml);
|
|
1389
|
+
if (typeof readResult === 'string' || readResult instanceof Error) {
|
|
1390
|
+
error = readResult;
|
|
1391
|
+
}
|
|
1392
|
+
else {
|
|
1393
|
+
result = readResult;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
else {
|
|
1397
|
+
error = new Error('Missing EML file content!');
|
|
1398
|
+
}
|
|
1399
|
+
callback && callback(error, result);
|
|
1400
|
+
return error || result || new Error('read EML failed!');
|
|
1401
|
+
}
|
|
1402
|
+
// const GBKUTF8 = GB2312UTF8;
|
|
1403
|
+
// const parseEml = parse;
|
|
1404
|
+
// const readEml = read;
|
|
1405
|
+
// const buildEml = build;
|
|
1406
|
+
|
|
1407
|
+
Object.defineProperty(exports, 'Base64', {
|
|
1408
|
+
enumerable: true,
|
|
1409
|
+
get: function () {
|
|
1410
|
+
return jsBase64.Base64;
|
|
1411
|
+
}
|
|
1412
|
+
});
|
|
1413
|
+
exports.GBKUTF8 = GB2312UTF8;
|
|
1414
|
+
exports.buildEml = build;
|
|
1415
|
+
exports.completeBoundary = completeBoundary;
|
|
1416
|
+
exports.convert = convert;
|
|
1417
|
+
exports.createBoundary = createBoundary;
|
|
1418
|
+
exports.decode = decode;
|
|
1419
|
+
exports.encode = encode;
|
|
1420
|
+
exports.getBoundary = getBoundary;
|
|
1421
|
+
exports.getCharset = getCharset;
|
|
1422
|
+
exports.getEmailAddress = getEmailAddress;
|
|
1423
|
+
exports.mimeDecode = mimeDecode;
|
|
1424
|
+
exports.parseEml = parse;
|
|
1425
|
+
exports.readEml = read;
|
|
1426
|
+
exports.toEmailAddress = toEmailAddress;
|
|
1427
|
+
exports.unquotePrintable = unquotePrintable;
|
|
1428
|
+
exports.unquoteString = unquoteString;
|