@bobfrankston/iflow 1.0.46 → 1.0.48

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.
@@ -215,13 +215,30 @@ export class NativeImapClient {
215
215
  const tag = proto.nextTag();
216
216
  const responses = await this.sendCommand(tag, proto.listCommand(tag));
217
217
  const folders = [];
218
+ let unparsed = 0;
219
+ const listResponses = responses.filter(r => r.tag === "*" && r.type === "LIST");
220
+ if (listResponses.length === 0 && responses.length > 0) {
221
+ console.error(` [imap] LIST returned ${responses.length} responses but none were LIST type. Types: ${responses.map(r => `${r.tag}:${r.type}`).join(", ")}`);
222
+ if (responses.length <= 5) {
223
+ for (const r of responses)
224
+ console.error(` [imap] raw: ${JSON.stringify(r.text.substring(0, 200))}`);
225
+ }
226
+ }
218
227
  for (const r of responses) {
219
228
  if (r.tag === "*" && r.type === "LIST") {
220
229
  const parsed = proto.parseListResponse(r.text);
221
- if (parsed)
230
+ if (parsed) {
222
231
  folders.push(parsed);
232
+ }
233
+ else {
234
+ unparsed++;
235
+ if (unparsed <= 3)
236
+ console.error(` [imap] Unparsed LIST response: ${JSON.stringify(r.text.substring(0, 200))}`);
237
+ }
223
238
  }
224
239
  }
240
+ if (unparsed > 0)
241
+ console.error(` [imap] ${unparsed} LIST responses could not be parsed (${responses.length} total responses)`);
225
242
  return folders;
226
243
  }
227
244
  async getStatus(mailbox) {
@@ -143,13 +143,14 @@ export function parseResponseLine(line) {
143
143
  }
144
144
  /** Parse a LIST response line: * LIST (\flags) "delimiter" "path" */
145
145
  export function parseListResponse(text) {
146
- // Match: LIST (flags) "delimiter" "path" or LIST (flags) "delimiter" path
147
- const match = text.match(/^LIST\s+\(([^)]*)\)\s+"([^"]*)"\s+(?:"([^"]+)"|(\S+))$/i);
146
+ // Match: (flags) "delimiter" "path" or (flags) "delimiter" path
147
+ // The "LIST" prefix may or may not be present (parseResponseLine may strip it into r.type)
148
+ const match = text.match(/^(?:LIST\s+)?\(([^)]*)\)\s+"([^"]*)"\s+(?:"([^"]+)"|(\S+))/i);
148
149
  if (!match)
149
150
  return null;
150
151
  const flags = match[1] ? match[1].split(/\s+/).filter(Boolean) : [];
151
152
  const delimiter = match[2] || ".";
152
- const path = match[3] || match[4] || "";
153
+ const path = (match[3] || match[4] || "").replace(/\r?\n$/, "");
153
154
  return { flags, delimiter, path };
154
155
  }
155
156
  /** Parse STATUS response: * STATUS "mailbox" (MESSAGES n UIDNEXT n ...) */
@@ -340,11 +341,13 @@ function parseAddressList(token) {
340
341
  if (!token || token === "NIL")
341
342
  return [];
342
343
  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]);
344
+ // Tokenize the outer list to get each address group as a paren-delimited token
345
+ // e.g. ((name NIL mailbox host)(name2 NIL mailbox2 host2)) → ["(name NIL mailbox host)", "(name2 ...)"]
346
+ const groups = tokenizeParenList(token);
347
+ for (const group of groups) {
348
+ if (!group.startsWith("("))
349
+ continue;
350
+ const parts = tokenizeParenList(group);
348
351
  if (parts.length >= 4) {
349
352
  const name = decodeImapString(unquote(parts[0]));
350
353
  const mailbox = unquote(parts[2]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/iflow",
3
- "version": "1.0.46",
3
+ "version": "1.0.48",
4
4
  "description": "IMAP client wrapper library",
5
5
  "main": "index.js",
6
6
  "types": "index.ts",