imapflow 1.6.4 → 1.6.5
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/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +7 -0
- package/lib/commands/compress.js +29 -18
- package/lib/handler/imap-compiler.js +91 -60
- package/lib/handler/imap-parser.js +7 -0
- package/lib/handler/imap-stream.js +22 -10
- package/lib/imap-flow.js +78 -33
- package/lib/search-compiler.js +24 -16
- package/package.json +1 -1
- package/test/commands-integration-test.js +97 -5
- package/test/idle-polling-test.js +81 -0
- package/test/imap-compiler-test.js +74 -4
- package/test/imap-flow-internals-test.js +134 -0
- package/test/imap-flow-secure-test.js +133 -116
- package/test/imap-flow-server-test.js +126 -0
- package/test/imap-parser-test.js +25 -0
- package/test/imap-stream-edge-cases-test.js +27 -3
- package/test/integration/rev2-live-test.js +30 -0
- package/test/search-compiler-test.js +90 -3
|
@@ -87,13 +87,49 @@ module.exports['Search Compiler: SEQ with number'] = test => {
|
|
|
87
87
|
test.done();
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
module.exports['Search Compiler: SEQ
|
|
90
|
+
module.exports['Search Compiler: SEQ passes invalid values through to the compiler guard'] = test => {
|
|
91
91
|
let connection = createMockConnection();
|
|
92
92
|
|
|
93
|
-
//
|
|
93
|
+
// An invalid sequence string used to be dropped silently here, which turned the
|
|
94
|
+
// filter into an unrestricted search matching every message. It is now emitted as
|
|
95
|
+
// a SEQUENCE token so the IMAP compiler rejects it with a coded error instead.
|
|
94
96
|
let compiled = searchCompiler(connection, { seq: '1 2 3' });
|
|
95
|
-
|
|
97
|
+
let seqAttr = compiled.find(a => a.type === 'SEQUENCE');
|
|
98
|
+
test.ok(seqAttr, 'the sequence value must not be dropped');
|
|
99
|
+
test.equal(seqAttr.value, '1 2 3');
|
|
100
|
+
|
|
101
|
+
// Junk values pass through too, so they fail loudly at the compiler instead of
|
|
102
|
+
// silently widening the search
|
|
103
|
+
let junk = searchCompiler(connection, { seq: {} });
|
|
104
|
+
test.ok(
|
|
105
|
+
junk.find(a => a.type === 'SEQUENCE'),
|
|
106
|
+
'a junk value must not be dropped'
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Zero is not a valid IMAP sequence number but it is a valid filter value,
|
|
110
|
+
// so it must reach the compiler guard rather than be dropped as falsy
|
|
111
|
+
let zero = searchCompiler(connection, { seq: 0 });
|
|
112
|
+
test.equal(zero.find(a => a.type === 'SEQUENCE').value, '0', 'zero must not be dropped');
|
|
113
|
+
|
|
114
|
+
test.done();
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
module.exports['Search Compiler: SEQ array compiles to a single comma-joined set'] = test => {
|
|
118
|
+
let connection = createMockConnection();
|
|
119
|
+
let compiled = searchCompiler(connection, { seq: [1, 3] });
|
|
120
|
+
|
|
121
|
+
let seqAttr = compiled.find(a => a.type === 'SEQUENCE');
|
|
122
|
+
test.ok(seqAttr, 'array must produce a sequence set');
|
|
123
|
+
test.equal(seqAttr.value, '1,3');
|
|
124
|
+
test.done();
|
|
125
|
+
};
|
|
96
126
|
|
|
127
|
+
module.exports['Search Compiler: SEQ empty string compiles to nothing'] = test => {
|
|
128
|
+
let connection = createMockConnection();
|
|
129
|
+
let compiled = searchCompiler(connection, { seq: '' });
|
|
130
|
+
|
|
131
|
+
test.ok(!compiled.find(a => a.type === 'SEQUENCE'), 'an empty set adds no SEQUENCE attribute');
|
|
132
|
+
test.equal(compiled.length, 0);
|
|
97
133
|
test.done();
|
|
98
134
|
};
|
|
99
135
|
|
|
@@ -366,6 +402,30 @@ module.exports['Search Compiler: UID with number'] = test => {
|
|
|
366
402
|
test.done();
|
|
367
403
|
};
|
|
368
404
|
|
|
405
|
+
module.exports['Search Compiler: UID array compiles to a single comma-joined set'] = test => {
|
|
406
|
+
let connection = createMockConnection();
|
|
407
|
+
let compiled = searchCompiler(connection, { uid: [5, 7, 9] });
|
|
408
|
+
|
|
409
|
+
// Separate tokens ("UID 5 7 9") would be parsed by the server as extra
|
|
410
|
+
// sequence-number search keys ANDed to the query - the array means the set {5,7,9}
|
|
411
|
+
test.ok(hasAttr(compiled, 'UID'));
|
|
412
|
+
let uidValueAttr = compiled.find(a => a.value === '5,7,9');
|
|
413
|
+
test.ok(uidValueAttr, 'array must be joined into one sequence set');
|
|
414
|
+
test.equal(uidValueAttr.type, 'SEQUENCE');
|
|
415
|
+
test.done();
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
module.exports['Search Compiler: UID accepts the SEARCHRES $ marker'] = test => {
|
|
419
|
+
let connection = createMockConnection();
|
|
420
|
+
let compiled = searchCompiler(connection, { uid: '$' });
|
|
421
|
+
|
|
422
|
+
test.ok(hasAttr(compiled, 'UID'));
|
|
423
|
+
let uidValueAttr = compiled.find(a => a.value === '$');
|
|
424
|
+
test.ok(uidValueAttr, 'the saved-result marker must pass through');
|
|
425
|
+
test.equal(uidValueAttr.type, 'SEQUENCE');
|
|
426
|
+
test.done();
|
|
427
|
+
};
|
|
428
|
+
|
|
369
429
|
// ============================================
|
|
370
430
|
// EMAILID / THREADID tests
|
|
371
431
|
// ============================================
|
|
@@ -488,6 +548,19 @@ module.exports['Search Compiler: LABELS not compiles to -label: via X-GM-RAW'] =
|
|
|
488
548
|
test.done();
|
|
489
549
|
};
|
|
490
550
|
|
|
551
|
+
module.exports['Search Compiler: LABELS with a non-object value is ignored'] = test => {
|
|
552
|
+
let connection = createMockConnection();
|
|
553
|
+
|
|
554
|
+
// Neither a falsy value nor a plain string is a { has, not } filter - both
|
|
555
|
+
// must compile to nothing even without the Gmail extension
|
|
556
|
+
let compiledNull = searchCompiler(connection, { labels: null });
|
|
557
|
+
test.equal(compiledNull.length, 0);
|
|
558
|
+
|
|
559
|
+
let compiledString = searchCompiler(connection, { labels: 'Horizon' });
|
|
560
|
+
test.equal(compiledString.length, 0);
|
|
561
|
+
test.done();
|
|
562
|
+
};
|
|
563
|
+
|
|
491
564
|
module.exports['Search Compiler: LABELS has and not combined'] = test => {
|
|
492
565
|
let connection = createMockConnection({
|
|
493
566
|
capabilities: [['X-GM-EXT-1', true]]
|
|
@@ -991,6 +1064,20 @@ module.exports['Search Compiler: non-ASCII GMRAW adds CHARSET UTF-8'] = test =>
|
|
|
991
1064
|
test.done();
|
|
992
1065
|
};
|
|
993
1066
|
|
|
1067
|
+
module.exports['Search Compiler: non-ASCII LABELS adds CHARSET UTF-8'] = test => {
|
|
1068
|
+
let connection = createMockConnection({
|
|
1069
|
+
capabilities: [['X-GM-EXT-1', true]],
|
|
1070
|
+
enabled: new Set()
|
|
1071
|
+
});
|
|
1072
|
+
// The label filter compiles into an X-GM-RAW query, and a non-ASCII label name
|
|
1073
|
+
// must mark the compiled query as Unicode the same way a direct gmraw value does
|
|
1074
|
+
let compiled = searchCompiler(connection, { labels: { has: ['Tähtis'] } });
|
|
1075
|
+
test.ok(hasAttr(compiled, 'CHARSET'));
|
|
1076
|
+
test.ok(hasAttr(compiled, 'X-GM-RAW'));
|
|
1077
|
+
test.ok(hasAttr(compiled, 'label:Tähtis'));
|
|
1078
|
+
test.done();
|
|
1079
|
+
};
|
|
1080
|
+
|
|
994
1081
|
// ============================================
|
|
995
1082
|
// Complex query tests
|
|
996
1083
|
// ============================================
|