@bobfrankston/iflow 1.0.42 → 1.0.44
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/imaplib/imap-native.js +31 -21
- package/imaplib/imap-protocol.js +2 -2
- package/package.json +1 -1
package/imaplib/imap-native.js
CHANGED
|
@@ -141,18 +141,10 @@ export class NativeImapClient {
|
|
|
141
141
|
this.capabilities.add(c.toUpperCase());
|
|
142
142
|
}
|
|
143
143
|
async logout() {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
await Promise.race([
|
|
149
|
-
this.sendCommand(tag, proto.logoutCommand(tag)),
|
|
150
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error("LOGOUT timeout")), 5000))
|
|
151
|
-
]);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
catch { /* ignore — always close transport below */ }
|
|
155
|
-
this.pendingCommand = null; // clear any hanging promise
|
|
144
|
+
// Force-close the transport immediately. The LOGOUT command is a courtesy —
|
|
145
|
+
// the server cleans up the session when the socket closes.
|
|
146
|
+
// Sending LOGOUT and waiting caused hangs and connection leaks.
|
|
147
|
+
this.pendingCommand = null;
|
|
156
148
|
this.transport.close();
|
|
157
149
|
this._connected = false;
|
|
158
150
|
}
|
|
@@ -473,15 +465,23 @@ export class NativeImapClient {
|
|
|
473
465
|
}
|
|
474
466
|
processBuffer() {
|
|
475
467
|
while (true) {
|
|
476
|
-
// Check for literal {size}\r\n
|
|
468
|
+
// Check for literal {size}\r\n — reading exact byte count of literal data
|
|
477
469
|
if (this.pendingCommand?.literalBytes != null) {
|
|
478
470
|
if (this.buffer.length >= this.pendingCommand.literalBytes) {
|
|
479
471
|
const literal = this.buffer.substring(0, this.pendingCommand.literalBytes);
|
|
480
472
|
this.buffer = this.buffer.substring(this.pendingCommand.literalBytes);
|
|
481
473
|
this.pendingCommand.literalBuffer = (this.pendingCommand.literalBuffer || "") + literal;
|
|
482
474
|
this.pendingCommand.literalBytes = undefined;
|
|
475
|
+
if (this.verbose)
|
|
476
|
+
console.log(` [imap] literal consumed, ${literal.length} bytes, buffer remaining: ${this.buffer.length}`);
|
|
477
|
+
// After consuming literal, check if the NEXT part has another literal
|
|
478
|
+
// (e.g., BODY[HEADER] {500}\r\n<data>BODY[] {2000}\r\n<data>)\r\n)
|
|
479
|
+
// Continue to process the next line/literal from the buffer
|
|
483
480
|
continue;
|
|
484
481
|
}
|
|
482
|
+
if (this.verbose && this.pendingCommand.literalBytes > 0) {
|
|
483
|
+
console.log(` [imap] waiting for literal: need ${this.pendingCommand.literalBytes}, have ${this.buffer.length}`);
|
|
484
|
+
}
|
|
485
485
|
break; // Wait for more data
|
|
486
486
|
}
|
|
487
487
|
const lineEnd = this.buffer.indexOf("\r\n");
|
|
@@ -489,24 +489,34 @@ export class NativeImapClient {
|
|
|
489
489
|
break;
|
|
490
490
|
const line = this.buffer.substring(0, lineEnd + 2);
|
|
491
491
|
this.buffer = this.buffer.substring(lineEnd + 2);
|
|
492
|
-
// Check for literal announcement {size}
|
|
492
|
+
// Check for literal announcement {size}\r\n at end of line
|
|
493
493
|
const literalMatch = line.match(/\{(\d+)\}\r\n$/);
|
|
494
494
|
if (literalMatch && this.pendingCommand) {
|
|
495
|
-
|
|
496
|
-
// Store the line prefix before
|
|
497
|
-
const linePrefix = line.substring(0,
|
|
498
|
-
this.pendingCommand.literalBuffer
|
|
495
|
+
const size = parseInt(literalMatch[1]);
|
|
496
|
+
// Store the line prefix before {size} — will be prepended after literal is consumed
|
|
497
|
+
const linePrefix = line.substring(0, literalMatch.index);
|
|
498
|
+
if (this.pendingCommand.literalBuffer) {
|
|
499
|
+
// Already have buffered data from a previous literal — append this prefix
|
|
500
|
+
this.pendingCommand.literalBuffer += linePrefix;
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
this.pendingCommand.literalBuffer = linePrefix;
|
|
504
|
+
}
|
|
505
|
+
this.pendingCommand.literalBytes = size;
|
|
506
|
+
if (this.verbose)
|
|
507
|
+
console.log(` [imap] literal announced: ${size} bytes, prefix: ${linePrefix.length} chars`);
|
|
499
508
|
continue;
|
|
500
509
|
}
|
|
501
|
-
// If we have buffered literal data, prepend it
|
|
510
|
+
// If we have buffered literal data, prepend it to this line (the closing part after the literal)
|
|
502
511
|
let fullLine = line;
|
|
503
512
|
if (this.pendingCommand?.literalBuffer) {
|
|
504
513
|
fullLine = this.pendingCommand.literalBuffer + line;
|
|
505
514
|
this.pendingCommand.literalBuffer = undefined;
|
|
506
515
|
}
|
|
507
516
|
const resp = proto.parseResponseLine(fullLine);
|
|
508
|
-
if (this.verbose
|
|
509
|
-
|
|
517
|
+
if (this.verbose) {
|
|
518
|
+
const display = resp.raw.length > 200 ? resp.raw.substring(0, 200) + `... (${resp.raw.length} bytes)` : resp.raw;
|
|
519
|
+
console.log(` [imap] < [tag=${resp.tag} type=${resp.type}] ${display}`);
|
|
510
520
|
}
|
|
511
521
|
// Server greeting — resolve readGreeting() promise
|
|
512
522
|
if (this.greetingResolve && resp.tag === "*" && (resp.type === "OK" || resp.type === "PREAUTH")) {
|
package/imaplib/imap-protocol.js
CHANGED
|
@@ -116,8 +116,8 @@ export function parseResponseLine(line) {
|
|
|
116
116
|
// Untagged response
|
|
117
117
|
if (trimmed.startsWith("* ")) {
|
|
118
118
|
const rest = trimmed.substring(2);
|
|
119
|
-
// Check for numeric response (e.g., "* 5 EXISTS")
|
|
120
|
-
const numMatch = rest.match(/^(\d+)\s+(\S+)
|
|
119
|
+
// Check for numeric response (e.g., "* 5 EXISTS", "* 131441 FETCH (...)")
|
|
120
|
+
const numMatch = rest.match(/^(\d+)\s+(\S+)/);
|
|
121
121
|
if (numMatch) {
|
|
122
122
|
return { tag: "*", type: numMatch[2].toUpperCase(), text: rest, raw: trimmed };
|
|
123
123
|
}
|