imapflow 1.0.89 → 1.0.92
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/.gitattributes +1 -0
- package/.github/workflows/test.yml +21 -0
- package/CHANGELOG.md +15 -0
- package/lib/commands/append.js +11 -1
- package/lib/commands/authenticate.js +1 -1
- package/lib/commands/create.js +2 -2
- package/lib/commands/delete.js +2 -2
- package/lib/commands/fetch.js +4 -2
- package/lib/commands/idle.js +120 -91
- package/lib/commands/list.js +44 -60
- package/lib/commands/quota.js +2 -2
- package/lib/commands/rename.js +3 -3
- package/lib/commands/select.js +93 -89
- package/lib/commands/status.js +2 -2
- package/lib/commands/subscribe.js +2 -2
- package/lib/commands/unsubscribe.js +2 -2
- package/lib/handler/imap-compiler.js +1 -1
- package/lib/handler/imap-formal-syntax.js +13 -13
- package/lib/handler/imap-stream.js +9 -1
- package/lib/handler/token-parser.js +41 -26
- package/lib/imap-flow.js +49 -12
- package/lib/tools.js +29 -11
- package/lib/types.d.ts +13 -3
- package/package.json +12 -10
- package/test/imap-compiler-test.js +41 -2
- package/test/imap-parser-test.js +30 -0
package/lib/imap-flow.js
CHANGED
|
@@ -129,6 +129,8 @@ class ImapFlow extends EventEmitter {
|
|
|
129
129
|
* @param {Boolean} [options.verifyOnly=false] If `true` then logs out automatically after successful authentication
|
|
130
130
|
* @param {Boolean} [options.proxy] Optional proxy URL. Supports HTTP CONNECT (`http://`, `https://`) and SOCKS (`socks://`, `socks4://`, `socks5://`) proxies
|
|
131
131
|
* @param {Boolean} [options.qresync=false] If true, then enables QRESYNC support. EXPUNGE notifications will include `uid` property instead of `seq`
|
|
132
|
+
* @param {Number} [options.maxIdleTime] If set, then breaks and restarts IDLE every maxIdleTime ms
|
|
133
|
+
* @param {Boolean} [options.disableBinary=false] If true, then ignores the BINARY extension when making FETCH and APPEND calls
|
|
132
134
|
*/
|
|
133
135
|
constructor(options) {
|
|
134
136
|
super({ captureRejections: true });
|
|
@@ -182,7 +184,8 @@ class ImapFlow extends EventEmitter {
|
|
|
182
184
|
this.streamer = new ImapStream({
|
|
183
185
|
logger: this.log,
|
|
184
186
|
cid: this.id,
|
|
185
|
-
logRaw: this.logRaw
|
|
187
|
+
logRaw: this.logRaw,
|
|
188
|
+
secureConnection: this.secureConnection
|
|
186
189
|
});
|
|
187
190
|
|
|
188
191
|
this.reading = false;
|
|
@@ -260,6 +263,10 @@ class ImapFlow extends EventEmitter {
|
|
|
260
263
|
this.currentLock = false;
|
|
261
264
|
this.locks = [];
|
|
262
265
|
|
|
266
|
+
this.maxIdleTime = this.options.maxIdleTime || false;
|
|
267
|
+
|
|
268
|
+
this.disableBinary = !!this.options.disableBinary;
|
|
269
|
+
|
|
263
270
|
this.streamer.on('error', err => {
|
|
264
271
|
if (['Z_BUF_ERROR', 'ECONNRESET', 'EPIPE', 'ETIMEDOUT', 'EHOSTUNREACH'].includes(err.code)) {
|
|
265
272
|
// just close the connection, usually nothing but noise
|
|
@@ -307,7 +314,14 @@ class ImapFlow extends EventEmitter {
|
|
|
307
314
|
}
|
|
308
315
|
|
|
309
316
|
if (this.logRaw) {
|
|
310
|
-
this.log.trace({
|
|
317
|
+
this.log.trace({
|
|
318
|
+
src: 'c',
|
|
319
|
+
msg: 'write to socket',
|
|
320
|
+
data: chunk.toString('base64'),
|
|
321
|
+
compress: !!this._deflate,
|
|
322
|
+
secure: !!this.secureConnection,
|
|
323
|
+
cid: this.id
|
|
324
|
+
});
|
|
311
325
|
}
|
|
312
326
|
|
|
313
327
|
this.writeSocket.write(chunk);
|
|
@@ -747,13 +761,14 @@ class ImapFlow extends EventEmitter {
|
|
|
747
761
|
this.upgrading = true;
|
|
748
762
|
this.socket = tls.connect(opts, () => {
|
|
749
763
|
clearTimeout(this.upgradeTimeout);
|
|
750
|
-
if (this.
|
|
764
|
+
if (this.isClosed) {
|
|
751
765
|
// not sure if this is possible?
|
|
752
766
|
return this.close();
|
|
753
767
|
}
|
|
754
768
|
|
|
755
769
|
this.secureConnection = true;
|
|
756
770
|
this.upgrading = false;
|
|
771
|
+
this.streamer.secureConnection = true;
|
|
757
772
|
this.socket.pipe(this.streamer);
|
|
758
773
|
this.tls = typeof this.socket.getCipher === 'function' ? this.socket.getCipher() : false;
|
|
759
774
|
if (this.tls) {
|
|
@@ -835,7 +850,7 @@ class ImapFlow extends EventEmitter {
|
|
|
835
850
|
this.untaggedHandlers.OK = null;
|
|
836
851
|
this.untaggedHandlers.PREAUTH = null;
|
|
837
852
|
|
|
838
|
-
if (this.
|
|
853
|
+
if (this.isClosed) {
|
|
839
854
|
return;
|
|
840
855
|
}
|
|
841
856
|
|
|
@@ -868,7 +883,7 @@ class ImapFlow extends EventEmitter {
|
|
|
868
883
|
this.untaggedHandlers.OK = null;
|
|
869
884
|
this.untaggedHandlers.PREAUTH = null;
|
|
870
885
|
|
|
871
|
-
if (this.
|
|
886
|
+
if (this.isClosed) {
|
|
872
887
|
return;
|
|
873
888
|
}
|
|
874
889
|
|
|
@@ -1060,6 +1075,15 @@ class ImapFlow extends EventEmitter {
|
|
|
1060
1075
|
range = range.toString();
|
|
1061
1076
|
}
|
|
1062
1077
|
|
|
1078
|
+
// special case, some servers allow this, some do not, so replace it with the last known EXISTS value
|
|
1079
|
+
if (range === '*') {
|
|
1080
|
+
if (!this.mailbox.exists) {
|
|
1081
|
+
return false;
|
|
1082
|
+
}
|
|
1083
|
+
range = this.mailbox.exists.toString();
|
|
1084
|
+
options.uid = false; // sequence query
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1063
1087
|
if (range && typeof range === 'object' && !Array.isArray(range)) {
|
|
1064
1088
|
if (range.all && Object.keys(range) === 1) {
|
|
1065
1089
|
range = '1:*';
|
|
@@ -1269,7 +1293,9 @@ class ImapFlow extends EventEmitter {
|
|
|
1269
1293
|
let reject = this.initialReject;
|
|
1270
1294
|
this.initialResolve = false;
|
|
1271
1295
|
this.initialReject = false;
|
|
1272
|
-
|
|
1296
|
+
let err = new Error('Unexpected close');
|
|
1297
|
+
err.code = `ClosedAfterConnect${this.secureConnection ? 'TLS' : 'Text'}`;
|
|
1298
|
+
reject(err);
|
|
1273
1299
|
}
|
|
1274
1300
|
|
|
1275
1301
|
if (typeof this.preCheck === 'function') {
|
|
@@ -1299,10 +1325,10 @@ class ImapFlow extends EventEmitter {
|
|
|
1299
1325
|
}
|
|
1300
1326
|
|
|
1301
1327
|
this.state = this.states.LOGOUT;
|
|
1302
|
-
if (this.
|
|
1328
|
+
if (this.isClosed) {
|
|
1303
1329
|
return;
|
|
1304
1330
|
}
|
|
1305
|
-
this.
|
|
1331
|
+
this.isClosed = true;
|
|
1306
1332
|
|
|
1307
1333
|
if (this.writeSocket && !this.writeSocket.destroyed) {
|
|
1308
1334
|
try {
|
|
@@ -1354,9 +1380,12 @@ class ImapFlow extends EventEmitter {
|
|
|
1354
1380
|
/**
|
|
1355
1381
|
* @typedef {Object} ListResponse
|
|
1356
1382
|
* @global
|
|
1357
|
-
* @property {String} path mailbox path
|
|
1383
|
+
* @property {String} path mailbox path (unicode string)
|
|
1384
|
+
* @property {String} pathAsListed mailbox path as listed in the LIST/LSUB response
|
|
1358
1385
|
* @property {String} name mailbox name (last part of path after delimiter)
|
|
1359
1386
|
* @property {String} delimiter mailbox path delimiter, usually "." or "/"
|
|
1387
|
+
* @property {Array<string>} parent An array of parent folder names. All names are in unicode
|
|
1388
|
+
* @property {String} parentPath Same as `parent`, but as a complete string path (unicode string)
|
|
1360
1389
|
* @property {Set<string>} flags a set of flags for this mailbox
|
|
1361
1390
|
* @property {String} specialUse one of special-use flags (if applicable): "\All", "\Archive", "\Drafts", "\Flagged", "\Junk", "\Sent", "\Trash". Additionally INBOX has non-standard "\Inbox" flag set
|
|
1362
1391
|
* @property {Boolean} listed `true` if mailbox was found from the output of LIST command
|
|
@@ -1560,7 +1589,7 @@ class ImapFlow extends EventEmitter {
|
|
|
1560
1589
|
/**
|
|
1561
1590
|
* Requests the status of the indicated mailbox. Only requested status values will be returned.
|
|
1562
1591
|
*
|
|
1563
|
-
* @param {String} path mailbox path to check for
|
|
1592
|
+
* @param {String} path mailbox path to check for (unicode string)
|
|
1564
1593
|
* @param {Object} query defines requested status items
|
|
1565
1594
|
* @param {Boolean} query.messages if `true` request count of messages
|
|
1566
1595
|
* @param {Boolean} query.recent if `true` request count of messages with \\Recent tag
|
|
@@ -1593,7 +1622,7 @@ class ImapFlow extends EventEmitter {
|
|
|
1593
1622
|
*/
|
|
1594
1623
|
async idle() {
|
|
1595
1624
|
if (!this.idling) {
|
|
1596
|
-
return await this.run('IDLE');
|
|
1625
|
+
return await this.run('IDLE', this.maxIdleTime);
|
|
1597
1626
|
}
|
|
1598
1627
|
}
|
|
1599
1628
|
|
|
@@ -1783,7 +1812,7 @@ class ImapFlow extends EventEmitter {
|
|
|
1783
1812
|
/**
|
|
1784
1813
|
* Appends a new message to a mailbox
|
|
1785
1814
|
*
|
|
1786
|
-
* @param {String} path Mailbox path to upload the message to
|
|
1815
|
+
* @param {String} path Mailbox path to upload the message to (unicode string)
|
|
1787
1816
|
* @param {string|Buffer} content RFC822 formatted email message
|
|
1788
1817
|
* @param {string[]} [flags] an array of flags to be set for the uploaded message
|
|
1789
1818
|
* @param {Date|string} [idate=now] internal date to be set for the message
|
|
@@ -2093,6 +2122,14 @@ class ImapFlow extends EventEmitter {
|
|
|
2093
2122
|
return;
|
|
2094
2123
|
}
|
|
2095
2124
|
|
|
2125
|
+
if (seq === '*') {
|
|
2126
|
+
if (!this.mailbox.exists) {
|
|
2127
|
+
return false;
|
|
2128
|
+
}
|
|
2129
|
+
seq = this.mailbox.exists.toString();
|
|
2130
|
+
options = Object.assign({}, options || {}, { uid: false }); // force into a sequence query
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2096
2133
|
let response = await this.run('FETCH', (seq || '').toString(), query, options);
|
|
2097
2134
|
|
|
2098
2135
|
if (!response || !response.list || !response.list.length) {
|
package/lib/tools.js
CHANGED
|
@@ -9,6 +9,30 @@ const { JPDecoder } = require('./jp-decoder');
|
|
|
9
9
|
const iconv = require('iconv-lite');
|
|
10
10
|
|
|
11
11
|
module.exports = {
|
|
12
|
+
encodePath(connection, path) {
|
|
13
|
+
path = (path || '').toString();
|
|
14
|
+
if (!connection.enabled.has('UTF8=ACCEPT') && /[&\x00-\x08\x0b-\x0c\x0e-\x1f\u0080-\uffff]/.test(path)) {
|
|
15
|
+
try {
|
|
16
|
+
path = iconv.encode(path, 'utf-7-imap').toString();
|
|
17
|
+
} catch (err) {
|
|
18
|
+
// ignore, keep name as is
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return path;
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
decodePath(connection, path) {
|
|
25
|
+
path = (path || '').toString();
|
|
26
|
+
if (!connection.enabled.has('UTF8=ACCEPT') && /[&]/.test(path)) {
|
|
27
|
+
try {
|
|
28
|
+
path = iconv.decode(Buffer.from(path), 'utf-7-imap').toString();
|
|
29
|
+
} catch (err) {
|
|
30
|
+
// ignore, keep name as is
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return path;
|
|
34
|
+
},
|
|
35
|
+
|
|
12
36
|
normalizePath(connection, path, skipNamespace) {
|
|
13
37
|
if (Array.isArray(path)) {
|
|
14
38
|
path = path.join((connection.namespace && connection.namespace.delimiter) || '');
|
|
@@ -19,14 +43,6 @@ module.exports = {
|
|
|
19
43
|
return 'INBOX';
|
|
20
44
|
}
|
|
21
45
|
|
|
22
|
-
if (!connection.enabled.has('UTF8=ACCEPT') && /[\x00-\x08\x0b-\x0c\x0e-\x1f\u0080-\uffff]/.test(path)) {
|
|
23
|
-
try {
|
|
24
|
-
path = iconv.encode(path, 'utf-7-imap').toString();
|
|
25
|
-
} catch (err) {
|
|
26
|
-
// ignore, keep name as is
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
46
|
// ensure namespace prefix if needed
|
|
31
47
|
if (!skipNamespace && connection.namespace && connection.namespace.prefix && path.indexOf(connection.namespace.prefix) !== 0) {
|
|
32
48
|
path = connection.namespace.prefix + path;
|
|
@@ -290,9 +306,10 @@ module.exports = {
|
|
|
290
306
|
break;
|
|
291
307
|
}
|
|
292
308
|
|
|
293
|
-
default:
|
|
294
|
-
|
|
295
|
-
|
|
309
|
+
default: {
|
|
310
|
+
let match = key.match(/(body|binary)\[/i);
|
|
311
|
+
if (match) {
|
|
312
|
+
let partKey = key.replace(/^(body|binary)\[|]$/gi, '');
|
|
296
313
|
partKey = partKey.replace(/\.fields.*$/g, '');
|
|
297
314
|
|
|
298
315
|
let value = getBuffer(attribute);
|
|
@@ -308,6 +325,7 @@ module.exports = {
|
|
|
308
325
|
break;
|
|
309
326
|
}
|
|
310
327
|
break;
|
|
328
|
+
}
|
|
311
329
|
}
|
|
312
330
|
}
|
|
313
331
|
|
package/lib/types.d.ts
CHANGED
|
@@ -28,6 +28,8 @@ declare module "imapflow" {
|
|
|
28
28
|
* @param [options.verifyOnly = false] - If `true` then logs out automatically after successful authentication
|
|
29
29
|
* @param [options.proxy] - Optional proxy URL. Supports HTTP CONNECT (`http://`, `https://`) and SOCKS (`socks://`, `socks4://`, `socks5://`) proxies
|
|
30
30
|
* @param [options.qresync = false] - If true, then enables QRESYNC support. EXPUNGE notifications will include `uid` property instead of `seq`
|
|
31
|
+
* @param [options.maxIdleTime] - If set, then breaks and restarts IDLE every maxIdleTime ms
|
|
32
|
+
* @param [options.disableBinary = false] - If true, then ignores the BINARY extension when making FETCH and APPEND calls
|
|
31
33
|
*/
|
|
32
34
|
class ImapFlow extends EventEmitter {
|
|
33
35
|
constructor(options: {
|
|
@@ -54,6 +56,8 @@ declare module "imapflow" {
|
|
|
54
56
|
verifyOnly?: boolean;
|
|
55
57
|
proxy?: boolean;
|
|
56
58
|
qresync?: boolean;
|
|
59
|
+
maxIdleTime?: number;
|
|
60
|
+
disableBinary?: boolean;
|
|
57
61
|
});
|
|
58
62
|
/**
|
|
59
63
|
* Current module version as a static class property
|
|
@@ -239,7 +243,7 @@ declare module "imapflow" {
|
|
|
239
243
|
* let status = await client.status('INBOX', {unseen: true});
|
|
240
244
|
* console.log(status.unseen);
|
|
241
245
|
* // 123
|
|
242
|
-
* @param path - mailbox path to check for
|
|
246
|
+
* @param path - mailbox path to check for (unicode string)
|
|
243
247
|
* @param query - defines requested status items
|
|
244
248
|
* @param query.messages - if `true` request count of messages
|
|
245
249
|
* @param query.recent - if `true` request count of messages with \\Recent tag
|
|
@@ -340,7 +344,7 @@ declare module "imapflow" {
|
|
|
340
344
|
* Appends a new message to a mailbox
|
|
341
345
|
* @example
|
|
342
346
|
* await client.append('INBOX', rawMessageBuffer, ['\\Seen'], new Date(2000, 1, 1));
|
|
343
|
-
* @param path - Mailbox path to upload the message to
|
|
347
|
+
* @param path - Mailbox path to upload the message to (unicode string)
|
|
344
348
|
* @param content - RFC822 formatted email message
|
|
345
349
|
* @param [flags] - an array of flags to be set for the uploaded message
|
|
346
350
|
* @param [idate = now] - internal date to be set for the message
|
|
@@ -563,9 +567,12 @@ declare type QuotaResponse = {
|
|
|
563
567
|
};
|
|
564
568
|
|
|
565
569
|
/**
|
|
566
|
-
* @property path - mailbox path
|
|
570
|
+
* @property path - mailbox path (unicode string)
|
|
571
|
+
* @property pathAsListed - mailbox path as listed in the LIST/LSUB response
|
|
567
572
|
* @property name - mailbox name (last part of path after delimiter)
|
|
568
573
|
* @property delimiter - mailbox path delimiter, usually "." or "/"
|
|
574
|
+
* @property parent - An array of parent folder names. All names are in unicode
|
|
575
|
+
* @property parentPath - Same as `parent`, but as a complete string path (unicode string)
|
|
569
576
|
* @property flags - a set of flags for this mailbox
|
|
570
577
|
* @property specialUse - one of special-use flags (if applicable): "\All", "\Archive", "\Drafts", "\Flagged", "\Junk", "\Sent", "\Trash". Additionally INBOX has non-standard "\Inbox" flag set
|
|
571
578
|
* @property listed - `true` if mailbox was found from the output of LIST command
|
|
@@ -573,8 +580,11 @@ declare type QuotaResponse = {
|
|
|
573
580
|
*/
|
|
574
581
|
declare type ListResponse = {
|
|
575
582
|
path: string;
|
|
583
|
+
pathAsListed: string;
|
|
576
584
|
name: string;
|
|
577
585
|
delimiter: string;
|
|
586
|
+
parent: string[];
|
|
587
|
+
parentPath: string;
|
|
578
588
|
flags: Set<string>;
|
|
579
589
|
specialUse: string;
|
|
580
590
|
listed: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imapflow",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.92",
|
|
4
4
|
"description": "IMAP Client for Node",
|
|
5
5
|
"main": "./lib/imap-flow.js",
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"prepare": "npm run build",
|
|
9
9
|
"docs": "rm -rf docs && mkdir -p docs && jsdoc lib/imap-flow.js -c jsdoc.json -R README.md --destination docs/ && cp assets/favicon.ico docs",
|
|
10
10
|
"dst": "node types.js",
|
|
11
|
-
"build": "npm run docs && npm run dst"
|
|
11
|
+
"build": "npm run docs && npm run dst",
|
|
12
|
+
"st": "npm run docs && st -d docs -i index.html"
|
|
12
13
|
},
|
|
13
14
|
"repository": {
|
|
14
15
|
"type": "git",
|
|
@@ -29,28 +30,29 @@
|
|
|
29
30
|
"@babel/eslint-parser": "7.17.0",
|
|
30
31
|
"@babel/eslint-plugin": "7.17.7",
|
|
31
32
|
"@babel/plugin-syntax-class-properties": "7.12.13",
|
|
32
|
-
"@babel/preset-env": "7.
|
|
33
|
-
"@types/node": "17.0.
|
|
33
|
+
"@babel/preset-env": "7.17.10",
|
|
34
|
+
"@types/node": "17.0.31",
|
|
34
35
|
"braintree-jsdoc-template": "3.3.0",
|
|
35
|
-
"eslint": "8.
|
|
36
|
+
"eslint": "8.14.0",
|
|
36
37
|
"eslint-config-nodemailer": "1.2.0",
|
|
37
38
|
"eslint-config-prettier": "8.5.0",
|
|
38
|
-
"grunt": "1.
|
|
39
|
+
"grunt": "1.5.2",
|
|
39
40
|
"grunt-cli": "1.4.3",
|
|
40
41
|
"grunt-contrib-nodeunit": "4.0.0",
|
|
41
42
|
"grunt-eslint": "24.0.0",
|
|
42
43
|
"jsdoc": "3.6.10",
|
|
44
|
+
"st": "3.0.0",
|
|
43
45
|
"tsd-jsdoc": "2.5.0"
|
|
44
46
|
},
|
|
45
47
|
"dependencies": {
|
|
46
48
|
"encoding-japanese": "2.0.0",
|
|
47
49
|
"iconv-lite": "0.6.3",
|
|
48
50
|
"libbase64": "1.2.1",
|
|
49
|
-
"libmime": "5.
|
|
51
|
+
"libmime": "5.1.0",
|
|
50
52
|
"libqp": "1.1.0",
|
|
51
|
-
"mailsplit": "5.3.
|
|
52
|
-
"nodemailer": "6.7.
|
|
53
|
-
"pino": "7.
|
|
53
|
+
"mailsplit": "5.3.2",
|
|
54
|
+
"nodemailer": "6.7.4",
|
|
55
|
+
"pino": "7.11.0",
|
|
54
56
|
"socks": "2.6.2"
|
|
55
57
|
}
|
|
56
58
|
}
|
|
@@ -200,8 +200,7 @@ module.exports['IMAP Compiler: hide long strings'] = test =>
|
|
|
200
200
|
attributes: [
|
|
201
201
|
{
|
|
202
202
|
type: 'String',
|
|
203
|
-
value:
|
|
204
|
-
'Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere!'
|
|
203
|
+
value: 'Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere!'
|
|
205
204
|
},
|
|
206
205
|
'Vana kere'
|
|
207
206
|
]
|
|
@@ -248,6 +247,46 @@ module.exports['IMAP Compiler: LITERAL text'] = test =>
|
|
|
248
247
|
)
|
|
249
248
|
);
|
|
250
249
|
|
|
250
|
+
module.exports['IMAP Compiler: LITERAL literal'] = test =>
|
|
251
|
+
asyncWrapper(test, async test =>
|
|
252
|
+
test.equal(
|
|
253
|
+
await compiler({
|
|
254
|
+
tag: '*',
|
|
255
|
+
command: 'CMD',
|
|
256
|
+
attributes: [
|
|
257
|
+
// keep indentation
|
|
258
|
+
{
|
|
259
|
+
type: 'LITERAL',
|
|
260
|
+
value: 'Tere\x00 tere!',
|
|
261
|
+
isLiteral8: false
|
|
262
|
+
},
|
|
263
|
+
'Vana kere'
|
|
264
|
+
]
|
|
265
|
+
}),
|
|
266
|
+
'* CMD {11}\r\nTere\x00 tere! "Vana kere"'
|
|
267
|
+
)
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
module.exports['IMAP Compiler: LITERAL literal8'] = test =>
|
|
271
|
+
asyncWrapper(test, async test =>
|
|
272
|
+
test.equal(
|
|
273
|
+
await compiler({
|
|
274
|
+
tag: '*',
|
|
275
|
+
command: 'CMD',
|
|
276
|
+
attributes: [
|
|
277
|
+
// keep indentation
|
|
278
|
+
{
|
|
279
|
+
type: 'LITERAL',
|
|
280
|
+
value: 'Tere\x00 tere!',
|
|
281
|
+
isLiteral8: true
|
|
282
|
+
},
|
|
283
|
+
'Vana kere'
|
|
284
|
+
]
|
|
285
|
+
}),
|
|
286
|
+
'* CMD ~{11}\r\nTere\x00 tere! "Vana kere"'
|
|
287
|
+
)
|
|
288
|
+
);
|
|
289
|
+
|
|
251
290
|
module.exports['IMAP Compiler: LITERAL array 1'] = test =>
|
|
252
291
|
asyncWrapper(test, async test =>
|
|
253
292
|
test.deepEqual(
|
package/test/imap-parser-test.js
CHANGED
|
@@ -309,6 +309,36 @@ module.exports['IMAP Parser: Literals: single literal'] = test =>
|
|
|
309
309
|
])
|
|
310
310
|
);
|
|
311
311
|
|
|
312
|
+
module.exports['IMAP Parser: Literals: literal with NULL'] = test =>
|
|
313
|
+
asyncWrapper(test, async test =>
|
|
314
|
+
test.deepEqual((await parser('TAG1 CMD {4}\r\n', { literals: [Buffer.from('ab\x00d')] })).attributes, [
|
|
315
|
+
{
|
|
316
|
+
type: 'LITERAL',
|
|
317
|
+
value: Buffer.from('ab\x00d')
|
|
318
|
+
}
|
|
319
|
+
])
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
module.exports['IMAP Parser: Literals: literal8'] = test =>
|
|
323
|
+
asyncWrapper(test, async test =>
|
|
324
|
+
test.deepEqual((await parser('TAG1 CMD ~{4}\r\n', { literals: [Buffer.from('ab\x00d')] })).attributes, [
|
|
325
|
+
{
|
|
326
|
+
type: 'LITERAL',
|
|
327
|
+
value: Buffer.from('ab\x00d')
|
|
328
|
+
}
|
|
329
|
+
])
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
module.exports['IMAP Parser: Literals: unexpected literal8 prefix'] = test =>
|
|
333
|
+
asyncWrapper(test, async test => {
|
|
334
|
+
try {
|
|
335
|
+
await parser('TAG1 CMD ~\r\n');
|
|
336
|
+
test.ok(false, 'Must throw');
|
|
337
|
+
} catch (err) {
|
|
338
|
+
test.ok(err, 'Error must exist');
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
312
342
|
module.exports['IMAP Parser: Literals: multiple literals'] = test =>
|
|
313
343
|
asyncWrapper(test, async test =>
|
|
314
344
|
test.deepEqual((await parser('TAG1 CMD {4}\r\n {4}\r\n', { literals: [Buffer.from('abcd'), Buffer.from('kere')] })).attributes, [
|