imapflow 2.0.5 → 2.0.7

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.7](https://github.com/postalsys/imapflow/compare/v2.0.6...v2.0.7) (2026-09-25)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **fetch:** keep body sections a server sends as quoted strings ([a4f2f18](https://github.com/postalsys/imapflow/commit/a4f2f181f978dea9e6c94195c1f4ddbe54d52fc7)), closes [#403](https://github.com/postalsys/imapflow/issues/403)
9
+
10
+ ## [2.0.6](https://github.com/postalsys/imapflow/compare/v2.0.5...v2.0.6) (2026-09-22)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **parser:** split flags a server writes without the separating space ([96b2022](https://github.com/postalsys/imapflow/commit/96b202283ea5840842b4c9c94319b2b29cad829f))
16
+
3
17
  ## [2.0.5](https://github.com/postalsys/imapflow/compare/v2.0.4...v2.0.5) (2026-09-15)
4
18
 
5
19
 
@@ -356,6 +356,7 @@ class TokenParser {
356
356
  break;
357
357
  case STATE_ATOM:
358
358
  // An atom is terminated by: space, closing delimiter of parent node,
359
+ // a backslash starting the next flag of a list (broken servers only),
359
360
  // or encountering a '[' that starts a section for BODY/BINARY commands.
360
361
  // space finishes an atom
361
362
  if (chr === ' ') {
@@ -376,6 +377,30 @@ class TokenParser {
376
377
  checkSP();
377
378
  break;
378
379
  }
380
+ // A backslash can not occur inside an atom (it is a quoted-special), so one
381
+ // arriving inside a flag of a parenthesized list can only be a server that
382
+ // wrote two flags without the separating space, as home.pl does in its LIST
383
+ // responses ("\\Sent\\HasNoChildren"). Read it as the end of this flag and the
384
+ // start of the next one rather than rejecting the line, which would drop the
385
+ // whole mailbox. Only an atom that already is a flag is split, so an unquoted
386
+ // name is never cut in two, and only when a flag name follows, so a trailing
387
+ // backslash still fails as before instead of becoming a one-character flag
388
+ if (chr === '\\') {
389
+ const parent = this.currentNode.parentNode;
390
+ const value = this.currentNode.value;
391
+ const next = this.str.charAt(i + 1);
392
+ if (parent &&
393
+ parent.type === 'LIST' &&
394
+ value.length > 1 &&
395
+ value.startsWith('\\') &&
396
+ next &&
397
+ (imap_formal_syntax_js_1.default['ATOM-CHAR']().includes(next) || next === '*')) {
398
+ this.currentNode.endPos = this.pos + i - 1;
399
+ this.currentNode = parent;
400
+ startAtom();
401
+ break;
402
+ }
403
+ }
379
404
  // If the atom so far is all digits and we see ',' or ':', it is actually
380
405
  // a sequence set (e.g., "1:5" or "1,3,5"), so reclassify and switch state
381
406
  if ((chr === ',' || chr === ':') && RE_DIGITS.test(this.currentNode.value)) {
@@ -1,3 +1,3 @@
1
1
  export declare const name = "imapflow";
2
- export declare const version = "2.0.5";
2
+ export declare const version = "2.0.7";
3
3
  export declare const homepage = "https://imapflow.com/";
@@ -3,5 +3,5 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.homepage = exports.version = exports.name = void 0;
5
5
  exports.name = 'imapflow';
6
- exports.version = '2.0.5';
6
+ exports.version = '2.0.7';
7
7
  exports.homepage = 'https://imapflow.com/';
package/dist/cjs/tools.js CHANGED
@@ -681,6 +681,12 @@ async function formatMessageResponse(untagged, mailbox) {
681
681
  if (Buffer.isBuffer(attribute.value)) {
682
682
  return attribute.value;
683
683
  }
684
+ // A section is an nstring, so a server may answer with a quoted string
685
+ // instead of a literal (Yahoo does for small parts). The tokenizer decoded
686
+ // the line as UTF-8, so encoding the same way restores the bytes it sent.
687
+ if (typeof attribute.value === 'string') {
688
+ return Buffer.from(attribute.value);
689
+ }
684
690
  };
685
691
  // NIL (parsed as null) and other non-array values yield an empty array, so callers
686
692
  // can safely index into the result. RFC 8474 allows e.g. `THREADID NIL` when the
@@ -350,6 +350,7 @@ export class TokenParser {
350
350
  break;
351
351
  case STATE_ATOM:
352
352
  // An atom is terminated by: space, closing delimiter of parent node,
353
+ // a backslash starting the next flag of a list (broken servers only),
353
354
  // or encountering a '[' that starts a section for BODY/BINARY commands.
354
355
  // space finishes an atom
355
356
  if (chr === ' ') {
@@ -370,6 +371,30 @@ export class TokenParser {
370
371
  checkSP();
371
372
  break;
372
373
  }
374
+ // A backslash can not occur inside an atom (it is a quoted-special), so one
375
+ // arriving inside a flag of a parenthesized list can only be a server that
376
+ // wrote two flags without the separating space, as home.pl does in its LIST
377
+ // responses ("\\Sent\\HasNoChildren"). Read it as the end of this flag and the
378
+ // start of the next one rather than rejecting the line, which would drop the
379
+ // whole mailbox. Only an atom that already is a flag is split, so an unquoted
380
+ // name is never cut in two, and only when a flag name follows, so a trailing
381
+ // backslash still fails as before instead of becoming a one-character flag
382
+ if (chr === '\\') {
383
+ const parent = this.currentNode.parentNode;
384
+ const value = this.currentNode.value;
385
+ const next = this.str.charAt(i + 1);
386
+ if (parent &&
387
+ parent.type === 'LIST' &&
388
+ value.length > 1 &&
389
+ value.startsWith('\\') &&
390
+ next &&
391
+ (imapFormalSyntax['ATOM-CHAR']().includes(next) || next === '*')) {
392
+ this.currentNode.endPos = this.pos + i - 1;
393
+ this.currentNode = parent;
394
+ startAtom();
395
+ break;
396
+ }
397
+ }
373
398
  // If the atom so far is all digits and we see ',' or ':', it is actually
374
399
  // a sequence set (e.g., "1:5" or "1,3,5"), so reclassify and switch state
375
400
  if ((chr === ',' || chr === ':') && RE_DIGITS.test(this.currentNode.value)) {
@@ -1,3 +1,3 @@
1
1
  export declare const name = "imapflow";
2
- export declare const version = "2.0.5";
2
+ export declare const version = "2.0.7";
3
3
  export declare const homepage = "https://imapflow.com/";
@@ -1,4 +1,4 @@
1
1
  // Generated by scripts/build.js from package.json. Do not edit by hand.
2
2
  export const name = 'imapflow';
3
- export const version = '2.0.5';
3
+ export const version = '2.0.7';
4
4
  export const homepage = 'https://imapflow.com/';
package/dist/esm/tools.js CHANGED
@@ -631,6 +631,12 @@ export async function formatMessageResponse(untagged, mailbox) {
631
631
  if (Buffer.isBuffer(attribute.value)) {
632
632
  return attribute.value;
633
633
  }
634
+ // A section is an nstring, so a server may answer with a quoted string
635
+ // instead of a literal (Yahoo does for small parts). The tokenizer decoded
636
+ // the line as UTF-8, so encoding the same way restores the bytes it sent.
637
+ if (typeof attribute.value === 'string') {
638
+ return Buffer.from(attribute.value);
639
+ }
634
640
  };
635
641
  // NIL (parsed as null) and other non-array values yield an empty array, so callers
636
642
  // can safely index into the result. RFC 8474 allows e.g. `THREADID NIL` when the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imapflow",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "IMAP Client for Node",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/imap-flow.js",
@@ -70,15 +70,15 @@
70
70
  "devDependencies": {
71
71
  "@types/node": "20.19.43",
72
72
  "c8": "12.0.0",
73
- "eslint": "10.10.0",
73
+ "eslint": "10.11.0",
74
74
  "eslint-config-prettier": "10.1.8",
75
75
  "globals": "17.12.0",
76
- "prettier": "3.9.6",
77
- "tsx": "4.23.13",
76
+ "prettier": "3.9.8",
77
+ "tsx": "4.23.15",
78
78
  "types-node-legacy": "npm:@types/node@20.0.0",
79
79
  "typescript": "6.0.3",
80
- "typescript-eslint": "8.70.0",
81
- "wrangler": "4.131.2"
80
+ "typescript-eslint": "8.70.1",
81
+ "wrangler": "4.136.3"
82
82
  },
83
83
  "dependencies": {
84
84
  "@zone-eu/mailsplit": "5.4.17",