@bobfrankston/iflow 1.0.45 → 1.0.47

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.
@@ -472,6 +472,14 @@ export class NativeImapClient {
472
472
  this.buffer = this.buffer.substring(this.pendingCommand.literalBytes);
473
473
  this.pendingCommand.literalBuffer = (this.pendingCommand.literalBuffer || "") + literal;
474
474
  this.pendingCommand.literalBytes = undefined;
475
+ // Store the literal data by its BODY key for parseFetchResponses
476
+ if (this.pendingCommand.currentLiteralKey) {
477
+ if (!this.pendingCommand.literals)
478
+ this.pendingCommand.literals = new Map();
479
+ this.pendingCommand.literals.set(this.pendingCommand.currentLiteralKey, literal);
480
+ this.pendingCommand.currentLiteralKey = undefined;
481
+ this.pendingCommand.currentLiteralSize = undefined;
482
+ }
475
483
  if (this.verbose)
476
484
  console.log(` [imap] literal consumed, ${literal.length} bytes, buffer remaining: ${this.buffer.length}`);
477
485
  // After consuming literal, check if the NEXT part has another literal
@@ -503,8 +511,14 @@ export class NativeImapClient {
503
511
  this.pendingCommand.literalBuffer = linePrefix;
504
512
  }
505
513
  this.pendingCommand.literalBytes = size;
514
+ // Extract the BODY section key from the prefix (e.g. BODY[], BODY[HEADER], BODY.PEEK[])
515
+ const keyMatch = linePrefix.match(/BODY(?:\.PEEK)?\[([^\]]*)\]\s*$/i);
516
+ if (keyMatch) {
517
+ this.pendingCommand.currentLiteralKey = `BODY[${keyMatch[1]}]`;
518
+ this.pendingCommand.currentLiteralSize = size;
519
+ }
506
520
  if (this.verbose)
507
- console.log(` [imap] literal announced: ${size} bytes, prefix: ${linePrefix.length} chars`);
521
+ console.log(` [imap] literal announced: ${size} bytes, prefix: ${linePrefix.length} chars, key: ${this.pendingCommand.currentLiteralKey || "none"}`);
508
522
  continue;
509
523
  }
510
524
  // If we have buffered literal data, prepend it to this line (the closing part after the literal)
@@ -514,6 +528,11 @@ export class NativeImapClient {
514
528
  this.pendingCommand.literalBuffer = undefined;
515
529
  }
516
530
  const resp = proto.parseResponseLine(fullLine);
531
+ // Attach accumulated literals to the response and reset for next response
532
+ if (this.pendingCommand?.literals?.size) {
533
+ resp.literals = this.pendingCommand.literals;
534
+ this.pendingCommand.literals = undefined;
535
+ }
517
536
  if (this.verbose) {
518
537
  const display = resp.raw.length > 200 ? resp.raw.substring(0, 200) + `... (${resp.raw.length} bytes)` : resp.raw;
519
538
  console.log(` [imap] < [tag=${resp.tag} type=${resp.type}] ${display}`);
@@ -622,9 +641,15 @@ export class NativeImapClient {
622
641
  msg.replyTo = env.replyTo;
623
642
  msg.inReplyTo = env.inReplyTo;
624
643
  }
625
- // Source body is in literal data (handled by literal buffering in processBuffer)
626
- // For now, simplified — the literal handling needs more work for production
627
- // TODO: improve literal parsing for BODY[] and BODY[HEADER]
644
+ // Extract body source and headers from literals tracked by processBuffer
645
+ if (r.literals) {
646
+ const source = r.literals.get("BODY[]");
647
+ if (source)
648
+ msg.source = source;
649
+ const headers = r.literals.get("BODY[HEADER]");
650
+ if (headers)
651
+ msg.headers = headers;
652
+ }
628
653
  messages.push(msg);
629
654
  }
630
655
  return messages;
@@ -13,6 +13,8 @@ export interface ImapResponse {
13
13
  text: string;
14
14
  /** Raw line */
15
15
  raw: string;
16
+ /** Literal data keyed by BODY section name (e.g. "BODY[]", "BODY[HEADER]") */
17
+ literals?: Map<string, string>;
16
18
  }
17
19
  /** Parsed FETCH response data */
18
20
  export interface FetchData {
@@ -340,11 +340,13 @@ function parseAddressList(token) {
340
340
  if (!token || token === "NIL")
341
341
  return [];
342
342
  const addrs = [];
343
- // Match each (name atdomain mailbox host) group
344
- const re = /\(([^)]*)\)/g;
345
- let m;
346
- while ((m = re.exec(token)) !== null) {
347
- const parts = tokenizeParenList(m[1]);
343
+ // Tokenize the outer list to get each address group as a paren-delimited token
344
+ // e.g. ((name NIL mailbox host)(name2 NIL mailbox2 host2)) → ["(name NIL mailbox host)", "(name2 ...)"]
345
+ const groups = tokenizeParenList(token);
346
+ for (const group of groups) {
347
+ if (!group.startsWith("("))
348
+ continue;
349
+ const parts = tokenizeParenList(group);
348
350
  if (parts.length >= 4) {
349
351
  const name = decodeImapString(unquote(parts[0]));
350
352
  const mailbox = unquote(parts[2]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/iflow",
3
- "version": "1.0.45",
3
+ "version": "1.0.47",
4
4
  "description": "IMAP client wrapper library",
5
5
  "main": "index.js",
6
6
  "types": "index.ts",