Subject: | [PATCH] Reading literals fails when the reply crosses a buffer boundary |
This is hard to explain.
When a literal arrives in a response, _read_line extracts it from the
input buffer and then expects to find the response text (sequence
number, OK|NO|BAD, etc) immediately after it. If that response text runs
off the end of the buffer, _read_line won't recognise it and will
discard the rest of the buffer, then loop and wait for the response text
again, which will never receive.
This is easy to fix. The code at the end of the literal handling block
that tries to find responses after the literal can be removed. The
unprocessed data will remain in the input buffer, and because there is
both data in the buffer and the last output object is not of type
OUTPUT, the loop runs again, it rereads the rest of the response text
from the server, appends in to the buffer, and all is well.
I think its safe to remove this code. It doesn't appear to be doing
anything that isn't handled by the loop running again. Before this
change, a test downloading some 1200 messages from a mailbox would
trigger this bug and hang on six of them. After this change, all are
downloaded successfully.
Mail-IMAPClient-3.00
perl 5.8.8
Debian lenny/sid Linux 2.6.22
Subject: | literal-reply.patch |
diff --git a/lib/Mail/IMAPClient.pm b/lib/Mail/IMAPClient.pm
index 0f87b40..88dbb82 100644
--- a/lib/Mail/IMAPClient.pm
+++ b/lib/Mail/IMAPClient.pm
@@ -1427,29 +1427,8 @@ sub _read_line
$self->Fast_io($fast_io) if $fast_io;
- # Now let's make sure there are no IMAP server output lines
- # (i.e. [tag|*] BAD|NO|OK Text) embedded in the literal string
- my $trailer;
- if($iBuffer =~ s/\r?\n((?:\*|\d+)\s(?:BAD|NO|OK)[^\n]*\r?\n\z)//i)
- { $trailer = $1;
- $self->_debug("Got output in literal: $trailer");
- }
-
- $self->_debug("literal includes ')' of FETCH")
- if length $iBuffer
- && $current_line =~ m/\bFETCH\b/i
- && $iBuffer =~ s/\)$//;
-
- if(length $iBuffer)
- { $self->_debug("literal: too much >>$iBuffer<<");
- $litstring .= $iBuffer;
- $iBuffer = '';
- }
-
push @$oBuffer, [$index++, "OUTPUT", $current_line];
push @$oBuffer, [$index++, "LITERAL", $litstring];
- push @$oBuffer, [$index++, "OUTPUT", $trailer]
- if $trailer;
}
}