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