Skip Menu |

This queue is for tickets about the Mail-IMAPClient CPAN distribution.

Report information
The Basics
Id: 61062
Status: resolved
Priority: 0/
Queue: Mail-IMAPClient

People
Owner: PLOBBES [...] cpan.org
Requestors: johan.ekenberg [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 3.25
Fixed in: 3.26



Subject: migrate() errors
Hello Mail-IMAPClient-3.25 perl 5.8.8, i686 Linux I'm trying to use migrate() First I got "Write failed ''" from line 1077. Looking at that code, I can't see how the while-loop starting at line 1047 could ever complete successfully after a successful syswrite(), since at line 1078 there is an unconditional return statement. I commented out lines 1077-1078. Then came the next error: Label not found for "next MIGMSG" at /usr/lib/perl5/site_perl/5.8.8/Mail/IMAPClient.pm line 1026. Looking at that piece of code, there is no label "MIGMSG" so this is clearly a bug. I suspect it should be "MSG" since that label exists above at line 872. I tried renaming the MIGMSG labels to MSG. Now the code runs but seems to end up in an endless loop where nothing happens. stracing shows forever: read(3, 0x8569328, 1) = -1 EAGAIN (Resource temporarily unavailable) where filehandle 3 is the source_imap object. I haven't (yet) located exactly where in the code this read/sysread is done since I don't know how to do that without adding a huge number of debug-statements. ? At this point I don't know what to do. Is the migrate()-code in a state of transition or revision? Please let me know what ever I can do to help! /Johan Ekenberg
From: johan.ekenberg [...] gmail.com
On Sat Sep 04 10:06:27 2010, grebneke wrote: Show quoted text
> I tried renaming the MIGMSG labels to MSG. Now the code runs but seems > to end up in an endless loop where nothing happens. stracing shows
forever: Show quoted text
> > read(3, 0x8569328, 1) = -1 EAGAIN (Resource temporarily unavailable) > where filehandle 3 is the source_imap object.
Correction: fh 3 is the target imap object. Anyway: I found the comment around line 830, which explains a lot: #???? this code is very clumsy, and currently probably broken. I fiddled around a bit and eventually got it all working. Please see the attached patch. (Some of the changes are just variable-names that happened when I was trying to sort stuff out.) But it's not very fast. Using the default buffer size of 4096 it's actually damn slow. With a buffer around 4096 * 32 it worked better, but still couldn't beat using Mail::Mbox::MessageParser to read the source mailbox and then feed it to IMAPClient, append()ing to the target mailbox. So I guess I'll stick to that solution even though it felt neater to use a dedicated migrate()-function. Take care, /Johan
Subject: Mail-IMAPClient.pm.patch
--- /root/.cpan/build/Mail-IMAPClient-3.25/blib/lib/Mail/IMAPClient.pm Fri May 28 06:06:35 2010 +++ /usr/lib/perl5/site_perl/5.8.8/Mail/IMAPClient.pm Sun Sep 5 01:00:52 2010 @@ -978,12 +979,12 @@ if ( $code ne 'OK' ) { $self->_debug("Error writing to target host: $@"); - next MIGMSG; + next MSG; } # Here is where we start sticking in UID if that parameter # is turned on: - my $string = ( $self->Uid ? "UID " : "" ) . "FETCH $mid $cmd"; + my $fetchCmd = ( $self->Uid ? "UID " : "" ) . "FETCH $mid $cmd"; # Clean up history buffer if necessary: $self->Clear($clear) @@ -993,16 +994,16 @@ # next IMAP FETCH should start (1st time start at offset zero): my $position = 0; my $chunkCount = 0; - my $readSoFar = 0; while ( $leftSoFar > 0 ) { + my $readSoFar = 0; my $take = min $leftSoFar, $bufferSize; - my $newstring = "$trans $string<$position.$take>"; + my $newFetchCmd = "$trans $fetchCmd<$position.$take>"; - $self->_record( $trans, [ 0, "INPUT", $newstring ] ); - $self->_debug("Issuing migration command: $newstring"); + $self->_record( $trans, [ 0, "INPUT", $newFetchCmd ] ); + $self->_debug("Issuing migration command: $newFetchCmd"); - unless ( $self->_send_line($newstring) ) { - $self->LastError( "Error sending '$newstring' to source IMAP: " + unless ( $self->_send_line($newFetchCmd) ) { + $self->LastError( "Error sending '$newFetchCmd' to source IMAP: " . $self->LastError ); return undef; } @@ -1016,14 +1018,15 @@ $self->_record( $trans, [ 0, "OUTPUT", $fromBuffer ] ); +# TODO: We should make sure $toSock is available (interrupt any ongoing APPEND reads etc) before trying the next message if ( $fromBuffer =~ /^$trans\s+(?:NO|BAD)/ ) { $self->LastError($fromBuffer); - next MIGMSG; + next MSG; } elsif ( $fromBuffer =~ /^$trans\s+OK/ ) { $self->LastError( "Unexpected good return code " . "from source host: $fromBuffer" ); - next MIGMSG; + next MSG; } } @@ -1035,6 +1038,14 @@ || 0; } + + # Finish up reading the server fetch response from the source system: + # look for "<trans> (OK|BAD|NO)" + $self->_debug("Reading from source: expecting 'OK' response"); + $code = $self->_get_response($trans) or return undef; + return undef unless $code eq 'OK'; + + # We have read a chunk, now comes the writing my $wroteSoFar = 0; my $temperrs = 0; my $waittime = .02; @@ -1074,24 +1085,15 @@ $self->State(Unconnected) if ( $! == EPIPE or $! == ECONNRESET ); - $self->LastError("Write failed '$!'"); - return; # no luck } $peer->_debug( "Chunk $chunkCount: wrote $wroteSoFar (of $chunk)"); } - } - $position += $readSoFar; $leftSoFar -= $readSoFar; - my $fromBuffer = ""; + } - # Finish up reading the server fetch response from the source system: - # look for "<trans> (OK|BAD|NO)" - $self->_debug("Reading from source: expecting 'OK' response"); - $code = $self->_get_response($trans) or return undef; - return undef unless $code eq 'OK'; # Now let's send a CRLF to the peer to signal end of APPEND cmd: unless ( $peer->_send_bytes( \$CRLF ) ) {
Thanks for the bug report and patch. As you found migrate() was broken (and has been broken for some time). Thanks to your help we will at least get it back to working I guess. Since I've taken over maintenance I have ignored it, sorry. When it comes to more serious "migrations" imapsync does a better (or more comprehensive job) at the moment. If I ever get lots of free time and some inspiration perhaps migrate() will grow to become more useful and complete but I doubt that happens any time soon. Regardless, your feedback and patch are greatly appreciated. I will try to include this (or something similar) in the next release!
Thanks again for your patch. In 3.26 the code for migrate() will be very simplified but should be functional at least. I have also done some major memory usage improvements (in other methods) that should allow this simplified code to work better or more systems than was possible in the past. Hopefully I'll have 3.26 out within the next week.
Mail::IMAPClient 3.26 has been released to CPAN. Please install it if you get a chance and let me know if you run into any more problems, thanks!