aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2016-03-11 22:04:17 +0100
committerGuilhem Moulin <guilhem@fripost.org>2016-03-12 00:48:39 +0100
commit5570af137725259a66043bcb747ecbdb3839a2d3 (patch)
tree6d3eced2368c0b5fbeb92d6adf27d8998f04ece1
parentf7becde978ab43cc5859a89d82aeb69521967a2d (diff)
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.
-rw-r--r--lib/Net/IMAP/InterIMAP.pm18
1 files 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 ')') {