From 5570af137725259a66043bcb747ecbdb3839a2d3 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 11 Mar 2016 22:04:17 +0100 Subject: Net::IMAP::InterIMAP: Don't increase UIDNEXT when receiving EXISTS responses. Indeed, if the server sends * n EXISTS * n EXPUNGE meaning a new message is received, and is immediately removed afterwards, the server might have allocated a new UID for the removed message. --- lib/Net/IMAP/InterIMAP.pm | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index be61cb6..cdc5697 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -645,6 +645,7 @@ sub unselect($) { # we'll get back to it $self->{_VANISHED} = []; $self->{_MODIFIED} = {}; + $self->{_NEW} = 0; } @@ -1082,6 +1083,7 @@ sub get_cache($@) { # persistent cache's values. sub is_dirty($$) { my ($self, $mailbox) = @_; + return 1 if $self->{_NEW}; $self->_updated_cache($mailbox, qw/HIGHESTMODSEQ UIDNEXT/); } @@ -1091,6 +1093,7 @@ sub is_dirty($$) { # internal cache's UIDNEXT value differs from its persistent cache's. sub has_new_mails($$) { my ($self, $mailbox) = @_; + return 1 if $self->{_NEW}; $self->_updated_cache($mailbox, 'UIDNEXT'); } @@ -1181,6 +1184,7 @@ sub pull_new_messages($$&@) { my @ignore = sort { $a <=> $b } @_; my $mailbox = $self->{_SELECTED} // $self->panic(); + my $cache = $self->{_CACHE}->{$mailbox}; my $UIDNEXT; do { @@ -1205,19 +1209,20 @@ sub pull_new_messages($$&@) { # 2^32-1: don't use '*' since the highest UID can be known already $range .= "$since:4294967295"; - $UIDNEXT = $self->{_CACHE}->{$mailbox}->{UIDNEXT} // $self->panic(); # sanity check + $UIDNEXT = $cache->{UIDNEXT} // $self->panic(); # sanity check $self->_send("UID FETCH $range ($attrs)", sub($) { my $mail = shift; $UIDNEXT = $mail->{UID} + 1 if $UIDNEXT <= $mail->{UID}; $callback->($mail) if defined $callback; - }) if $first < $UIDNEXT; + }) if $first < $UIDNEXT or $self->{_NEW}; # update the persistent cache for UIDNEXT (not for HIGHESTMODSEQ # since there might be pending updates) $self->set_cache($mailbox, UIDNEXT => $UIDNEXT); + $self->{_NEW} = 0; } # loop if new messages were received in the meantime - while ($UIDNEXT < $self->{_CACHE}->{$mailbox}->{UIDNEXT}); + while ($self->{_NEW} or $UIDNEXT < $cache->{UIDNEXT}); } @@ -1993,6 +1998,7 @@ sub _open_mailbox($$) { # we'll get back to it $self->{_VANISHED} = []; $self->{_MODIFIED} = {}; + $self->{_NEW} = 0; $self->{_SELECTED} = $mailbox; $self->{_CACHE}->{$mailbox} //= {}; @@ -2233,12 +2239,12 @@ sub _resp($$;&$$) { # /!\ $cache->{EXISTS} MUST NOT be defined on SELECT if (defined $cache->{EXISTS}) { $self->panic("Unexpected EXISTS shrink $1 < $cache->{EXISTS}!") if $1 < $cache->{EXISTS}; - # the actual UIDNEXT is *at least* that - $cache->{UIDNEXT} += $1 - $cache->{EXISTS} if defined $cache->{UIDNEXT}; + $self->{_NEW} += $1 - $cache->{EXISTS} if $1 > $cache->{EXISTS}; # new mails } $cache->{EXISTS} = $1; } elsif (/\A([0-9]+) EXPUNGE\z/) { + $self->panic() unless defined $cache->{EXISTS}; # sanity check # /!\ No bookkeeping since there is no internal cache mapping sequence numbers to UIDs if ($self->_enabled('QRESYNC')) { $self->panic("$1 <= $cache->{EXISTS}") if $1 <= $cache->{EXISTS}; # sanity check @@ -2270,7 +2276,7 @@ sub _resp($$;&$$) { $callback->($mailbox, %status) if defined $callback and $cmd eq 'STATUS'; } elsif (s/\A([0-9]+) FETCH \(//) { - $self->panic("$1 <= $cache->{EXISTS}") unless $1 <= $cache->{EXISTS}; # sanity check + $cache->{EXISTS} = $1 if $1 > $cache->{EXISTS}; my ($seq, $first) = ($1, 1); my %mail; while ($_ ne ')') { -- cgit v1.2.3