imapflow 1.0.96 → 1.0.99
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/CHANGELOG.md +12 -0
- package/lib/commands/list.js +7 -1
- package/lib/commands/status.js +10 -0
- package/lib/handler/imap-formal-syntax.js +1 -1
- package/lib/handler/parser-instance.js +7 -7
- package/lib/handler/token-parser.js +26 -26
- package/lib/imap-flow.js +12 -0
- package/lib/tools.js +20 -7
- package/package.json +6 -6
- package/test/imap-parser-test.js +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
- 1.0.99 - 2022-06-05
|
|
4
|
+
|
|
5
|
+
- Check if folder exists on failed status command
|
|
6
|
+
|
|
7
|
+
- 1.0.98 - 2022-05-30
|
|
8
|
+
|
|
9
|
+
- Fixed an issue with envelope parsing where literal values were returned as Buffers
|
|
10
|
+
|
|
11
|
+
- 1.0.97 - 2022-05-29
|
|
12
|
+
|
|
13
|
+
- Allow single quotes in atoms
|
|
14
|
+
|
|
3
15
|
- 1.0.96 - 2022-05-18
|
|
4
16
|
|
|
5
17
|
- Allow non-standard characters in ATOM if it's the string after NO/OK/BAD response
|
package/lib/commands/list.js
CHANGED
|
@@ -4,7 +4,9 @@ const { decodePath, encodePath, normalizePath } = require('../tools.js');
|
|
|
4
4
|
const { specialUse } = require('../special-use');
|
|
5
5
|
|
|
6
6
|
// Lists mailboxes from server
|
|
7
|
-
module.exports = async (connection, reference, mailbox) => {
|
|
7
|
+
module.exports = async (connection, reference, mailbox, options) => {
|
|
8
|
+
options = options || {};
|
|
9
|
+
|
|
8
10
|
let listCommand = connection.capabilities.has('XLIST') && !connection.capabilities.has('SPECIAL-USE') ? 'XLIST' : 'LIST';
|
|
9
11
|
|
|
10
12
|
let response;
|
|
@@ -64,6 +66,10 @@ module.exports = async (connection, reference, mailbox) => {
|
|
|
64
66
|
let normalizedReference = normalizePath(connection, reference || '');
|
|
65
67
|
await runList(normalizedReference, normalizePath(connection, mailbox || '', true));
|
|
66
68
|
|
|
69
|
+
if (options.listOnly) {
|
|
70
|
+
return entries;
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
if (normalizedReference && !entries.find(entry => entry.specialUse === '\\Inbox')) {
|
|
68
74
|
// INBOX was most probably not included in the listing if namespace was used
|
|
69
75
|
await runList('', 'INBOX');
|
package/lib/commands/status.js
CHANGED
|
@@ -126,6 +126,16 @@ module.exports = async (connection, path, query) => {
|
|
|
126
126
|
response.next();
|
|
127
127
|
return map;
|
|
128
128
|
} catch (err) {
|
|
129
|
+
if (err.responseStatus === 'NO') {
|
|
130
|
+
let folders = await connection.run('LIST', '', path, { listOnly: true });
|
|
131
|
+
if (folders && !folders.length) {
|
|
132
|
+
let error = new Error(`Mailbox doesn't exist: ${path}`);
|
|
133
|
+
error.code = 'NotFound';
|
|
134
|
+
error.response = err;
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
129
139
|
connection.log.warn({ err, cid: connection.id });
|
|
130
140
|
return false;
|
|
131
141
|
}
|
|
@@ -60,16 +60,16 @@ class ParserInstance {
|
|
|
60
60
|
let match, element, errPos;
|
|
61
61
|
|
|
62
62
|
if (this.remainder.match(/^\s/)) {
|
|
63
|
-
throw new Error(
|
|
63
|
+
throw new Error(`Unexpected whitespace at position ${this.pos} [E1]`);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
if ((match = this.remainder.match(/^\s*[^\s]+(?=\s|$)/))) {
|
|
67
67
|
element = match[0];
|
|
68
68
|
if ((errPos = imapFormalSyntax.verify(element, syntax)) >= 0) {
|
|
69
|
-
throw new Error(
|
|
69
|
+
throw new Error(`Unexpected char at position ${this.pos + errPos} [E2: ${JSON.stringify(element.charAt(errPos))}]`);
|
|
70
70
|
}
|
|
71
71
|
} else {
|
|
72
|
-
throw new Error(
|
|
72
|
+
throw new Error(`Unexpected end of input at position ${this.pos} [E3]`);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
this.pos += match[0].length;
|
|
@@ -80,11 +80,11 @@ class ParserInstance {
|
|
|
80
80
|
|
|
81
81
|
async getSpace() {
|
|
82
82
|
if (!this.remainder.length) {
|
|
83
|
-
throw new Error(
|
|
83
|
+
throw new Error(`Unexpected end of input at position ${this.pos} [E4]`);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
if (imapFormalSyntax.verify(this.remainder.charAt(0), imapFormalSyntax.SP()) >= 0) {
|
|
87
|
-
throw new Error(
|
|
87
|
+
throw new Error(`Unexpected char at position ${this.pos} [E5: ${JSON.stringify(this.remainder.charAt(0))}]`);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
this.pos++;
|
|
@@ -93,11 +93,11 @@ class ParserInstance {
|
|
|
93
93
|
|
|
94
94
|
async getAttributes() {
|
|
95
95
|
if (!this.remainder.length) {
|
|
96
|
-
throw new Error(
|
|
96
|
+
throw new Error(`Unexpected end of input at position ${this.pos} [E6]`);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
if (this.remainder.match(/^\s/)) {
|
|
100
|
-
throw new Error(
|
|
100
|
+
throw new Error(`Unexpected whitespace at position ${this.pos} [E7]`);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
const tokenParser = new TokenParser(this, this.pos, this.remainder, this.options);
|
|
@@ -36,7 +36,7 @@ class TokenParser {
|
|
|
36
36
|
|
|
37
37
|
// If the node was never closed, throw it
|
|
38
38
|
if (!node.isClosed) {
|
|
39
|
-
throw new Error(
|
|
39
|
+
throw new Error(`Unexpected end of input at position ${this.pos + this.str.length - 1} [E6]`);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
let type = (node.type || '').toString().toUpperCase();
|
|
@@ -149,7 +149,7 @@ class TokenParser {
|
|
|
149
149
|
// ) closes a list
|
|
150
150
|
case ')':
|
|
151
151
|
if (this.currentNode.type !== 'LIST') {
|
|
152
|
-
throw new Error(
|
|
152
|
+
throw new Error(`Unexpected list terminator ) at position ${this.pos + i} [E7]`);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
this.currentNode.isClosed = true;
|
|
@@ -162,7 +162,7 @@ class TokenParser {
|
|
|
162
162
|
// ] closes section group
|
|
163
163
|
case ']':
|
|
164
164
|
if (this.currentNode.type !== 'SECTION') {
|
|
165
|
-
throw new Error(
|
|
165
|
+
throw new Error(`Unexpected section terminator ] at position ${this.pos + i} [E8]`);
|
|
166
166
|
}
|
|
167
167
|
this.currentNode.isClosed = true;
|
|
168
168
|
this.currentNode.endPos = this.pos + i;
|
|
@@ -189,7 +189,7 @@ class TokenParser {
|
|
|
189
189
|
case '~': {
|
|
190
190
|
let nextChr = this.str.charAt(i + 1);
|
|
191
191
|
if (nextChr !== '{') {
|
|
192
|
-
throw new Error(
|
|
192
|
+
throw new Error(`Unexpected literal8 marker at position ${this.pos + i} [E9]`);
|
|
193
193
|
}
|
|
194
194
|
this.expectedLiteralType = 'literal8';
|
|
195
195
|
break;
|
|
@@ -270,7 +270,7 @@ class TokenParser {
|
|
|
270
270
|
// Allow \ as the first char for atom to support system flags
|
|
271
271
|
// Allow % to support LIST '' %
|
|
272
272
|
if (imapFormalSyntax['ATOM-CHAR']().indexOf(chr) < 0 && chr !== '\\' && chr !== '%') {
|
|
273
|
-
throw new Error(
|
|
273
|
+
throw new Error(`Unexpected char at position ${this.pos + i} [E10: ${JSON.stringify(chr)}]`);
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
this.currentNode = this.createNode(this.currentNode, this.pos + i);
|
|
@@ -317,7 +317,7 @@ class TokenParser {
|
|
|
317
317
|
if (chr === '[') {
|
|
318
318
|
// allowed only for selected elements
|
|
319
319
|
if (['BODY', 'BODY.PEEK', 'BINARY', 'BINARY.PEEK'].indexOf(this.currentNode.value.toUpperCase()) < 0) {
|
|
320
|
-
throw new Error(
|
|
320
|
+
throw new Error(`Unexpected section start char [ at position ${this.pos} [E11]`);
|
|
321
321
|
}
|
|
322
322
|
this.currentNode.endPos = this.pos + i;
|
|
323
323
|
this.currentNode = this.createNode(this.currentNode.parentNode, this.pos + i);
|
|
@@ -328,7 +328,7 @@ class TokenParser {
|
|
|
328
328
|
}
|
|
329
329
|
|
|
330
330
|
if (chr === '<') {
|
|
331
|
-
throw new Error(
|
|
331
|
+
throw new Error(`Unexpected start of partial at position ${this.pos} [E12]`);
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
// if the char is not ATOM compatible, throw. Allow \* as an exception
|
|
@@ -338,9 +338,9 @@ class TokenParser {
|
|
|
338
338
|
!(chr === '*' && this.currentNode.value === '\\') &&
|
|
339
339
|
(!this.parent || !this.parent.command || !['NO', 'BAD', 'OK'].includes(this.parent.command))
|
|
340
340
|
) {
|
|
341
|
-
throw new Error(
|
|
341
|
+
throw new Error(`Unexpected char at position ${this.pos + i} [E13: ${JSON.stringify(chr)}]`);
|
|
342
342
|
} else if (this.currentNode.value === '\\*') {
|
|
343
|
-
throw new Error(
|
|
343
|
+
throw new Error(`Unexpected char at position ${this.pos + i} [E14: ${JSON.stringify(chr)}]`);
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
this.currentNode.value += chr;
|
|
@@ -362,7 +362,7 @@ class TokenParser {
|
|
|
362
362
|
if (chr === '\\') {
|
|
363
363
|
i++;
|
|
364
364
|
if (i >= len) {
|
|
365
|
-
throw new Error(
|
|
365
|
+
throw new Error(`Unexpected end of input at position ${this.pos + i} [E15]`);
|
|
366
366
|
}
|
|
367
367
|
chr = this.str.charAt(i);
|
|
368
368
|
}
|
|
@@ -373,7 +373,7 @@ class TokenParser {
|
|
|
373
373
|
case 'PARTIAL':
|
|
374
374
|
if (chr === '>') {
|
|
375
375
|
if (this.currentNode.value.substr(-1) === '.') {
|
|
376
|
-
throw new Error(
|
|
376
|
+
throw new Error(`Unexpected end of partial at position ${this.pos} [E16]`);
|
|
377
377
|
}
|
|
378
378
|
this.currentNode.endPos = this.pos + i;
|
|
379
379
|
this.currentNode.isClosed = true;
|
|
@@ -384,15 +384,15 @@ class TokenParser {
|
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
if (chr === '.' && (!this.currentNode.value.length || this.currentNode.value.match(/\./))) {
|
|
387
|
-
throw new Error(
|
|
387
|
+
throw new Error(`Unexpected partial separator . at position ${this.pos} [E17]`);
|
|
388
388
|
}
|
|
389
389
|
|
|
390
390
|
if (imapFormalSyntax.DIGIT().indexOf(chr) < 0 && chr !== '.') {
|
|
391
|
-
throw new Error(
|
|
391
|
+
throw new Error(`Unexpected char at position ${this.pos + i} [E18: ${JSON.stringify(chr)}]`);
|
|
392
392
|
}
|
|
393
393
|
|
|
394
394
|
if (this.currentNode.value.match(/^0$|\.0$/) && chr !== '.') {
|
|
395
|
-
throw new Error(
|
|
395
|
+
throw new Error(`Invalid partial at position ${this.pos + i} [E19: ${JSON.stringify(chr)}]`);
|
|
396
396
|
}
|
|
397
397
|
|
|
398
398
|
this.currentNode.value += chr;
|
|
@@ -431,14 +431,14 @@ class TokenParser {
|
|
|
431
431
|
|
|
432
432
|
if (chr === '}') {
|
|
433
433
|
if (!('literalLength' in this.currentNode)) {
|
|
434
|
-
throw new Error(
|
|
434
|
+
throw new Error(`Unexpected literal prefix end char } at position ${this.pos + i} [E20]`);
|
|
435
435
|
}
|
|
436
436
|
if (this.str.charAt(i + 1) === '\n') {
|
|
437
437
|
i++;
|
|
438
438
|
} else if (this.str.charAt(i + 1) === '\r' && this.str.charAt(i + 2) === '\n') {
|
|
439
439
|
i += 2;
|
|
440
440
|
} else {
|
|
441
|
-
throw new Error(
|
|
441
|
+
throw new Error(`Unexpected char at position ${this.pos + i} [E21: ${JSON.stringify(chr)}]`);
|
|
442
442
|
}
|
|
443
443
|
|
|
444
444
|
this.currentNode.literalLength = Number(this.currentNode.literalLength);
|
|
@@ -479,10 +479,10 @@ class TokenParser {
|
|
|
479
479
|
break;
|
|
480
480
|
}
|
|
481
481
|
if (imapFormalSyntax.DIGIT().indexOf(chr) < 0) {
|
|
482
|
-
throw new Error(
|
|
482
|
+
throw new Error(`Unexpected char at position ${this.pos + i} [E22: ${JSON.stringify(chr)}]`);
|
|
483
483
|
}
|
|
484
484
|
if (this.currentNode.literalLength === '0') {
|
|
485
|
-
throw new Error(
|
|
485
|
+
throw new Error(`Invalid literal at position ${this.pos + i} [E23]`);
|
|
486
486
|
}
|
|
487
487
|
this.currentNode.literalLength = (this.currentNode.literalLength || '') + chr;
|
|
488
488
|
break;
|
|
@@ -491,11 +491,11 @@ class TokenParser {
|
|
|
491
491
|
// space finishes the sequence set
|
|
492
492
|
if (chr === ' ') {
|
|
493
493
|
if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== '*') {
|
|
494
|
-
throw new Error(
|
|
494
|
+
throw new Error(`Unexpected whitespace at position ${this.pos + i} [E24]`);
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
if (this.currentNode.value !== '*' && this.currentNode.value.substr(-1) === '*' && this.currentNode.value.substr(-2, 1) !== ':') {
|
|
498
|
-
throw new Error(
|
|
498
|
+
throw new Error(`Unexpected whitespace at position ${this.pos + i} [E25]`);
|
|
499
499
|
}
|
|
500
500
|
|
|
501
501
|
this.currentNode.isClosed = true;
|
|
@@ -518,25 +518,25 @@ class TokenParser {
|
|
|
518
518
|
|
|
519
519
|
if (chr === ':') {
|
|
520
520
|
if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== '*') {
|
|
521
|
-
throw new Error(
|
|
521
|
+
throw new Error(`Unexpected range separator : at position ${this.pos + i} [E26]`);
|
|
522
522
|
}
|
|
523
523
|
} else if (chr === '*') {
|
|
524
524
|
if ([',', ':'].indexOf(this.currentNode.value.substr(-1)) < 0) {
|
|
525
|
-
throw new Error(
|
|
525
|
+
throw new Error(`Unexpected range wildcard at position ${this.pos + i} [E27]`);
|
|
526
526
|
}
|
|
527
527
|
} else if (chr === ',') {
|
|
528
528
|
if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== '*') {
|
|
529
|
-
throw new Error(
|
|
529
|
+
throw new Error(`Unexpected sequence separator , at position ${this.pos + i} [E28]`);
|
|
530
530
|
}
|
|
531
531
|
if (this.currentNode.value.substr(-1) === '*' && this.currentNode.value.substr(-2, 1) !== ':') {
|
|
532
|
-
throw new Error(
|
|
532
|
+
throw new Error(`Unexpected sequence separator , at position ${this.pos + i} [E29]`);
|
|
533
533
|
}
|
|
534
534
|
} else if (!chr.match(/\d/)) {
|
|
535
|
-
throw new Error(
|
|
535
|
+
throw new Error(`Unexpected char at position ${this.pos + i} [E30: ${JSON.stringify(chr)}]`);
|
|
536
536
|
}
|
|
537
537
|
|
|
538
538
|
if (chr.match(/\d/) && this.currentNode.value.substr(-1) === '*') {
|
|
539
|
-
throw new Error(
|
|
539
|
+
throw new Error(`Unexpected number at position ${this.pos + i} [E31: ${JSON.stringify(chr)}]`);
|
|
540
540
|
}
|
|
541
541
|
|
|
542
542
|
this.currentNode.value += chr;
|
package/lib/imap-flow.js
CHANGED
|
@@ -2501,6 +2501,17 @@ class ImapFlow extends EventEmitter {
|
|
|
2501
2501
|
this.currentLockId = lockId;
|
|
2502
2502
|
return resolve({ path, release });
|
|
2503
2503
|
} catch (err) {
|
|
2504
|
+
if (err.responseStatus === 'NO') {
|
|
2505
|
+
try {
|
|
2506
|
+
let folders = await this.run('LIST', '', path, { listOnly: true });
|
|
2507
|
+
if (!folders || !folders.length) {
|
|
2508
|
+
err.mailboxMissing = true;
|
|
2509
|
+
}
|
|
2510
|
+
} catch (E) {
|
|
2511
|
+
this.log.trace({ msg: 'Failed to verify failed mailbox', path, err: E });
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2504
2515
|
this.log.trace({ msg: 'Failed to acquire mailbox lock', path, lockId });
|
|
2505
2516
|
reject(err);
|
|
2506
2517
|
await this.processLocks(true);
|
|
@@ -2531,6 +2542,7 @@ class ImapFlow extends EventEmitter {
|
|
|
2531
2542
|
*/
|
|
2532
2543
|
async getMailboxLock(path, options) {
|
|
2533
2544
|
options = options || {};
|
|
2545
|
+
|
|
2534
2546
|
path = normalizePath(this, path);
|
|
2535
2547
|
|
|
2536
2548
|
let lockId = ++this.lockCounter;
|
package/lib/tools.js
CHANGED
|
@@ -350,25 +350,38 @@ module.exports = {
|
|
|
350
350
|
},
|
|
351
351
|
|
|
352
352
|
parseEnvelope(entry) {
|
|
353
|
+
let getStrValue = obj => {
|
|
354
|
+
if (!obj) {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
if (typeof obj.value === 'string') {
|
|
358
|
+
return obj.value;
|
|
359
|
+
}
|
|
360
|
+
if (Buffer.isBuffer(obj.value)) {
|
|
361
|
+
return obj.value.toString();
|
|
362
|
+
}
|
|
363
|
+
return obj.value;
|
|
364
|
+
};
|
|
365
|
+
|
|
353
366
|
let processAddresses = function (list) {
|
|
354
367
|
return [].concat(list || []).map(addr => ({
|
|
355
|
-
name: libmime.decodeWords((addr[0]
|
|
356
|
-
address: ((addr[2]
|
|
368
|
+
name: libmime.decodeWords(getStrValue(addr[0]) || ''),
|
|
369
|
+
address: (getStrValue(addr[2]) || '') + '@' + (getStrValue(addr[3]) || '')
|
|
357
370
|
}));
|
|
358
371
|
},
|
|
359
372
|
envelope = {};
|
|
360
373
|
|
|
361
374
|
if (entry[0] && entry[0].value) {
|
|
362
|
-
let date = new Date(entry[0]
|
|
375
|
+
let date = new Date(getStrValue(entry[0]));
|
|
363
376
|
if (date.toString() === 'Invalid Date') {
|
|
364
|
-
envelope.date = entry[0]
|
|
377
|
+
envelope.date = getStrValue(entry[0]);
|
|
365
378
|
} else {
|
|
366
379
|
envelope.date = date;
|
|
367
380
|
}
|
|
368
381
|
}
|
|
369
382
|
|
|
370
383
|
if (entry[1] && entry[1].value) {
|
|
371
|
-
envelope.subject = libmime.decodeWords(entry[1]
|
|
384
|
+
envelope.subject = libmime.decodeWords(getStrValue(entry[1]));
|
|
372
385
|
}
|
|
373
386
|
|
|
374
387
|
if (entry[2] && entry[2].length) {
|
|
@@ -396,11 +409,11 @@ module.exports = {
|
|
|
396
409
|
}
|
|
397
410
|
|
|
398
411
|
if (entry[8] && entry[8].value) {
|
|
399
|
-
envelope.inReplyTo = entry[8].
|
|
412
|
+
envelope.inReplyTo = (getStrValue(entry[8]) || '').toString().trim();
|
|
400
413
|
}
|
|
401
414
|
|
|
402
415
|
if (entry[9] && entry[9].value) {
|
|
403
|
-
envelope.messageId = entry[9].
|
|
416
|
+
envelope.messageId = (getStrValue(entry[9]) || '').toString().trim();
|
|
404
417
|
}
|
|
405
418
|
|
|
406
419
|
return envelope;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imapflow",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.99",
|
|
4
4
|
"description": "IMAP Client for Node",
|
|
5
5
|
"main": "./lib/imap-flow.js",
|
|
6
6
|
"scripts": {
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://imapflow.com/",
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@babel/eslint-parser": "7.
|
|
30
|
+
"@babel/eslint-parser": "7.18.2",
|
|
31
31
|
"@babel/eslint-plugin": "7.17.7",
|
|
32
32
|
"@babel/plugin-syntax-class-properties": "7.12.13",
|
|
33
|
-
"@babel/preset-env": "7.
|
|
34
|
-
"@types/node": "17.0.
|
|
33
|
+
"@babel/preset-env": "7.18.2",
|
|
34
|
+
"@types/node": "17.0.40",
|
|
35
35
|
"braintree-jsdoc-template": "3.3.0",
|
|
36
|
-
"eslint": "8.
|
|
36
|
+
"eslint": "8.17.0",
|
|
37
37
|
"eslint-config-nodemailer": "1.2.0",
|
|
38
38
|
"eslint-config-prettier": "8.5.0",
|
|
39
39
|
"grunt": "1.5.3",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"libqp": "1.1.0",
|
|
53
53
|
"mailsplit": "5.3.2",
|
|
54
54
|
"nodemailer": "6.7.5",
|
|
55
|
-
"pino": "
|
|
55
|
+
"pino": "8.0.0",
|
|
56
56
|
"socks": "2.6.2"
|
|
57
57
|
}
|
|
58
58
|
}
|
package/test/imap-parser-test.js
CHANGED
|
@@ -921,3 +921,15 @@ module.exports['IMAP Parser, unicode select'] = test =>
|
|
|
921
921
|
{ type: 'ATOM', value: '[THROTTLED]' }
|
|
922
922
|
])
|
|
923
923
|
);
|
|
924
|
+
|
|
925
|
+
module.exports['IMAP Parser, single quote in atom'] = test =>
|
|
926
|
+
asyncWrapper(test, async test =>
|
|
927
|
+
test.deepEqual((await parser('* LIST (HasNoChildren UnMarked) "/" \'a')).attributes, [
|
|
928
|
+
[
|
|
929
|
+
{ type: 'ATOM', value: 'HasNoChildren' },
|
|
930
|
+
{ type: 'ATOM', value: 'UnMarked' }
|
|
931
|
+
],
|
|
932
|
+
{ type: 'STRING', value: '/' },
|
|
933
|
+
{ type: 'ATOM', value: "'a" }
|
|
934
|
+
])
|
|
935
|
+
);
|