imapflow 1.0.116 → 1.0.118
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 +8 -0
- package/lib/commands/list.js +71 -18
- package/lib/handler/imap-compiler.js +58 -24
- package/lib/imap-flow.js +7 -2
- package/lib/special-use.js +15 -3
- package/lib/tools.js +2 -1
- package/lib/types.d.ts +11 -0
- package/package.json +7 -7
- package/test/imap-compiler-test.js +285 -247
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
- 1.0.118 - 2022-12-22
|
|
4
|
+
|
|
5
|
+
- Refactored detecting special use folders
|
|
6
|
+
|
|
7
|
+
- 1.0.117 - 2022-12-05
|
|
8
|
+
|
|
9
|
+
- Updated command compiling. The command compiler returns a Buffer, not a "binary" string.
|
|
10
|
+
|
|
3
11
|
- 1.0.116 - 2022-11-30
|
|
4
12
|
|
|
5
13
|
- Added `SPECIAL-USE` flag by default when given parameters to `Imap#list`
|
package/lib/commands/list.js
CHANGED
|
@@ -7,11 +7,13 @@ const { specialUse } = require('../special-use');
|
|
|
7
7
|
module.exports = async (connection, reference, mailbox, options) => {
|
|
8
8
|
options = options || {};
|
|
9
9
|
|
|
10
|
+
const FLAG_SORT_ORDER = ['\\Inbox', '\\Flagged', '\\Sent', '\\Drafts', '\\All', '\\Archive', '\\Junk', '\\Trash'];
|
|
11
|
+
const SOURCE_SORT_ORDER = ['user', 'extension', 'name'];
|
|
12
|
+
|
|
10
13
|
let listCommand = connection.capabilities.has('XLIST') && !connection.capabilities.has('SPECIAL-USE') ? 'XLIST' : 'LIST';
|
|
11
14
|
|
|
12
15
|
let response;
|
|
13
16
|
try {
|
|
14
|
-
let flagsSeen = new Set();
|
|
15
17
|
let entries = [];
|
|
16
18
|
|
|
17
19
|
let statusMap = new Map();
|
|
@@ -49,6 +51,23 @@ module.exports = async (connection, reference, mailbox, options) => {
|
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
|
|
54
|
+
let specialUseMatches = {};
|
|
55
|
+
let addSpecialUseMatch = (entry, type, source) => {
|
|
56
|
+
if (!specialUseMatches[type]) {
|
|
57
|
+
specialUseMatches[type] = [];
|
|
58
|
+
}
|
|
59
|
+
specialUseMatches[type].push({ entry, source });
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
let specialUseHints = {};
|
|
63
|
+
if (options.specialUseHints && typeof options.specialUseHints === 'object') {
|
|
64
|
+
for (let type of Object.keys(options.specialUseHints)) {
|
|
65
|
+
if (['sent', 'junk', 'trash', 'drafts'].includes(type)) {
|
|
66
|
+
specialUseHints[normalizePath(connection, options.specialUseHints[type])] = `\\${type.replace(/^./, c => c.toUpperCase())}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
52
71
|
let runList = async (reference, mailbox) => {
|
|
53
72
|
const cmdArgs = [encodePath(connection, reference), encodePath(connection, mailbox)];
|
|
54
73
|
|
|
@@ -71,17 +90,21 @@ module.exports = async (connection, reference, mailbox, options) => {
|
|
|
71
90
|
listed: true
|
|
72
91
|
};
|
|
73
92
|
|
|
93
|
+
if (specialUseHints[entry.path]) {
|
|
94
|
+
addSpecialUseMatch(entry, specialUseHints[entry.path], 'user');
|
|
95
|
+
}
|
|
96
|
+
|
|
74
97
|
if (listCommand === 'XLIST' && entry.flags.has('\\Inbox')) {
|
|
75
98
|
// XLIST specific flag, ignore
|
|
76
99
|
entry.flags.delete('\\Inbox');
|
|
77
100
|
if (entry.path !== 'INBOX') {
|
|
78
101
|
// XLIST may use localised inbox name
|
|
79
|
-
entry
|
|
102
|
+
addSpecialUseMatch(entry, '\\Inbox', 'extension');
|
|
80
103
|
}
|
|
81
104
|
}
|
|
82
105
|
|
|
83
106
|
if (entry.path.toUpperCase() === 'INBOX') {
|
|
84
|
-
entry
|
|
107
|
+
addSpecialUseMatch(entry, '\\Inbox', 'name');
|
|
85
108
|
}
|
|
86
109
|
|
|
87
110
|
if (entry.delimiter && entry.path.charAt(0) === entry.delimiter) {
|
|
@@ -92,9 +115,13 @@ module.exports = async (connection, reference, mailbox, options) => {
|
|
|
92
115
|
entry.parent = entry.delimiter ? entry.path.split(entry.delimiter) : [entry.path];
|
|
93
116
|
entry.name = entry.parent.pop();
|
|
94
117
|
|
|
95
|
-
let specialUseFlag = specialUse(
|
|
96
|
-
|
|
97
|
-
entry
|
|
118
|
+
let { flag: specialUseFlag, source: flagSource } = specialUse(
|
|
119
|
+
connection.capabilities.has('XLIST') || connection.capabilities.has('SPECIAL-USE'),
|
|
120
|
+
entry
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (specialUseFlag) {
|
|
124
|
+
addSpecialUseMatch(entry, specialUseFlag, flagSource);
|
|
98
125
|
}
|
|
99
126
|
|
|
100
127
|
entries.push(entry);
|
|
@@ -172,7 +199,7 @@ module.exports = async (connection, reference, mailbox, options) => {
|
|
|
172
199
|
return entries;
|
|
173
200
|
}
|
|
174
201
|
|
|
175
|
-
if (normalizedReference && !
|
|
202
|
+
if (normalizedReference && !specialUseMatches['\\Inbox']) {
|
|
176
203
|
// INBOX was most probably not included in the listing if namespace was used
|
|
177
204
|
await runList('', 'INBOX');
|
|
178
205
|
}
|
|
@@ -213,7 +240,7 @@ module.exports = async (connection, reference, mailbox, options) => {
|
|
|
213
240
|
};
|
|
214
241
|
|
|
215
242
|
if (entry.path.toUpperCase() === 'INBOX') {
|
|
216
|
-
entry
|
|
243
|
+
addSpecialUseMatch(entry, '\\Inbox', 'name');
|
|
217
244
|
}
|
|
218
245
|
|
|
219
246
|
if (entry.delimiter && entry.path.charAt(0) === entry.delimiter) {
|
|
@@ -244,26 +271,52 @@ module.exports = async (connection, reference, mailbox, options) => {
|
|
|
244
271
|
);
|
|
245
272
|
response.next();
|
|
246
273
|
|
|
274
|
+
for (let type of Object.keys(specialUseMatches)) {
|
|
275
|
+
let sortedEntries = specialUseMatches[type].sort((a, b) => {
|
|
276
|
+
let aSource = SOURCE_SORT_ORDER.indexOf(a.source);
|
|
277
|
+
let bSource = SOURCE_SORT_ORDER.indexOf(b.source);
|
|
278
|
+
if (aSource === bSource) {
|
|
279
|
+
return a.entry.path.localeCompare(b.entry.path);
|
|
280
|
+
}
|
|
281
|
+
return aSource - bSource;
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (!sortedEntries[0].entry.specialUse) {
|
|
285
|
+
sortedEntries[0].entry.specialUse = type;
|
|
286
|
+
sortedEntries[0].entry.specialUseSource = sortedEntries[0].source;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
247
290
|
let inboxEntry = entries.find(entry => entry.specialUse === '\\Inbox');
|
|
248
291
|
if (inboxEntry && !inboxEntry.subscribed) {
|
|
249
292
|
// override server settings and make INBOX always as subscribed
|
|
250
293
|
inboxEntry.subscribed = true;
|
|
251
294
|
}
|
|
252
295
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
296
|
+
return entries.sort((a, b) => {
|
|
297
|
+
if (a.specialUse && !b.specialUse) {
|
|
298
|
+
return -1;
|
|
299
|
+
}
|
|
300
|
+
if (!a.specialUse && b.specialUse) {
|
|
301
|
+
return 1;
|
|
257
302
|
}
|
|
303
|
+
if (a.specialUse && b.specialUse) {
|
|
304
|
+
return FLAG_SORT_ORDER.indexOf(a.specialUse) - FLAG_SORT_ORDER.indexOf(b.specialUse);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
let aList = [].concat(a.parent).concat(a.name);
|
|
308
|
+
let bList = [].concat(b.parent).concat(b.name);
|
|
258
309
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
310
|
+
for (let i = 0; i < aList.length; i++) {
|
|
311
|
+
let aPart = aList[i];
|
|
312
|
+
let bPart = bList[i];
|
|
313
|
+
if (aPart !== bPart) {
|
|
314
|
+
return aPart.localeCompare(bPart || '');
|
|
315
|
+
}
|
|
263
316
|
}
|
|
264
|
-
});
|
|
265
317
|
|
|
266
|
-
|
|
318
|
+
return a.path.localeCompare(b.path);
|
|
319
|
+
});
|
|
267
320
|
} catch (err) {
|
|
268
321
|
connection.log.warn({ msg: 'Failed to list folders', err, cid: connection.id });
|
|
269
322
|
throw err;
|
|
@@ -4,6 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
const imapFormalSyntax = require('./imap-formal-syntax');
|
|
6
6
|
|
|
7
|
+
const formatRespEntry = (entry, returnEmpty) => {
|
|
8
|
+
if (typeof entry === 'string') {
|
|
9
|
+
return Buffer.from(entry);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (typeof entry === 'number') {
|
|
13
|
+
return Buffer.from(entry.toString());
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (Buffer.isBuffer(entry)) {
|
|
17
|
+
return entry;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (returnEmpty) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return Buffer.alloc(0);
|
|
25
|
+
};
|
|
26
|
+
|
|
7
27
|
/**
|
|
8
28
|
* Compiles an input object into
|
|
9
29
|
*/
|
|
@@ -11,18 +31,24 @@ module.exports = async (response, options) => {
|
|
|
11
31
|
let { asArray, isLogging, literalPlus, literalMinus } = options || {};
|
|
12
32
|
const respParts = [];
|
|
13
33
|
|
|
14
|
-
let resp = (response.tag ||
|
|
34
|
+
let resp = [].concat(formatRespEntry(response.tag, true) || []).concat(response.command ? formatRespEntry(' ' + response.command) : []);
|
|
15
35
|
let val;
|
|
16
36
|
let lastType;
|
|
17
37
|
|
|
18
38
|
let walk = async (node, options) => {
|
|
19
39
|
options = options || {};
|
|
20
40
|
|
|
21
|
-
|
|
41
|
+
let lastRespEntry = resp.length && resp[resp.length - 1];
|
|
42
|
+
let lastRespByte = (lastRespEntry && lastRespEntry.length && lastRespEntry[lastRespEntry.length - 1]) || '';
|
|
43
|
+
if (typeof lastRespByte === 'number') {
|
|
44
|
+
lastRespByte = String.fromCharCode(lastRespByte);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (lastType === 'LITERAL' || (!['(', '<', '['].includes(lastRespByte) && resp.length)) {
|
|
22
48
|
if (options.subArray) {
|
|
23
49
|
// ignore separator
|
|
24
50
|
} else {
|
|
25
|
-
resp
|
|
51
|
+
resp.push(formatRespEntry(' '));
|
|
26
52
|
}
|
|
27
53
|
}
|
|
28
54
|
|
|
@@ -33,7 +59,7 @@ module.exports = async (response, options) => {
|
|
|
33
59
|
|
|
34
60
|
if (Array.isArray(node)) {
|
|
35
61
|
lastType = 'LIST';
|
|
36
|
-
resp
|
|
62
|
+
resp.push(formatRespEntry('('));
|
|
37
63
|
|
|
38
64
|
// check if we need to skip separtor WS between two arrays
|
|
39
65
|
let subArray = node.length > 1 && Array.isArray(node[0]);
|
|
@@ -45,97 +71,101 @@ module.exports = async (response, options) => {
|
|
|
45
71
|
await walk(child, { subArray });
|
|
46
72
|
}
|
|
47
73
|
|
|
48
|
-
resp
|
|
74
|
+
resp.push(formatRespEntry(')'));
|
|
49
75
|
return;
|
|
50
76
|
}
|
|
51
77
|
|
|
52
78
|
if (!node && typeof node !== 'string' && typeof node !== 'number' && !Buffer.isBuffer(node)) {
|
|
53
|
-
resp
|
|
79
|
+
resp.push(formatRespEntry('NIL'));
|
|
54
80
|
return;
|
|
55
81
|
}
|
|
56
82
|
|
|
57
83
|
if (typeof node === 'string' || Buffer.isBuffer(node)) {
|
|
58
84
|
if (isLogging && node.length > 100) {
|
|
59
|
-
resp
|
|
85
|
+
resp.push(formatRespEntry('"(* ' + node.length + 'B string *)"'));
|
|
60
86
|
} else {
|
|
61
|
-
resp
|
|
87
|
+
resp.push(formatRespEntry(JSON.stringify(node.toString())));
|
|
62
88
|
}
|
|
63
89
|
return;
|
|
64
90
|
}
|
|
65
91
|
|
|
66
92
|
if (typeof node === 'number') {
|
|
67
|
-
resp
|
|
93
|
+
resp.push(formatRespEntry(Math.round(node) || 0)); // Only integers allowed
|
|
68
94
|
return;
|
|
69
95
|
}
|
|
70
96
|
|
|
71
97
|
lastType = node.type;
|
|
72
98
|
|
|
73
99
|
if (isLogging && node.sensitive) {
|
|
74
|
-
resp
|
|
100
|
+
resp.push(formatRespEntry('"(* value hidden *)"'));
|
|
75
101
|
return;
|
|
76
102
|
}
|
|
77
103
|
|
|
78
104
|
switch (node.type.toUpperCase()) {
|
|
79
105
|
case 'LITERAL':
|
|
80
106
|
if (isLogging) {
|
|
81
|
-
resp
|
|
107
|
+
resp.push(formatRespEntry('"(* ' + node.value.length + 'B literal *)"'));
|
|
82
108
|
} else {
|
|
83
109
|
let literalLength = !node.value ? 0 : Math.max(node.value.length, 0);
|
|
84
110
|
|
|
85
111
|
let canAppend = !asArray || literalPlus || (literalMinus && literalLength <= 4096);
|
|
86
112
|
let usePlus = canAppend && (literalMinus || literalPlus);
|
|
87
113
|
|
|
88
|
-
resp
|
|
114
|
+
resp.push(formatRespEntry(`${node.isLiteral8 ? '~' : ''}{${literalLength}${usePlus ? '+' : ''}}\r\n`));
|
|
89
115
|
|
|
90
116
|
if (canAppend) {
|
|
91
|
-
|
|
117
|
+
if (node.value && node.value.length) {
|
|
118
|
+
resp.push(formatRespEntry(node.value));
|
|
119
|
+
}
|
|
92
120
|
} else {
|
|
93
121
|
respParts.push(resp);
|
|
94
|
-
resp = (node.value ||
|
|
122
|
+
resp = [].concat(formatRespEntry(node.value, true) || []);
|
|
95
123
|
}
|
|
96
124
|
}
|
|
97
125
|
break;
|
|
98
126
|
|
|
99
127
|
case 'STRING':
|
|
100
128
|
if (isLogging && node.value.length > 100) {
|
|
101
|
-
resp
|
|
129
|
+
resp.push(formatRespEntry('"(* ' + node.value.length + 'B string *)"'));
|
|
102
130
|
} else {
|
|
103
|
-
resp
|
|
131
|
+
resp.push(formatRespEntry(JSON.stringify((node.value || '').toString())));
|
|
104
132
|
}
|
|
105
133
|
break;
|
|
106
134
|
|
|
107
135
|
case 'TEXT':
|
|
108
136
|
case 'SEQUENCE':
|
|
109
|
-
|
|
137
|
+
if (node.value) {
|
|
138
|
+
resp.push(formatRespEntry(node.value));
|
|
139
|
+
}
|
|
110
140
|
break;
|
|
111
141
|
|
|
112
142
|
case 'NUMBER':
|
|
113
|
-
resp
|
|
143
|
+
resp.push(formatRespEntry(node.value || 0));
|
|
114
144
|
break;
|
|
115
145
|
|
|
116
146
|
case 'ATOM':
|
|
117
147
|
case 'SECTION':
|
|
118
|
-
val = (node.value || '').toString(
|
|
148
|
+
val = (node.value || '').toString();
|
|
119
149
|
|
|
120
150
|
if (!node.section || val) {
|
|
121
151
|
if (node.value === '' || imapFormalSyntax.verify(val.charAt(0) === '\\' ? val.substr(1) : val, imapFormalSyntax['ATOM-CHAR']()) >= 0) {
|
|
122
152
|
val = JSON.stringify(val);
|
|
123
153
|
}
|
|
124
154
|
|
|
125
|
-
resp
|
|
155
|
+
resp.push(formatRespEntry(val));
|
|
126
156
|
}
|
|
127
157
|
|
|
128
158
|
if (node.section) {
|
|
129
|
-
resp
|
|
159
|
+
resp.push(formatRespEntry('['));
|
|
130
160
|
|
|
131
161
|
for (let child of node.section) {
|
|
132
162
|
await walk(child);
|
|
133
163
|
}
|
|
134
164
|
|
|
135
|
-
resp
|
|
165
|
+
resp.push(formatRespEntry(']'));
|
|
136
166
|
}
|
|
137
167
|
if (node.partial) {
|
|
138
|
-
resp
|
|
168
|
+
resp.push(formatRespEntry(`<${node.partial.join('.')}>`));
|
|
139
169
|
}
|
|
140
170
|
break;
|
|
141
171
|
}
|
|
@@ -152,5 +182,9 @@ module.exports = async (response, options) => {
|
|
|
152
182
|
respParts.push(resp);
|
|
153
183
|
}
|
|
154
184
|
|
|
155
|
-
|
|
185
|
+
for (let i = 0; i < respParts.length; i++) {
|
|
186
|
+
respParts[i] = Buffer.concat(respParts[i]);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return asArray ? respParts : respParts.flatMap(entry => entry);
|
|
156
190
|
};
|
package/lib/imap-flow.js
CHANGED
|
@@ -380,7 +380,7 @@ class ImapFlow extends EventEmitter {
|
|
|
380
380
|
let options = data.options || {};
|
|
381
381
|
|
|
382
382
|
this.log.debug({ src: 's', msg: logCompiled.toString(), cid: this.id, comment: options.comment });
|
|
383
|
-
this.write(
|
|
383
|
+
this.write(this.commandParts.shift());
|
|
384
384
|
|
|
385
385
|
if (typeof options.onSend === 'function') {
|
|
386
386
|
options.onSend();
|
|
@@ -491,7 +491,7 @@ class ImapFlow extends EventEmitter {
|
|
|
491
491
|
}
|
|
492
492
|
|
|
493
493
|
if (parsed.tag === '+' && this.commandParts.length) {
|
|
494
|
-
let content =
|
|
494
|
+
let content = this.commandParts.shift();
|
|
495
495
|
this.write(content);
|
|
496
496
|
this.log.debug({ src: 'c', msg: `(* ${content.length}B continuation *)`, cid: this.id });
|
|
497
497
|
data.next();
|
|
@@ -1452,6 +1452,11 @@ class ImapFlow extends EventEmitter {
|
|
|
1452
1452
|
* @param {Boolean} [options.statusQuery.uidValidity] if `true` request mailbox `UIDVALIDITY` value
|
|
1453
1453
|
* @param {Boolean} [options.statusQuery.unseen] if `true` request count of unseen messages
|
|
1454
1454
|
* @param {Boolean} [options.statusQuery.highestModseq] if `true` request last known modseq value
|
|
1455
|
+
* @param {Object} [options.specialUseHints] set specific paths as special use folders, this would override special use flags provided from the server
|
|
1456
|
+
* @param {String} [options.specialUseHints.sent] Path to "Sent Mail" folder
|
|
1457
|
+
* @param {String} [options.specialUseHints.trash] Path to "Trash" folder
|
|
1458
|
+
* @param {String} [options.specialUseHints.junk] Path to "Junk Mail" folder
|
|
1459
|
+
* @param {String} [options.specialUseHints.drafts] Path to "Drafts" folder
|
|
1455
1460
|
* @returns {Promise<ListResponse[]>} An array of ListResponse objects
|
|
1456
1461
|
*
|
|
1457
1462
|
* @example
|
package/lib/special-use.js
CHANGED
|
@@ -269,11 +269,23 @@ module.exports = {
|
|
|
269
269
|
},
|
|
270
270
|
|
|
271
271
|
specialUse(hasSpecialUseExtension, folder) {
|
|
272
|
+
let result;
|
|
273
|
+
|
|
272
274
|
if (hasSpecialUseExtension) {
|
|
273
|
-
|
|
275
|
+
result = {
|
|
276
|
+
flag: module.exports.flags.find(flag => folder.flags.has(flag)),
|
|
277
|
+
source: 'extension'
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (!result || !result.flag) {
|
|
282
|
+
let name = folder.name.toLowerCase().trim();
|
|
283
|
+
result = {
|
|
284
|
+
flag: Object.keys(module.exports.names).find(flag => module.exports.names[flag].includes(name)),
|
|
285
|
+
source: 'name'
|
|
286
|
+
};
|
|
274
287
|
}
|
|
275
288
|
|
|
276
|
-
|
|
277
|
-
return Object.keys(module.exports.names).find(flag => module.exports.names[flag].includes(name));
|
|
289
|
+
return result && result.flag ? result : { flag: null };
|
|
278
290
|
}
|
|
279
291
|
};
|
package/lib/tools.js
CHANGED
|
@@ -103,7 +103,7 @@ module.exports = {
|
|
|
103
103
|
return false;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
return await compiler(response);
|
|
106
|
+
return (await compiler(response)).toString();
|
|
107
107
|
},
|
|
108
108
|
|
|
109
109
|
getFolderTree(folders) {
|
|
@@ -202,6 +202,7 @@ module.exports = {
|
|
|
202
202
|
attributes: [attribute]
|
|
203
203
|
})
|
|
204
204
|
)
|
|
205
|
+
.toString()
|
|
205
206
|
.toLowerCase()
|
|
206
207
|
.replace(/<\d+>$/, '');
|
|
207
208
|
continue;
|
package/lib/types.d.ts
CHANGED
|
@@ -167,6 +167,11 @@ declare module "imapflow" {
|
|
|
167
167
|
* @param [options.statusQuery.uidValidity] - if `true` request mailbox `UIDVALIDITY` value
|
|
168
168
|
* @param [options.statusQuery.unseen] - if `true` request count of unseen messages
|
|
169
169
|
* @param [options.statusQuery.highestModseq] - if `true` request last known modseq value
|
|
170
|
+
* @param [options.specialUseHints] - set specific paths as special use folders, this would override special use flags provided from the server
|
|
171
|
+
* @param [options.specialUseHints.sent] - Path to "Sent Mail" folder
|
|
172
|
+
* @param [options.specialUseHints.trash] - Path to "Trash" folder
|
|
173
|
+
* @param [options.specialUseHints.junk] - Path to "Junk Mail" folder
|
|
174
|
+
* @param [options.specialUseHints.drafts] - Path to "Drafts" folder
|
|
170
175
|
* @returns An array of ListResponse objects
|
|
171
176
|
*/
|
|
172
177
|
list(options?: {
|
|
@@ -178,6 +183,12 @@ declare module "imapflow" {
|
|
|
178
183
|
unseen?: boolean;
|
|
179
184
|
highestModseq?: boolean;
|
|
180
185
|
};
|
|
186
|
+
specialUseHints?: {
|
|
187
|
+
sent?: string;
|
|
188
|
+
trash?: string;
|
|
189
|
+
junk?: string;
|
|
190
|
+
drafts?: string;
|
|
191
|
+
};
|
|
181
192
|
}): Promise<ListResponse[]>;
|
|
182
193
|
/**
|
|
183
194
|
* Lists available mailboxes as a tree structured object
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imapflow",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.118",
|
|
4
4
|
"description": "IMAP Client for Node",
|
|
5
5
|
"main": "./lib/imap-flow.js",
|
|
6
6
|
"scripts": {
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
"@babel/eslint-plugin": "7.19.1",
|
|
32
32
|
"@babel/plugin-syntax-class-properties": "7.12.13",
|
|
33
33
|
"@babel/preset-env": "7.20.2",
|
|
34
|
-
"@types/node": "18.11.
|
|
34
|
+
"@types/node": "18.11.17",
|
|
35
35
|
"braintree-jsdoc-template": "3.3.0",
|
|
36
|
-
"eslint": "8.
|
|
36
|
+
"eslint": "8.30.0",
|
|
37
37
|
"eslint-config-nodemailer": "1.2.0",
|
|
38
38
|
"eslint-config-prettier": "8.5.0",
|
|
39
39
|
"grunt": "1.5.3",
|
|
40
40
|
"grunt-cli": "1.4.3",
|
|
41
41
|
"grunt-contrib-nodeunit": "4.0.0",
|
|
42
|
-
"grunt-eslint": "24.0.
|
|
42
|
+
"grunt-eslint": "24.0.1",
|
|
43
43
|
"jsdoc": "3.6.11",
|
|
44
44
|
"st": "3.0.0",
|
|
45
45
|
"tsd-jsdoc": "2.5.0"
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"encoding-japanese": "2.0.0",
|
|
49
49
|
"iconv-lite": "0.6.3",
|
|
50
50
|
"libbase64": "1.2.1",
|
|
51
|
-
"libmime": "5.
|
|
51
|
+
"libmime": "5.2.0",
|
|
52
52
|
"libqp": "2.0.1",
|
|
53
|
-
"mailsplit": "5.
|
|
53
|
+
"mailsplit": "5.4.0",
|
|
54
54
|
"nodemailer": "6.8.0",
|
|
55
|
-
"pino": "8.
|
|
55
|
+
"pino": "8.8.0",
|
|
56
56
|
"socks": "2.7.1"
|
|
57
57
|
}
|
|
58
58
|
}
|
|
@@ -20,17 +20,19 @@ module.exports['IMAP Compiler: mixed'] = test =>
|
|
|
20
20
|
const parsed = await parser(command, {
|
|
21
21
|
allowUntagged: true
|
|
22
22
|
});
|
|
23
|
-
const compiled = await compiler(parsed);
|
|
23
|
+
const compiled = (await compiler(parsed)).toString();
|
|
24
24
|
test.equal(compiled, command);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
module.exports['IMAP Compiler: no attributes'] = test =>
|
|
28
28
|
asyncWrapper(test, async test =>
|
|
29
29
|
test.equal(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
(
|
|
31
|
+
await compiler({
|
|
32
|
+
tag: '*',
|
|
33
|
+
command: 'CMD'
|
|
34
|
+
})
|
|
35
|
+
).toString(),
|
|
34
36
|
'* CMD'
|
|
35
37
|
)
|
|
36
38
|
);
|
|
@@ -38,16 +40,18 @@ module.exports['IMAP Compiler: no attributes'] = test =>
|
|
|
38
40
|
module.exports['IMAP Compiler: TEXT'] = test =>
|
|
39
41
|
asyncWrapper(test, async test =>
|
|
40
42
|
test.equal(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
(
|
|
44
|
+
await compiler({
|
|
45
|
+
tag: '*',
|
|
46
|
+
command: 'CMD',
|
|
47
|
+
attributes: [
|
|
48
|
+
{
|
|
49
|
+
type: 'TEXT',
|
|
50
|
+
value: 'Tere tere!'
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
})
|
|
54
|
+
).toString(),
|
|
51
55
|
'* CMD Tere tere!'
|
|
52
56
|
)
|
|
53
57
|
);
|
|
@@ -55,21 +59,23 @@ module.exports['IMAP Compiler: TEXT'] = test =>
|
|
|
55
59
|
module.exports['IMAP Compiler: SECTION'] = test =>
|
|
56
60
|
asyncWrapper(test, async test =>
|
|
57
61
|
test.equal(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
62
|
+
(
|
|
63
|
+
await compiler({
|
|
64
|
+
tag: '*',
|
|
65
|
+
command: 'CMD',
|
|
66
|
+
attributes: [
|
|
67
|
+
{
|
|
68
|
+
type: 'SECTION',
|
|
69
|
+
section: [
|
|
70
|
+
{
|
|
71
|
+
type: 'ATOM',
|
|
72
|
+
value: 'ALERT'
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
})
|
|
78
|
+
).toString(),
|
|
73
79
|
'* CMD [ALERT]'
|
|
74
80
|
)
|
|
75
81
|
);
|
|
@@ -77,24 +83,26 @@ module.exports['IMAP Compiler: SECTION'] = test =>
|
|
|
77
83
|
module.exports['IMAP Compiler: escaped ATOM'] = test =>
|
|
78
84
|
asyncWrapper(test, async test =>
|
|
79
85
|
test.equal(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
86
|
+
(
|
|
87
|
+
await compiler({
|
|
88
|
+
tag: '*',
|
|
89
|
+
command: 'CMD',
|
|
90
|
+
attributes: [
|
|
91
|
+
{
|
|
92
|
+
type: 'ATOM',
|
|
93
|
+
value: 'ALERT'
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
type: 'ATOM',
|
|
97
|
+
value: '\\ALERT'
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
type: 'ATOM',
|
|
101
|
+
value: 'NO ALERT'
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
})
|
|
105
|
+
).toString(),
|
|
98
106
|
'* CMD ALERT \\ALERT "NO ALERT"'
|
|
99
107
|
)
|
|
100
108
|
);
|
|
@@ -102,16 +110,18 @@ module.exports['IMAP Compiler: escaped ATOM'] = test =>
|
|
|
102
110
|
module.exports['IMAP Compiler: SEQUENCE'] = test =>
|
|
103
111
|
asyncWrapper(test, async test =>
|
|
104
112
|
test.equal(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
(
|
|
114
|
+
await compiler({
|
|
115
|
+
tag: '*',
|
|
116
|
+
command: 'CMD',
|
|
117
|
+
attributes: [
|
|
118
|
+
{
|
|
119
|
+
type: 'SEQUENCE',
|
|
120
|
+
value: '*:4,5,6'
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
})
|
|
124
|
+
).toString(),
|
|
115
125
|
'* CMD *:4,5,6'
|
|
116
126
|
)
|
|
117
127
|
);
|
|
@@ -119,11 +129,13 @@ module.exports['IMAP Compiler: SEQUENCE'] = test =>
|
|
|
119
129
|
module.exports['IMAP Compiler: NIL'] = test =>
|
|
120
130
|
asyncWrapper(test, async test =>
|
|
121
131
|
test.equal(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
132
|
+
(
|
|
133
|
+
await compiler({
|
|
134
|
+
tag: '*',
|
|
135
|
+
command: 'CMD',
|
|
136
|
+
attributes: [null, null]
|
|
137
|
+
})
|
|
138
|
+
).toString(),
|
|
127
139
|
'* CMD NIL NIL'
|
|
128
140
|
)
|
|
129
141
|
);
|
|
@@ -131,39 +143,43 @@ module.exports['IMAP Compiler: NIL'] = test =>
|
|
|
131
143
|
module.exports['IMAP Compiler: quoted TEXT'] = test =>
|
|
132
144
|
asyncWrapper(test, async test =>
|
|
133
145
|
test.equal(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
command: 'CMD',
|
|
137
|
-
attributes: [
|
|
138
|
-
{
|
|
139
|
-
type: 'String',
|
|
140
|
-
value: 'Tere tere!',
|
|
141
|
-
sensitive: true
|
|
142
|
-
},
|
|
143
|
-
'Vana kere'
|
|
144
|
-
]
|
|
145
|
-
}),
|
|
146
|
-
'* CMD "Tere tere!" "Vana kere"'
|
|
147
|
-
)
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
module.exports['IMAP Compiler: keep short strings'] = test =>
|
|
151
|
-
asyncWrapper(test, async test =>
|
|
152
|
-
test.equal(
|
|
153
|
-
await compiler(
|
|
154
|
-
{
|
|
146
|
+
(
|
|
147
|
+
await compiler({
|
|
155
148
|
tag: '*',
|
|
156
149
|
command: 'CMD',
|
|
157
150
|
attributes: [
|
|
158
151
|
{
|
|
159
152
|
type: 'String',
|
|
160
|
-
value: 'Tere tere!'
|
|
153
|
+
value: 'Tere tere!',
|
|
154
|
+
sensitive: true
|
|
161
155
|
},
|
|
162
156
|
'Vana kere'
|
|
163
157
|
]
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
158
|
+
})
|
|
159
|
+
).toString(),
|
|
160
|
+
'* CMD "Tere tere!" "Vana kere"'
|
|
161
|
+
)
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
module.exports['IMAP Compiler: keep short strings'] = test =>
|
|
165
|
+
asyncWrapper(test, async test =>
|
|
166
|
+
test.equal(
|
|
167
|
+
(
|
|
168
|
+
await compiler(
|
|
169
|
+
{
|
|
170
|
+
tag: '*',
|
|
171
|
+
command: 'CMD',
|
|
172
|
+
attributes: [
|
|
173
|
+
{
|
|
174
|
+
type: 'String',
|
|
175
|
+
value: 'Tere tere!'
|
|
176
|
+
},
|
|
177
|
+
'Vana kere'
|
|
178
|
+
]
|
|
179
|
+
},
|
|
180
|
+
{ asArray: false, isLogging: true }
|
|
181
|
+
)
|
|
182
|
+
).toString(),
|
|
167
183
|
'* CMD "Tere tere!" "Vana kere"'
|
|
168
184
|
)
|
|
169
185
|
);
|
|
@@ -171,21 +187,23 @@ module.exports['IMAP Compiler: keep short strings'] = test =>
|
|
|
171
187
|
module.exports['IMAP Compiler: hide sensitive strings'] = test =>
|
|
172
188
|
asyncWrapper(test, async test =>
|
|
173
189
|
test.equal(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
(
|
|
191
|
+
await compiler(
|
|
192
|
+
{
|
|
193
|
+
tag: '*',
|
|
194
|
+
command: 'CMD',
|
|
195
|
+
attributes: [
|
|
196
|
+
{
|
|
197
|
+
type: 'String',
|
|
198
|
+
value: 'Tere tere!',
|
|
199
|
+
sensitive: true
|
|
200
|
+
},
|
|
201
|
+
'Vana kere'
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
{ asArray: false, isLogging: true }
|
|
205
|
+
)
|
|
206
|
+
).toString(),
|
|
189
207
|
'* CMD "(* value hidden *)" "Vana kere"'
|
|
190
208
|
)
|
|
191
209
|
);
|
|
@@ -193,20 +211,22 @@ module.exports['IMAP Compiler: hide sensitive strings'] = test =>
|
|
|
193
211
|
module.exports['IMAP Compiler: hide long strings'] = test =>
|
|
194
212
|
asyncWrapper(test, async test =>
|
|
195
213
|
test.equal(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
214
|
+
(
|
|
215
|
+
await compiler(
|
|
216
|
+
{
|
|
217
|
+
tag: '*',
|
|
218
|
+
command: 'CMD',
|
|
219
|
+
attributes: [
|
|
220
|
+
{
|
|
221
|
+
type: 'String',
|
|
222
|
+
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!'
|
|
223
|
+
},
|
|
224
|
+
'Vana kere'
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
{ asArray: false, isLogging: true }
|
|
228
|
+
)
|
|
229
|
+
).toString(),
|
|
210
230
|
'* CMD "(* 219B string *)" "Vana kere"'
|
|
211
231
|
)
|
|
212
232
|
);
|
|
@@ -214,16 +234,18 @@ module.exports['IMAP Compiler: hide long strings'] = test =>
|
|
|
214
234
|
module.exports['IMAP Compiler: no command'] = test =>
|
|
215
235
|
asyncWrapper(test, async test =>
|
|
216
236
|
test.equal(
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
237
|
+
(
|
|
238
|
+
await compiler({
|
|
239
|
+
tag: '*',
|
|
240
|
+
attributes: [
|
|
241
|
+
1,
|
|
242
|
+
{
|
|
243
|
+
type: 'ATOM',
|
|
244
|
+
value: 'EXPUNGE'
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
})
|
|
248
|
+
).toString(),
|
|
227
249
|
'* 1 EXPUNGE'
|
|
228
250
|
)
|
|
229
251
|
);
|
|
@@ -231,18 +253,20 @@ module.exports['IMAP Compiler: no command'] = test =>
|
|
|
231
253
|
module.exports['IMAP Compiler: LITERAL text'] = test =>
|
|
232
254
|
asyncWrapper(test, async test =>
|
|
233
255
|
test.equal(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
256
|
+
(
|
|
257
|
+
await compiler({
|
|
258
|
+
tag: '*',
|
|
259
|
+
command: 'CMD',
|
|
260
|
+
attributes: [
|
|
261
|
+
// keep indentation
|
|
262
|
+
{
|
|
263
|
+
type: 'LITERAL',
|
|
264
|
+
value: 'Tere tere!'
|
|
265
|
+
},
|
|
266
|
+
'Vana kere'
|
|
267
|
+
]
|
|
268
|
+
})
|
|
269
|
+
).toString(),
|
|
246
270
|
'* CMD {10}\r\nTere tere! "Vana kere"'
|
|
247
271
|
)
|
|
248
272
|
);
|
|
@@ -250,19 +274,21 @@ module.exports['IMAP Compiler: LITERAL text'] = test =>
|
|
|
250
274
|
module.exports['IMAP Compiler: LITERAL literal'] = test =>
|
|
251
275
|
asyncWrapper(test, async test =>
|
|
252
276
|
test.equal(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
277
|
+
(
|
|
278
|
+
await compiler({
|
|
279
|
+
tag: '*',
|
|
280
|
+
command: 'CMD',
|
|
281
|
+
attributes: [
|
|
282
|
+
// keep indentation
|
|
283
|
+
{
|
|
284
|
+
type: 'LITERAL',
|
|
285
|
+
value: 'Tere\x00 tere!',
|
|
286
|
+
isLiteral8: false
|
|
287
|
+
},
|
|
288
|
+
'Vana kere'
|
|
289
|
+
]
|
|
290
|
+
})
|
|
291
|
+
).toString(),
|
|
266
292
|
'* CMD {11}\r\nTere\x00 tere! "Vana kere"'
|
|
267
293
|
)
|
|
268
294
|
);
|
|
@@ -270,43 +296,47 @@ module.exports['IMAP Compiler: LITERAL literal'] = test =>
|
|
|
270
296
|
module.exports['IMAP Compiler: LITERAL literal8'] = test =>
|
|
271
297
|
asyncWrapper(test, async test =>
|
|
272
298
|
test.equal(
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
290
|
-
module.exports['IMAP Compiler: LITERAL array 1'] = test =>
|
|
291
|
-
asyncWrapper(test, async test =>
|
|
292
|
-
test.deepEqual(
|
|
293
|
-
await compiler(
|
|
294
|
-
{
|
|
299
|
+
(
|
|
300
|
+
await compiler({
|
|
295
301
|
tag: '*',
|
|
296
302
|
command: 'CMD',
|
|
297
303
|
attributes: [
|
|
304
|
+
// keep indentation
|
|
298
305
|
{
|
|
299
306
|
type: 'LITERAL',
|
|
300
|
-
value: 'Tere tere!'
|
|
307
|
+
value: 'Tere\x00 tere!',
|
|
308
|
+
isLiteral8: true
|
|
301
309
|
},
|
|
302
|
-
|
|
303
|
-
type: 'LITERAL',
|
|
304
|
-
value: 'Vana kere'
|
|
305
|
-
}
|
|
310
|
+
'Vana kere'
|
|
306
311
|
]
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
|
|
312
|
+
})
|
|
313
|
+
).toString(),
|
|
314
|
+
'* CMD ~{11}\r\nTere\x00 tere! "Vana kere"'
|
|
315
|
+
)
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
module.exports['IMAP Compiler: LITERAL array 1'] = test =>
|
|
319
|
+
asyncWrapper(test, async test =>
|
|
320
|
+
test.deepEqual(
|
|
321
|
+
(
|
|
322
|
+
await compiler(
|
|
323
|
+
{
|
|
324
|
+
tag: '*',
|
|
325
|
+
command: 'CMD',
|
|
326
|
+
attributes: [
|
|
327
|
+
{
|
|
328
|
+
type: 'LITERAL',
|
|
329
|
+
value: 'Tere tere!'
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
type: 'LITERAL',
|
|
333
|
+
value: 'Vana kere'
|
|
334
|
+
}
|
|
335
|
+
]
|
|
336
|
+
},
|
|
337
|
+
{ asArray: true }
|
|
338
|
+
)
|
|
339
|
+
).map(entry => entry.toString()),
|
|
310
340
|
['* CMD {10}\r\n', 'Tere tere! {9}\r\n', 'Vana kere']
|
|
311
341
|
)
|
|
312
342
|
);
|
|
@@ -314,24 +344,26 @@ module.exports['IMAP Compiler: LITERAL array 1'] = test =>
|
|
|
314
344
|
module.exports['IMAP Compiler: LITERAL array 2'] = test =>
|
|
315
345
|
asyncWrapper(test, async test =>
|
|
316
346
|
test.deepEqual(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
347
|
+
(
|
|
348
|
+
await compiler(
|
|
349
|
+
{
|
|
350
|
+
tag: '*',
|
|
351
|
+
command: 'CMD',
|
|
352
|
+
attributes: [
|
|
353
|
+
{
|
|
354
|
+
type: 'LITERAL',
|
|
355
|
+
value: 'Tere tere!'
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
type: 'LITERAL',
|
|
359
|
+
value: 'Vana kere'
|
|
360
|
+
},
|
|
361
|
+
'zzz'
|
|
362
|
+
]
|
|
363
|
+
},
|
|
364
|
+
{ asArray: true }
|
|
365
|
+
)
|
|
366
|
+
).map(entry => entry.toString()),
|
|
335
367
|
['* CMD {10}\r\n', 'Tere tere! {9}\r\n', 'Vana kere "zzz"']
|
|
336
368
|
)
|
|
337
369
|
);
|
|
@@ -339,24 +371,26 @@ module.exports['IMAP Compiler: LITERAL array 2'] = test =>
|
|
|
339
371
|
module.exports['IMAP Compiler: LITERALPLUS array'] = test =>
|
|
340
372
|
asyncWrapper(test, async test =>
|
|
341
373
|
test.deepEqual(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
374
|
+
(
|
|
375
|
+
await compiler(
|
|
376
|
+
{
|
|
377
|
+
tag: '*',
|
|
378
|
+
command: 'CMD',
|
|
379
|
+
attributes: [
|
|
380
|
+
{
|
|
381
|
+
type: 'LITERAL',
|
|
382
|
+
value: 'Tere tere!'
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
type: 'LITERAL',
|
|
386
|
+
value: 'Vana kere'
|
|
387
|
+
},
|
|
388
|
+
'zzz'
|
|
389
|
+
]
|
|
390
|
+
},
|
|
391
|
+
{ asArray: true, literalPlus: true }
|
|
392
|
+
)
|
|
393
|
+
).map(entry => entry.toString()),
|
|
360
394
|
['* CMD {10+}\r\nTere tere! {9+}\r\nVana kere "zzz"']
|
|
361
395
|
)
|
|
362
396
|
);
|
|
@@ -364,21 +398,23 @@ module.exports['IMAP Compiler: LITERALPLUS array'] = test =>
|
|
|
364
398
|
module.exports['IMAP Compiler: LITERAL array without tag/command'] = test =>
|
|
365
399
|
asyncWrapper(test, async test =>
|
|
366
400
|
test.deepEqual(
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
401
|
+
(
|
|
402
|
+
await compiler(
|
|
403
|
+
{
|
|
404
|
+
attributes: [
|
|
405
|
+
{
|
|
406
|
+
type: 'LITERAL',
|
|
407
|
+
value: 'Tere tere!'
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
type: 'LITERAL',
|
|
411
|
+
value: 'Vana kere'
|
|
412
|
+
}
|
|
413
|
+
]
|
|
414
|
+
},
|
|
415
|
+
{ asArray: true }
|
|
416
|
+
)
|
|
417
|
+
).map(entry => entry.toString()),
|
|
382
418
|
['{10}\r\n', 'Tere tere! {9}\r\n', 'Vana kere']
|
|
383
419
|
)
|
|
384
420
|
);
|
|
@@ -386,20 +422,22 @@ module.exports['IMAP Compiler: LITERAL array without tag/command'] = test =>
|
|
|
386
422
|
module.exports['IMAP Compiler: LITERAL byte length'] = test =>
|
|
387
423
|
asyncWrapper(test, async test =>
|
|
388
424
|
test.deepEqual(
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
425
|
+
(
|
|
426
|
+
await compiler(
|
|
427
|
+
{
|
|
428
|
+
tag: '*',
|
|
429
|
+
command: 'CMD',
|
|
430
|
+
attributes: [
|
|
431
|
+
{
|
|
432
|
+
type: 'LITERAL',
|
|
433
|
+
value: 'Tere tere!'
|
|
434
|
+
},
|
|
435
|
+
'Vana kere'
|
|
436
|
+
]
|
|
437
|
+
},
|
|
438
|
+
{ asArray: false, isLogging: true }
|
|
439
|
+
)
|
|
440
|
+
).toString(),
|
|
403
441
|
'* CMD "(* 10B literal *)" "Vana kere"'
|
|
404
442
|
)
|
|
405
443
|
);
|