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.
@@ -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|(&quot;)/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;