emailengine-app 2.61.1 → 2.61.2

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.
Files changed (136) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/data/google-crawlers.json +1 -1
  3. package/lib/account/account-state.js +248 -0
  4. package/lib/account.js +17 -178
  5. package/lib/api-routes/account-routes.js +1006 -0
  6. package/lib/api-routes/message-routes.js +1377 -0
  7. package/lib/consts.js +12 -2
  8. package/lib/email-client/base-client.js +282 -771
  9. package/lib/email-client/gmail/gmail-api.js +243 -0
  10. package/lib/email-client/gmail-client.js +145 -53
  11. package/lib/email-client/imap/mailbox.js +24 -698
  12. package/lib/email-client/imap/sync-operations.js +812 -0
  13. package/lib/email-client/imap-client.js +1 -1
  14. package/lib/email-client/message-builder.js +566 -0
  15. package/lib/email-client/notification-handler.js +314 -0
  16. package/lib/email-client/outlook/graph-api.js +326 -0
  17. package/lib/email-client/outlook-client.js +159 -113
  18. package/lib/email-client/smtp-pool-manager.js +196 -0
  19. package/lib/imapproxy/imap-server.js +3 -12
  20. package/lib/oauth/gmail.js +4 -4
  21. package/lib/oauth/mail-ru.js +30 -5
  22. package/lib/oauth/outlook.js +57 -3
  23. package/lib/oauth/pubsub/google.js +30 -11
  24. package/lib/oauth/scope-checker.js +202 -0
  25. package/lib/oauth2-apps.js +8 -4
  26. package/lib/redis-operations.js +484 -0
  27. package/lib/routes-ui.js +283 -2582
  28. package/lib/tools.js +4 -196
  29. package/lib/ui-routes/account-routes.js +1931 -0
  30. package/lib/ui-routes/admin-config-routes.js +1233 -0
  31. package/lib/ui-routes/admin-entities-routes.js +2367 -0
  32. package/lib/ui-routes/oauth-routes.js +992 -0
  33. package/lib/utils/network.js +237 -0
  34. package/package.json +9 -9
  35. package/sbom.json +1 -1
  36. package/static/js/app.js +5 -5
  37. package/static/licenses.html +78 -18
  38. package/translations/de.mo +0 -0
  39. package/translations/de.po +85 -82
  40. package/translations/en.mo +0 -0
  41. package/translations/en.po +63 -71
  42. package/translations/et.mo +0 -0
  43. package/translations/et.po +84 -82
  44. package/translations/fr.mo +0 -0
  45. package/translations/fr.po +85 -82
  46. package/translations/ja.mo +0 -0
  47. package/translations/ja.po +84 -82
  48. package/translations/messages.pot +74 -87
  49. package/translations/nl.mo +0 -0
  50. package/translations/nl.po +86 -82
  51. package/translations/pl.mo +0 -0
  52. package/translations/pl.po +84 -82
  53. package/views/account/security.hbs +4 -4
  54. package/views/accounts/account.hbs +13 -13
  55. package/views/accounts/register/imap-server.hbs +12 -12
  56. package/views/config/document-store/pre-processing/index.hbs +4 -2
  57. package/views/config/oauth/app.hbs +6 -7
  58. package/views/config/oauth/index.hbs +2 -2
  59. package/views/config/service.hbs +3 -4
  60. package/views/dashboard.hbs +5 -7
  61. package/views/error.hbs +22 -7
  62. package/views/gateways/gateway.hbs +2 -2
  63. package/views/partials/add_account_modal.hbs +7 -10
  64. package/views/partials/document_store_header.hbs +1 -1
  65. package/views/partials/editor_scope_info.hbs +0 -1
  66. package/views/partials/oauth_config_header.hbs +1 -1
  67. package/views/partials/side_menu.hbs +3 -3
  68. package/views/partials/webhook_form.hbs +2 -2
  69. package/views/templates/index.hbs +1 -1
  70. package/views/templates/template.hbs +8 -8
  71. package/views/tokens/index.hbs +6 -6
  72. package/views/tokens/new.hbs +1 -1
  73. package/views/webhooks/index.hbs +4 -4
  74. package/views/webhooks/webhook.hbs +7 -7
  75. package/workers/api.js +148 -2436
  76. package/workers/smtp.js +2 -1
  77. package/lib/imapproxy/imap-core/test/client.js +0 -46
  78. package/lib/imapproxy/imap-core/test/fixtures/append.eml +0 -1196
  79. package/lib/imapproxy/imap-core/test/fixtures/chunks.js +0 -44
  80. package/lib/imapproxy/imap-core/test/fixtures/fix1.eml +0 -6
  81. package/lib/imapproxy/imap-core/test/fixtures/fix2.eml +0 -599
  82. package/lib/imapproxy/imap-core/test/fixtures/fix3.eml +0 -32
  83. package/lib/imapproxy/imap-core/test/fixtures/fix4.eml +0 -6
  84. package/lib/imapproxy/imap-core/test/fixtures/mimetorture.eml +0 -599
  85. package/lib/imapproxy/imap-core/test/fixtures/mimetorture.js +0 -2740
  86. package/lib/imapproxy/imap-core/test/fixtures/mimetorture.json +0 -1411
  87. package/lib/imapproxy/imap-core/test/fixtures/mimetree.js +0 -85
  88. package/lib/imapproxy/imap-core/test/fixtures/nodemailer.eml +0 -582
  89. package/lib/imapproxy/imap-core/test/fixtures/ryan_finnie_mime_torture.eml +0 -599
  90. package/lib/imapproxy/imap-core/test/fixtures/simple.eml +0 -42
  91. package/lib/imapproxy/imap-core/test/fixtures/simple.json +0 -164
  92. package/lib/imapproxy/imap-core/test/imap-compile-stream-test.js +0 -671
  93. package/lib/imapproxy/imap-core/test/imap-compiler-test.js +0 -272
  94. package/lib/imapproxy/imap-core/test/imap-indexer-test.js +0 -236
  95. package/lib/imapproxy/imap-core/test/imap-parser-test.js +0 -922
  96. package/lib/imapproxy/imap-core/test/memory-notifier.js +0 -129
  97. package/lib/imapproxy/imap-core/test/prepare.sh +0 -74
  98. package/lib/imapproxy/imap-core/test/protocol-test.js +0 -1756
  99. package/lib/imapproxy/imap-core/test/search-test.js +0 -1356
  100. package/lib/imapproxy/imap-core/test/test-client.js +0 -152
  101. package/lib/imapproxy/imap-core/test/test-server.js +0 -623
  102. package/lib/imapproxy/imap-core/test/tools-test.js +0 -22
  103. package/test/api-test.js +0 -899
  104. package/test/autoreply-test.js +0 -327
  105. package/test/bounce-test.js +0 -151
  106. package/test/complaint-test.js +0 -256
  107. package/test/fixtures/autoreply/LICENSE +0 -27
  108. package/test/fixtures/autoreply/rfc3834-01.eml +0 -23
  109. package/test/fixtures/autoreply/rfc3834-02.eml +0 -24
  110. package/test/fixtures/autoreply/rfc3834-03.eml +0 -26
  111. package/test/fixtures/autoreply/rfc3834-04.eml +0 -48
  112. package/test/fixtures/autoreply/rfc3834-05.eml +0 -19
  113. package/test/fixtures/autoreply/rfc3834-06.eml +0 -59
  114. package/test/fixtures/bounces/163.eml +0 -2521
  115. package/test/fixtures/bounces/fastmail.eml +0 -242
  116. package/test/fixtures/bounces/gmail.eml +0 -252
  117. package/test/fixtures/bounces/hotmail.eml +0 -655
  118. package/test/fixtures/bounces/mailru.eml +0 -121
  119. package/test/fixtures/bounces/outlook.eml +0 -1107
  120. package/test/fixtures/bounces/postfix.eml +0 -101
  121. package/test/fixtures/bounces/rambler.eml +0 -116
  122. package/test/fixtures/bounces/workmail.eml +0 -142
  123. package/test/fixtures/bounces/yahoo.eml +0 -139
  124. package/test/fixtures/bounces/zoho.eml +0 -83
  125. package/test/fixtures/bounces/zonemta.eml +0 -100
  126. package/test/fixtures/complaints/LICENSE +0 -27
  127. package/test/fixtures/complaints/amazonses.eml +0 -72
  128. package/test/fixtures/complaints/dmarc.eml +0 -59
  129. package/test/fixtures/complaints/hotmail.eml +0 -49
  130. package/test/fixtures/complaints/optout.eml +0 -40
  131. package/test/fixtures/complaints/standard-arf.eml +0 -68
  132. package/test/fixtures/complaints/yahoo.eml +0 -68
  133. package/test/oauth2-apps-test.js +0 -301
  134. package/test/sendonly-test.js +0 -160
  135. package/test/test-config.js +0 -34
  136. package/test/webhooks-server.js +0 -39
