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.
- package/CHANGELOG.md +9 -0
- package/data/google-crawlers.json +1 -1
- package/lib/account/account-state.js +248 -0
- package/lib/account.js +17 -178
- package/lib/api-routes/account-routes.js +1006 -0
- package/lib/api-routes/message-routes.js +1377 -0
- package/lib/consts.js +12 -2
- package/lib/email-client/base-client.js +282 -771
- package/lib/email-client/gmail/gmail-api.js +243 -0
- package/lib/email-client/gmail-client.js +145 -53
- package/lib/email-client/imap/mailbox.js +24 -698
- package/lib/email-client/imap/sync-operations.js +812 -0
- package/lib/email-client/imap-client.js +1 -1
- package/lib/email-client/message-builder.js +566 -0
- package/lib/email-client/notification-handler.js +314 -0
- package/lib/email-client/outlook/graph-api.js +326 -0
- package/lib/email-client/outlook-client.js +159 -113
- package/lib/email-client/smtp-pool-manager.js +196 -0
- package/lib/imapproxy/imap-server.js +3 -12
- package/lib/oauth/gmail.js +4 -4
- package/lib/oauth/mail-ru.js +30 -5
- package/lib/oauth/outlook.js +57 -3
- package/lib/oauth/pubsub/google.js +30 -11
- package/lib/oauth/scope-checker.js +202 -0
- package/lib/oauth2-apps.js +8 -4
- package/lib/redis-operations.js +484 -0
- package/lib/routes-ui.js +283 -2582
- package/lib/tools.js +4 -196
- package/lib/ui-routes/account-routes.js +1931 -0
- package/lib/ui-routes/admin-config-routes.js +1233 -0
- package/lib/ui-routes/admin-entities-routes.js +2367 -0
- package/lib/ui-routes/oauth-routes.js +992 -0
- package/lib/utils/network.js +237 -0
- package/package.json +9 -9
- package/sbom.json +1 -1
- package/static/js/app.js +5 -5
- package/static/licenses.html +78 -18
- package/translations/de.mo +0 -0
- package/translations/de.po +85 -82
- package/translations/en.mo +0 -0
- package/translations/en.po +63 -71
- package/translations/et.mo +0 -0
- package/translations/et.po +84 -82
- package/translations/fr.mo +0 -0
- package/translations/fr.po +85 -82
- package/translations/ja.mo +0 -0
- package/translations/ja.po +84 -82
- package/translations/messages.pot +74 -87
- package/translations/nl.mo +0 -0
- package/translations/nl.po +86 -82
- package/translations/pl.mo +0 -0
- package/translations/pl.po +84 -82
- package/views/account/security.hbs +4 -4
- package/views/accounts/account.hbs +13 -13
- package/views/accounts/register/imap-server.hbs +12 -12
- package/views/config/document-store/pre-processing/index.hbs +4 -2
- package/views/config/oauth/app.hbs +6 -7
- package/views/config/oauth/index.hbs +2 -2
- package/views/config/service.hbs +3 -4
- package/views/dashboard.hbs +5 -7
- package/views/error.hbs +22 -7
- package/views/gateways/gateway.hbs +2 -2
- package/views/partials/add_account_modal.hbs +7 -10
- package/views/partials/document_store_header.hbs +1 -1
- package/views/partials/editor_scope_info.hbs +0 -1
- package/views/partials/oauth_config_header.hbs +1 -1
- package/views/partials/side_menu.hbs +3 -3
- package/views/partials/webhook_form.hbs +2 -2
- package/views/templates/index.hbs +1 -1
- package/views/templates/template.hbs +8 -8
- package/views/tokens/index.hbs +6 -6
- package/views/tokens/new.hbs +1 -1
- package/views/webhooks/index.hbs +4 -4
- package/views/webhooks/webhook.hbs +7 -7
- package/workers/api.js +148 -2436
- package/workers/smtp.js +2 -1
- package/lib/imapproxy/imap-core/test/client.js +0 -46
- package/lib/imapproxy/imap-core/test/fixtures/append.eml +0 -1196
- package/lib/imapproxy/imap-core/test/fixtures/chunks.js +0 -44
- package/lib/imapproxy/imap-core/test/fixtures/fix1.eml +0 -6
- package/lib/imapproxy/imap-core/test/fixtures/fix2.eml +0 -599
- package/lib/imapproxy/imap-core/test/fixtures/fix3.eml +0 -32
- package/lib/imapproxy/imap-core/test/fixtures/fix4.eml +0 -6
- package/lib/imapproxy/imap-core/test/fixtures/mimetorture.eml +0 -599
- package/lib/imapproxy/imap-core/test/fixtures/mimetorture.js +0 -2740
- package/lib/imapproxy/imap-core/test/fixtures/mimetorture.json +0 -1411
- package/lib/imapproxy/imap-core/test/fixtures/mimetree.js +0 -85
- package/lib/imapproxy/imap-core/test/fixtures/nodemailer.eml +0 -582
- package/lib/imapproxy/imap-core/test/fixtures/ryan_finnie_mime_torture.eml +0 -599
- package/lib/imapproxy/imap-core/test/fixtures/simple.eml +0 -42
- package/lib/imapproxy/imap-core/test/fixtures/simple.json +0 -164
- package/lib/imapproxy/imap-core/test/imap-compile-stream-test.js +0 -671
- package/lib/imapproxy/imap-core/test/imap-compiler-test.js +0 -272
- package/lib/imapproxy/imap-core/test/imap-indexer-test.js +0 -236
- package/lib/imapproxy/imap-core/test/imap-parser-test.js +0 -922
- package/lib/imapproxy/imap-core/test/memory-notifier.js +0 -129
- package/lib/imapproxy/imap-core/test/prepare.sh +0 -74
- package/lib/imapproxy/imap-core/test/protocol-test.js +0 -1756
- package/lib/imapproxy/imap-core/test/search-test.js +0 -1356
- package/lib/imapproxy/imap-core/test/test-client.js +0 -152
- package/lib/imapproxy/imap-core/test/test-server.js +0 -623
- package/lib/imapproxy/imap-core/test/tools-test.js +0 -22
- package/test/api-test.js +0 -899
- package/test/autoreply-test.js +0 -327
- package/test/bounce-test.js +0 -151
- package/test/complaint-test.js +0 -256
- package/test/fixtures/autoreply/LICENSE +0 -27
- package/test/fixtures/autoreply/rfc3834-01.eml +0 -23
- package/test/fixtures/autoreply/rfc3834-02.eml +0 -24
- package/test/fixtures/autoreply/rfc3834-03.eml +0 -26
- package/test/fixtures/autoreply/rfc3834-04.eml +0 -48
- package/test/fixtures/autoreply/rfc3834-05.eml +0 -19
- package/test/fixtures/autoreply/rfc3834-06.eml +0 -59
- package/test/fixtures/bounces/163.eml +0 -2521
- package/test/fixtures/bounces/fastmail.eml +0 -242
- package/test/fixtures/bounces/gmail.eml +0 -252
- package/test/fixtures/bounces/hotmail.eml +0 -655
- package/test/fixtures/bounces/mailru.eml +0 -121
- package/test/fixtures/bounces/outlook.eml +0 -1107
- package/test/fixtures/bounces/postfix.eml +0 -101
- package/test/fixtures/bounces/rambler.eml +0 -116
- package/test/fixtures/bounces/workmail.eml +0 -142
- package/test/fixtures/bounces/yahoo.eml +0 -139
- package/test/fixtures/bounces/zoho.eml +0 -83
- package/test/fixtures/bounces/zonemta.eml +0 -100
- package/test/fixtures/complaints/LICENSE +0 -27
- package/test/fixtures/complaints/amazonses.eml +0 -72
- package/test/fixtures/complaints/dmarc.eml +0 -59
- package/test/fixtures/complaints/hotmail.eml +0 -49
- package/test/fixtures/complaints/optout.eml +0 -40
- package/test/fixtures/complaints/standard-arf.eml +0 -68
- package/test/fixtures/complaints/yahoo.eml +0 -68
- package/test/oauth2-apps-test.js +0 -301
- package/test/sendonly-test.js +0 -160
- package/test/test-config.js +0 -34
- 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
|
-
});
|