From 464862335d1bc09437d4238214d30a1db7b829bd Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 15:53:13 +0200 Subject: bugfix: Fetching new messages from local and adding them to remote modifies its UIDNEXT. So we need to check again the first $source (remote) whenever the last one (local) added new messages to it. --- imapsync | 46 ++++++++++++++++++++++++++-------------------- lib/Net/IMAP/Sync.pm | 4 ++-- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/imapsync b/imapsync index c0da7d6..25e65d6 100755 --- a/imapsync +++ b/imapsync @@ -961,26 +961,32 @@ sub callback_new_message_flush($$$@) { # the given UIDs. sub sync_messages($$;$$) { my ($idx, $mailbox, $lIgnore, $rIgnore) = @_; - my ($buff, $bufflen, @lUIDs); - - # get new messages from remote (except @$rIgnore) and APPEND them to local - ($buff, $bufflen) = ([], 0); - undef $buff if $lIMAP->incapable('MULTIAPPEND'); - $rIMAP->pull_new_messages(sub($) { - callback_new_message($idx, $mailbox, 'remote', shift, \@lUIDs, $buff, \$bufflen) - }, @{$rIgnore // []}); - push @lUIDs, callback_new_message_flush($idx, $mailbox, 'remote', @$buff) - if defined $buff and @$buff; - - # get new messages from local (except @$lIgnore and the newly allocated local - # UIDs @lUIDs) and APPEND them to remote - ($buff, $bufflen) = ([], 0); - undef $buff if $rIMAP->incapable('MULTIAPPEND'); - $lIMAP->pull_new_messages(sub($) { - callback_new_message($idx, $mailbox, 'local', shift, undef, $buff, \$bufflen) - }, @{$lIgnore // []}, @lUIDs); - callback_new_message_flush($idx, $mailbox, 'local', @$buff) - if defined $buff and @$buff; + + my %ignore = (local => ($lIgnore // []), remote => ($rIgnore // [])); + my $loop; + do { + # get new messages from $source (except @{$ignore{$source}}) and APPEND them to $target + foreach my $source (qw/remote local/) { # pull remote mails first + my $target = $source eq 'remote' ? 'local' : 'remote'; + my $buff = [] unless ($target eq 'local' ? $lIMAP : $rIMAP)->incapable('MULTIAPPEND'); + my $bufflen = 0; + my @tUIDs; + + ($source eq 'remote' ? $rIMAP : $lIMAP)->pull_new_messages(sub($) { + callback_new_message($idx, $mailbox, $source, shift, \@tUIDs, $buff, \$bufflen) + }, @{$ignore{$source}}); + + push @tUIDs, callback_new_message_flush($idx, $mailbox, $source, @$buff) + if defined $buff and @$buff; + push @{$ignore{$target}}, @tUIDs; + + $loop = @tUIDs ? 1 : 0; + } + # since $source modifies $target's UIDNEXT upon new mails, we + # need to check again the first $source (remote) whenever the + # last one (local) added new messages to it + } + while ($loop); # both local and remote UIDNEXT are now up to date; proceed with # pending flag updates and vanished messages diff --git a/lib/Net/IMAP/Sync.pm b/lib/Net/IMAP/Sync.pm index 26303a6..bf56519 100644 --- a/lib/Net/IMAP/Sync.pm +++ b/lib/Net/IMAP/Sync.pm @@ -657,12 +657,12 @@ sub append($$@) { my @uids; foreach (split /,/, $uidset) { if (/\A([0-9]+)\z/) { - $UIDNEXT = $1 + 1 if $UIDNEXT <= $1; + $UIDNEXT = $1 + 1 if defined $UIDNEXT and $UIDNEXT <= $1; push @uids, $1; } elsif (/\A([0-9]+):([0-9]+)\z/) { my ($min, $max) = $1 <= $2 ? ($1,$2) : ($2,$1); push @uids, ($min .. $max); - $UIDNEXT = $max + 1 if $UIDNEXT <= $max; + $UIDNEXT = $max + 1 if defined $UIDNEXT and $UIDNEXT <= $max; } else { $self->panic($_); } -- cgit v1.2.3