@@ -1,922 +0,0 @@
1
- /*eslint no-unused-expressions: 0, prefer-arrow-callback: 0 */
2
-
3
- 'use strict';
4
-
5
- const chai = require('chai');
6
- const imapHandler = require('../lib/handler/imap-handler');
7
- const mimetorture = require('./fixtures/mimetorture');
8
-
9
- const expect = chai.expect;
10
- chai.config.includeStack = true;
11
-
12
- describe('IMAP Command Parser', function() {
13
- describe('get tag', function() {
14
- it('should succeed', function() {
15
- expect(imapHandler.parser('TAG1 CMD').tag).to.equal('TAG1');
16
- });
17
-
18
- it('should fail for unexpected WS', function() {
19
- expect(function() {
20
- imapHandler.parser(' TAG CMD');
21
- }).to.throw(Error);
22
- });
23
-
24
- it('should * OK ', function() {
25
- expect(function() {
26
- imapHandler.parser(' TAG CMD');
27
- }).to.throw(Error);
28
- });
29
-
30
- it('should + OK ', function() {
31
- expect(imapHandler.parser('+ TAG CMD').tag).to.equal('+');
32
- });
33
-
34
- it('should allow untagged', function() {
35
- expect(function() {
36
- imapHandler.parser('* CMD');
37
- }).to.not.throw(Error);
38
- });
39
-
40
- it('should fail for empty tag', function() {
41
- expect(function() {
42
- imapHandler.parser('');
43
- }).to.throw(Error);
44
- });
45
-
46
- it('should fail for unexpected end', function() {
47
- expect(function() {
48
- imapHandler.parser('TAG1');
49
- }).to.throw(Error);
50
- });
51
-
52
- it('should fail for invalid char', function() {
53
- expect(function() {
54
- imapHandler.parser('TAG"1 CMD');
55
- }).to.throw(Error);
56
- });
57
- });
58
-
59
- describe('get arguments', function() {
60
- it('should allow trailing whitespace and empty arguments', function() {
61
- expect(function() {
62
- imapHandler.parser('* SEARCH ');
63
- }).to.not.throw(Error);
64
- });
65
- });
66
-
67
- describe('get command', function() {
68
- it('should succeed', function() {
69
- expect(imapHandler.parser('TAG1 CMD').command).to.equal('CMD');
70
- });
71
-
72
- it('should work for multi word command', function() {
73
- expect(imapHandler.parser('TAG1 UID FETCH').command).to.equal('UID FETCH');
74
- });
75
-
76
- it('should fail for unexpected WS', function() {
77
- expect(function() {
78
- imapHandler.parser('TAG1 CMD');
79
- }).to.throw(Error);
80
- });
81
-
82
- it('should fail for empty command', function() {
83
- expect(function() {
84
- imapHandler.parser('TAG1 ');
85
- }).to.throw(Error);
86
- });
87
-
88
- it('should fail for invalid char', function() {
89
- expect(function() {
90
- imapHandler.parser('TAG1 CM=D');
91
- }).to.throw(Error);
92
- });
93
- });
94
-
95
- describe('get attribute', function() {
96
- it('should succeed', function() {
97
- expect(imapHandler.parser('TAG1 CMD FED').attributes).to.deep.equal([
98
- {
99
- type: 'ATOM',
100
- value: 'FED'
101
- }
102
- ]);
103
- });
104
-
105
- it('should succeed for single whitespace between values', function() {
106
- expect(imapHandler.parser('TAG1 CMD FED TED').attributes).to.deep.equal([
107
- {
108
- type: 'ATOM',
109
- value: 'FED'
110
- },
111
- {
112
- type: 'ATOM',
113
- value: 'TED'
114
- }
115
- ]);
116
- });
117
-
118
- it('should succeed for ATOM', function() {
119
- expect(imapHandler.parser('TAG1 CMD ABCDE').attributes).to.deep.equal([
120
- {
121
- type: 'ATOM',
122
- value: 'ABCDE'
123
- }
124
- ]);
125
-
126
- expect(imapHandler.parser('TAG1 CMD ABCDE DEFGH').attributes).to.deep.equal([
127
- {
128
- type: 'ATOM',
129
- value: 'ABCDE'
130
- },
131
- {
132
- type: 'ATOM',
133
- value: 'DEFGH'
134
- }
135
- ]);
136
-
137
- expect(imapHandler.parser('TAG1 CMD %').attributes).to.deep.equal([
138
- {
139
- type: 'ATOM',
140
- value: '%'
141
- }
142
- ]);
143
-
144
- expect(imapHandler.parser('TAG1 CMD \\*').attributes).to.deep.equal([
145
- {
146
- type: 'ATOM',
147
- value: '\\*'
148
- }
149
- ]);
150
-
151
- expect(imapHandler.parser('12.82 STATUS [Gmail].Trash (UIDNEXT UNSEEN HIGHESTMODSEQ)').attributes).to.deep.equal([
152
- // keep indentation
153
- {
154
- type: 'ATOM',
155
- value: '[Gmail].Trash'
156
- },
157
- [
158
- {
159
- type: 'ATOM',
160
- value: 'UIDNEXT'
161
- },
162
- {
163
- type: 'ATOM',
164
- value: 'UNSEEN'
165
- },
166
- {
167
- type: 'ATOM',
168
- value: 'HIGHESTMODSEQ'
169
- }
170
- ]
171
- ]);
172
- });
173
-
174
- it('should not succeed for ATOM', function() {
175
- expect(function() {
176
- imapHandler.parser('TAG1 CMD \\*a');
177
- }).to.throw(Error);
178
- });
179
- });
180
-
181
- describe('get string', function() {
182
- it('should succeed', function() {
183
- expect(imapHandler.parser('TAG1 CMD "ABCDE"').attributes).to.deep.equal([
184
- {
185
- type: 'STRING',
186
- value: 'ABCDE'
187
- }
188
- ]);
189
-
190
- expect(imapHandler.parser('TAG1 CMD "ABCDE" "DEFGH"').attributes).to.deep.equal([
191
- {
192
- type: 'STRING',
193
- value: 'ABCDE'
194
- },
195
- {
196
- type: 'STRING',
197
- value: 'DEFGH'
198
- }
199
- ]);
200
- });
201
-
202
- it('should not explode on invalid char', function() {
203
- expect(imapHandler.parser('* 1 FETCH (BODY[] "\xc2")').attributes).to.deep.equal([
204
- // keep indentation
205
- {
206
- type: 'ATOM',
207
- value: 'FETCH'
208
- },
209
- [
210
- {
211
- type: 'ATOM',
212
- value: 'BODY',
213
- section: []
214
- },
215
- {
216
- type: 'STRING',
217
- value: '\xc2'
218
- }
219
- ]
220
- ]);
221
- });
222
- });
223
-
224
- describe('get list', function() {
225
- it('should succeed', function() {
226
- expect(imapHandler.parser('TAG1 CMD (1234)').attributes).to.deep.equal([
227
- [
228
- {
229
- type: 'ATOM',
230
- value: '1234'
231
- }
232
- ]
233
- ]);
234
- expect(imapHandler.parser('TAG1 CMD (1234 TERE)').attributes).to.deep.equal([
235
- [
236
- {
237
- type: 'ATOM',
238
- value: '1234'
239
- },
240
- {
241
- type: 'ATOM',
242
- value: 'TERE'
243
- }
244
- ]
245
- ]);
246
- expect(imapHandler.parser('TAG1 CMD (1234)(TERE)').attributes).to.deep.equal([
247
- [
248
- {
249
- type: 'ATOM',
250
- value: '1234'
251
- }
252
- ],
253
- [
254
- {
255
- type: 'ATOM',
256
- value: 'TERE'
257
- }
258
- ]
259
- ]);
260
- expect(imapHandler.parser('TAG1 CMD ( 1234)').attributes).to.deep.equal([
261
- [
262
- {
263
- type: 'ATOM',
264
- value: '1234'
265
- }
266
- ]
267
- ]);
268
- // Trailing whitespace in a BODYSTRUCTURE atom list has been
269
- // observed on yahoo.co.jp's
270
- expect(imapHandler.parser('TAG1 CMD (1234 )').attributes).to.deep.equal([
271
- [
272
- {
273
- type: 'ATOM',
274
- value: '1234'
275
- }
276
- ]
277
- ]);
278
- expect(imapHandler.parser('TAG1 CMD (1234) ').attributes).to.deep.equal([
279
- [
280
- {
281
- type: 'ATOM',
282
- value: '1234'
283
- }
284
- ]
285
- ]);
286
- });
287
- });
288
-
289
- describe('nested list', function() {
290
- it('should succeed', function() {
291
- expect(imapHandler.parser('TAG1 CMD (((TERE)) VANA)').attributes).to.deep.equal([
292
- [
293
- [
294
- [
295
- {
296
- type: 'ATOM',
297
- value: 'TERE'
298
- }
299
- ]
300
- ],
301
- {
302
- type: 'ATOM',
303
- value: 'VANA'
304
- }
305
- ]
306
- ]);
307
- expect(imapHandler.parser('TAG1 CMD (( (TERE)) VANA)').attributes).to.deep.equal([
308
- [
309
- [
310
- [
311
- {
312
- type: 'ATOM',
313
- value: 'TERE'
314
- }
315
- ]
316
- ],
317
- {
318
- type: 'ATOM',
319
- value: 'VANA'
320
- }
321
- ]
322
- ]);
323
- expect(imapHandler.parser('TAG1 CMD (((TERE) ) VANA)').attributes).to.deep.equal([
324
- [
325
- [
326
- [
327
- {
328
- type: 'ATOM',
329
- value: 'TERE'
330
- }
331
- ]
332
- ],
333
- {
334
- type: 'ATOM',
335
- value: 'VANA'
336
- }
337
- ]
338
- ]);
339
- });
340
- });
341
-
342
- describe('get literal', function() {
343
- it('should succeed', function() {
344
- expect(imapHandler.parser('TAG1 CMD {4}\r\n', { literals: [Buffer.from('abcd')] }).attributes).to.deep.equal([
345
- {
346
- type: 'LITERAL',
347
- value: 'abcd'
348
- }
349
- ]);
350
-
351
- expect(imapHandler.parser('TAG1 CMD {4}\r\n {4}\r\n', { literals: [Buffer.from('abcd'), Buffer.from('kere')] }).attributes).to.deep.equal([
352
- {
353
- type: 'LITERAL',
354
- value: 'abcd'
355
- },
356
- {
357
- type: 'LITERAL',
358
- value: 'kere'
359
- }
360
- ]);
361
-
362
- expect(imapHandler.parser('TAG1 CMD ({4}\r\n {4}\r\n)', { literals: [Buffer.from('abcd'), Buffer.from('kere')] }).attributes).to.deep.equal([
363
- [
364
- {
365
- type: 'LITERAL',
366
- value: 'abcd'
367
- },
368
- {
369
- type: 'LITERAL',
370
- value: 'kere'
371
- }
372
- ]
373
- ]);
374
- });
375
-
376
- it('should fail', function() {
377
- expect(function() {
378
- imapHandler.parser('TAG1 CMD {4}\r\n{4} \r\n', { literals: [Buffer.from('abcd'), Buffer.from('kere')] });
379
- }).to.throw(Error);
380
- });
381
-
382
- it('should allow zero length literal in the end of a list', function() {
383
- expect(imapHandler.parser('TAG1 CMD ({0}\r\n)').attributes).to.deep.equal([
384
- [
385
- {
386
- type: 'LITERAL',
387
- value: ''
388
- }
389
- ]
390
- ]);
391
- });
392
- });
393
-
394
- describe('ATOM Section', function() {
395
- it('should succeed', function() {
396
- expect(imapHandler.parser('TAG1 CMD BODY[]').attributes).to.deep.equal([
397
- {
398
- type: 'ATOM',
399
- value: 'BODY',
400
- section: []
401
- }
402
- ]);
403
- expect(imapHandler.parser('TAG1 CMD BODY[(KERE)]').attributes).to.deep.equal([
404
- {
405
- type: 'ATOM',
406
- value: 'BODY',
407
- section: [
408
- [
409
- {
410
- type: 'ATOM',
411
- value: 'KERE'
412
- }
413
- ]
414
- ]
415
- }
416
- ]);
417
- });
418
- it('will not fail due to trailing whitespace', function() {
419
- // We intentionally have trailing whitespace in the section here
420
- // because we altered the parser to handle this when we made it
421
- // legal for lists and it makes sense to accordingly test it.
422
- // However, we have no recorded incidences of this happening in
423
- // reality (unlike for lists).
424
- expect(imapHandler.parser('TAG1 CMD BODY[HEADER.FIELDS (Subject From) ]').attributes).to.deep.equal([
425
- {
426
- type: 'ATOM',
427
- value: 'BODY',
428
- section: [
429
- // keep indentation
430
- {
431
- type: 'ATOM',
432
- value: 'HEADER.FIELDS'
433
- },
434
- [
435
- {
436
- type: 'ATOM',
437
- value: 'Subject'
438
- },
439
- {
440
- type: 'ATOM',
441
- value: 'From'
442
- }
443
- ]
444
- ]
445
- }
446
- ]);
447
- });
448
- it('should fail where default BODY and BODY.PEEK are allowed to have sections', function() {});
449
- expect(function() {
450
- imapHandler.parser('TAG1 CMD KODY[]');
451
- }).to.throw(Error);
452
- });
453
-
454
- describe('Human readable', function() {
455
- it('should succeed', function() {
456
- expect(imapHandler.parser('* OK [CAPABILITY IDLE] Hello world!')).to.deep.equal({
457
- command: 'OK',
458
- tag: '*',
459
- attributes: [
460
- {
461
- section: [
462
- {
463
- type: 'ATOM',
464
- value: 'CAPABILITY'
465
- },
466
- {
467
- type: 'ATOM',
468
- value: 'IDLE'
469
- }
470
- ],
471
- type: 'ATOM',
472
- value: ''
473
- },
474
- {
475
- type: 'TEXT',
476
- value: 'Hello world!'
477
- }
478
- ]
479
- });
480
-
481
- expect(imapHandler.parser('* OK Hello world!')).to.deep.equal({
482
- command: 'OK',
483
- tag: '*',
484
- attributes: [
485
- {
486
- type: 'TEXT',
487
- value: 'Hello world!'
488
- }
489
- ]
490
- });
491
-
492
- expect(imapHandler.parser('* OK')).to.deep.equal({
493
- command: 'OK',
494
- tag: '*'
495
- });
496
-
497
- // USEATTR is from RFC6154; we are testing that just an ATOM
498
- // on its own will parse successfully here. (All of the
499
- // RFC5530 codes are also single atoms.)
500
- expect(imapHandler.parser('TAG1 OK [USEATTR] \\All not supported')).to.deep.equal({
501
- tag: 'TAG1',
502
- command: 'OK',
503
- attributes: [
504
- {
505
- type: 'ATOM',
506
- value: '',
507
- section: [
508
- {
509
- type: 'ATOM',
510
- value: 'USEATTR'
511
- }
512
- ]
513
- },
514
- {
515
- type: 'TEXT',
516
- value: '\\All not supported'
517
- }
518
- ]
519
- });
520
-
521
- // RFC5267 defines the NOUPDATE error. Including for quote /
522
- // string coverage.
523
- expect(imapHandler.parser('* NO [NOUPDATE "B02"] Too many contexts')).to.deep.equal({
524
- tag: '*',
525
- command: 'NO',
526
- attributes: [
527
- {
528
- type: 'ATOM',
529
- value: '',
530
- section: [
531
- {
532
- type: 'ATOM',
533
- value: 'NOUPDATE'
534
- },
535
- {
536
- type: 'STRING',
537
- value: 'B02'
538
- }
539
- ]
540
- },
541
- {
542
- type: 'TEXT',
543
- value: 'Too many contexts'
544
- }
545
- ]
546
- });
547
-
548
- // RFC5464 defines the METADATA response code; adding this to
549
- // ensure the transition for when '2199' hits ']' is handled
550
- // safely.
551
- expect(imapHandler.parser('TAG1 OK [METADATA LONGENTRIES 2199] GETMETADATA complete')).to.deep.equal({
552
- tag: 'TAG1',
553
- command: 'OK',
554
- attributes: [
555
- {
556
- type: 'ATOM',
557
- value: '',
558
- section: [
559
- {
560
- type: 'ATOM',
561
- value: 'METADATA'
562
- },
563
- {
564
- type: 'ATOM',
565
- value: 'LONGENTRIES'
566
- },
567
- {
568
- type: 'ATOM',
569
- value: '2199'
570
- }
571
- ]
572
- },
573
- {
574
- type: 'TEXT',
575
- value: 'GETMETADATA complete'
576
- }
577
- ]
578
- });
579
-
580
- // RFC4467 defines URLMECH. Included because of the example
581
- // third atom involves base64-encoding which is somewhat unusual
582
- expect(imapHandler.parser('TAG1 OK [URLMECH INTERNAL XSAMPLE=P34OKhO7VEkCbsiYY8rGEg==] done')).to.deep.equal({
583
- tag: 'TAG1',
584
- command: 'OK',
585
- attributes: [
586
- {
587
- type: 'ATOM',
588
- value: '',
589
- section: [
590
- {
591
- type: 'ATOM',
592
- value: 'URLMECH'
593
- },
594
- {
595
- type: 'ATOM',
596
- value: 'INTERNAL'
597
- },
598
- {
599
- type: 'ATOM',
600
- value: 'XSAMPLE=P34OKhO7VEkCbsiYY8rGEg=='
601
- }
602
- ]
603
- },
604
- {
605
- type: 'TEXT',
606
- value: 'done'
607
- }
608
- ]
609
- });
610
-
611
- // RFC2221 defines REFERRAL where the argument is an imapurl
612
- // (defined by RFC2192 which is obsoleted by RFC5092) which
613
- // is significantly more complicated than the rest of the IMAP
614
- // grammar and which was based on the RFC2060 grammar where
615
- // resp_text_code included:
616
- // atom [SPACE 1*<any TEXT_CHAR except ']'>]
617
- // So this is just a test case of our explicit special-casing
618
- // of REFERRAL.
619
- expect(imapHandler.parser('TAG1 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/] Remote Server')).to.deep.equal({
620
- tag: 'TAG1',
621
- command: 'NO',
622
- attributes: [
623
- {
624
- type: 'ATOM',
625
- value: '',
626
- section: [
627
- {
628
- type: 'ATOM',
629
- value: 'REFERRAL'
630
- },
631
- {
632
- type: 'ATOM',
633
- value: 'IMAP://user;AUTH=*@SERVER2/'
634
- }
635
- ]
636
- },
637
- {
638
- type: 'TEXT',
639
- value: 'Remote Server'
640
- }
641
- ]
642
- });
643
-
644
- // PERMANENTFLAGS is from RFC3501. Its syntax is also very
645
- // similar to BADCHARSET, except BADCHARSET has astrings
646
- // inside the list.
647
- expect(imapHandler.parser('* OK [PERMANENTFLAGS (de:hacking $label kt-evalution [css3-page] \\*)] Flags permitted.')).to.deep.equal({
648
- tag: '*',
649
- command: 'OK',
650
- attributes: [
651
- {
652
- type: 'ATOM',
653
- value: '',
654
- section: [
655
- // keep indentation
656
- {
657
- type: 'ATOM',
658
- value: 'PERMANENTFLAGS'
659
- },
660
- [
661
- {
662
- type: 'ATOM',
663
- value: 'de:hacking'
664
- },
665
- {
666
- type: 'ATOM',
667
- value: '$label'
668
- },
669
- {
670
- type: 'ATOM',
671
- value: 'kt-evalution'
672
- },
673
- {
674
- type: 'ATOM',
675
- value: '[css3-page]'
676
- },
677
- {
678
- type: 'ATOM',
679
- value: '\\*'
680
- }
681
- ]
682
- ]
683
- },
684
- {
685
- type: 'TEXT',
686
- value: 'Flags permitted.'
687
- }
688
- ]
689
- });
690
-
691
- // COPYUID is from RFC4315 and included the previously failing
692
- // parsing situation of a sequence terminated by ']' rather than
693
- // whitespace.
694
- expect(imapHandler.parser('TAG1 OK [COPYUID 4 1417051618:1417051620 1421730687:1421730689] COPY completed')).to.deep.equal({
695
- tag: 'TAG1',
696
- command: 'OK',
697
- attributes: [
698
- {
699
- type: 'ATOM',
700
- value: '',
701
- section: [
702
- {
703
- type: 'ATOM',
704
- value: 'COPYUID'
705
- },
706
- {
707
- type: 'ATOM',
708
- value: '4'
709
- },
710
- {
711
- type: 'SEQUENCE',
712
- value: '1417051618:1417051620'
713
- },
714
- {
715
- type: 'SEQUENCE',
716
- value: '1421730687:1421730689'
717
- }
718
- ]
719
- },
720
- {
721
- type: 'TEXT',
722
- value: 'COPY completed'
723
- }
724
- ]
725
- });
726
-
727
- // MODIFIED is from RFC4551 and is basically the same situation
728
- // as the COPYUID case, but in this case our example sequences
729
- // have commas in them. (Note that if there was no comma, the
730
- // '7,9' payload would end up an ATOM.)
731
- expect(imapHandler.parser('TAG1 OK [MODIFIED 7,9] Conditional STORE failed')).to.deep.equal({
732
- tag: 'TAG1',
733
- command: 'OK',
734
- attributes: [
735
- {
736
- type: 'ATOM',
737
- value: '',
738
- section: [
739
- {
740
- type: 'ATOM',
741
- value: 'MODIFIED'
742
- },
743
- {
744
- type: 'SEQUENCE',
745
- value: '7,9'
746
- }
747
- ]
748
- },
749
- {
750
- type: 'TEXT',
751
- value: 'Conditional STORE failed'
752
- }
753
- ]
754
- });
755
- });
756
- });
757
-
758
- describe('ATOM Partial', function() {
759
- it('should succeed', function() {
760
- expect(imapHandler.parser('TAG1 CMD BODY[]<0>').attributes).to.deep.equal([
761
- {
762
- type: 'ATOM',
763
- value: 'BODY',
764
- section: [],
765
- partial: [0]
766
- }
767
- ]);
768
- expect(imapHandler.parser('TAG1 CMD BODY[]<12.45>').attributes).to.deep.equal([
769
- {
770
- type: 'ATOM',
771
- value: 'BODY',
772
- section: [],
773
- partial: [12, 45]
774
- }
775
- ]);
776
- expect(imapHandler.parser('TAG1 CMD BODY[HEADER.FIELDS (Subject From)]<12.45>').attributes).to.deep.equal([
777
- {
778
- type: 'ATOM',
779
- value: 'BODY',
780
- section: [
781
- // keep indentation
782
- {
783
- type: 'ATOM',
784
- value: 'HEADER.FIELDS'
785
- },
786
- [
787
- {
788
- type: 'ATOM',
789
- value: 'Subject'
790
- },
791
- {
792
- type: 'ATOM',
793
- value: 'From'
794
- }
795
- ]
796
- ],
797
- partial: [12, 45]
798
- }
799
- ]);
800
- });
801
-
802
- it('should fail', function() {
803
- expect(function() {
804
- imapHandler.parser('TAG1 CMD KODY<0.123>');
805
- }).to.throw(Error);
806
-
807
- expect(function() {
808
- imapHandler.parser('TAG1 CMD BODY[]<01>');
809
- }).to.throw(Error);
810
-
811
- expect(function() {
812
- imapHandler.parser('TAG1 CMD BODY[]<0.01>');
813
- }).to.throw(Error);
814
-
815
- expect(function() {
816
- imapHandler.parser('TAG1 CMD BODY[]<0.1.>');
817
- }).to.throw(Error);
818
- });
819
- });
820
-
821
- describe('SEQUENCE', function() {
822
- it('should succeed', function() {
823
- expect(imapHandler.parser('TAG1 CMD *:4,5:7 TEST').attributes).to.deep.equal([
824
- {
825
- type: 'SEQUENCE',
826
- value: '*:4,5:7'
827
- },
828
- {
829
- type: 'ATOM',
830
- value: 'TEST'
831
- }
832
- ]);
833
-
834
- expect(imapHandler.parser('TAG1 CMD 1:* TEST').attributes).to.deep.equal([
835
- {
836
- type: 'SEQUENCE',
837
- value: '1:*'
838
- },
839
- {
840
- type: 'ATOM',
841
- value: 'TEST'
842
- }
843
- ]);
844
-
845
- expect(imapHandler.parser('TAG1 CMD *:4 TEST').attributes).to.deep.equal([
846
- {
847
- type: 'SEQUENCE',
848
- value: '*:4'
849
- },
850
- {
851
- type: 'ATOM',
852
- value: 'TEST'
853
- }
854
- ]);
855
- });
856
-
857
- it('should fail', function() {
858
- expect(function() {
859
- imapHandler.parser('TAG1 CMD *:4,5:');
860
- }).to.throw(Error);
861
-
862
- expect(function() {
863
- imapHandler.parser('TAG1 CMD *:4,5:TEST TEST');
864
- }).to.throw(Error);
865
-
866
- expect(function() {
867
- imapHandler.parser('TAG1 CMD *:4,5: TEST');
868
- }).to.throw(Error);
869
-
870
- expect(function() {
871
- imapHandler.parser('TAG1 CMD *4,5 TEST');
872
- }).to.throw(Error);
873
-
874
- expect(function() {
875
- imapHandler.parser('TAG1 CMD *,5 TEST');
876
- }).to.throw(Error);
877
-
878
- expect(function() {
879
- imapHandler.parser('TAG1 CMD 5,* TEST');
880
- }).to.throw(Error);
881
-
882
- expect(function() {
883
- imapHandler.parser('TAG1 CMD 5, TEST');
884
- }).to.throw(Error);
885
- });
886
- });
887
-
888
- describe('Escaped quotes', function() {
889
- it('should succeed', function() {
890
- expect(imapHandler.parser('* 331 FETCH (ENVELOPE ("=?ISO-8859-1?Q?\\"G=FCnter__Hammerl\\"?="))').attributes).to.deep.equal([
891
- // keep indentation
892
- {
893
- type: 'ATOM',
894
- value: 'FETCH'
895
- },
896
- [
897
- // keep indentation
898
- {
899
- type: 'ATOM',
900
- value: 'ENVELOPE'
901
- },
902
- [
903
- {
904
- type: 'STRING',
905
- value: '=?ISO-8859-1?Q?"G=FCnter__Hammerl"?='
906
- }
907
- ]
908
- ]
909
- ]);
910
- });
911
- });
912
-
913
- describe('MimeTorture', function() {
914
- it('should parse mimetorture input', function() {
915
- let parsed;
916
- expect(function() {
917
- parsed = imapHandler.parser(mimetorture.input);
918
- }).to.not.throw(Error);
919
- expect(parsed).to.deep.equal(mimetorture.output);
920
- });
921
- });
922
- });