diff options
author | Eric Wong <e@yhbt.net> | 2020-06-25 10:09:37 +0000 |
---|---|---|
committer | Eric Wong <e@yhbt.net> | 2020-06-27 10:08:29 +0000 |
commit | 89efc8f4e8d603e4fad3c4c754e23561d82de2c1 (patch) | |
tree | 238aaad487b111782cdae773111f1d8bbedcdc02 /lib/PublicInbox/IMAP.pm | |
parent | 2a06fc8e54607e7d418ee746ab4e17ad48716c6d (diff) | |
download | public-inbox-89efc8f4e8d603e4fad3c4c754e23561d82de2c1.tar.gz |
We need to rely on num_highwater for UIDNEXT since the highest `num' stored in over.sqlite3 may be rolled back if the most recent messages were spam. We also need to load the uo2m immediately on EXAMINE to ensure EXISTS responses are always consistent with regard to future updates.
Diffstat (limited to 'lib/PublicInbox/IMAP.pm')
-rw-r--r-- | lib/PublicInbox/IMAP.pm | 61 |
1 files changed, 33 insertions, 28 deletions
diff --git a/lib/PublicInbox/IMAP.pm b/lib/PublicInbox/IMAP.pm index 888c9bec..9ad74de8 100644 --- a/lib/PublicInbox/IMAP.pm +++ b/lib/PublicInbox/IMAP.pm @@ -192,8 +192,8 @@ sub cmd_capability ($$) { # uo2m: UID Offset to MSN, this is an arrayref by default, # but uo2m_hibernate can compact and deduplicate it -sub uo2m_ary_new ($) { - my ($self) = @_; +sub uo2m_ary_new ($;$) { + my ($self, $exists) = @_; my $base = $self->{uid_base}; my $uids = $self->{ibx}->over->uid_range($base + 1, $base + UID_SLICE); @@ -202,6 +202,7 @@ sub uo2m_ary_new ($) { my $msn = 0; ++$base; $tmp[$_ - $base] = ++$msn for @$uids; + $$exists = $msn if $exists; \@tmp; } @@ -385,44 +386,48 @@ sub ensure_slices_exist ($$$) { push @$l, map { qq[* LIST (\\HasNoChildren) "." $_\r\n] } @created; } -sub inbox_lookup ($$) { - my ($self, $mailbox) = @_; - my ($ibx, $exists, $uidnext, $uid_base); - if ($mailbox =~ /\A(.+)\.([0-9]+)\z/) { - # old mail: inbox.comp.foo.$SLICE_IDX - my $mb_top = $1; - $uid_base = $2 * UID_SLICE; - $ibx = $self->{imapd}->{mailboxes}->{lc $mailbox} or return; - my $max; - ($exists, $uidnext, $max) = $ibx->over->imap_status($uid_base, - $uid_base + UID_SLICE); - ensure_slices_exist($self->{imapd}, $ibx, $max); - } else { # check for dummy inboxes - $mailbox = lc $mailbox; - $ibx = $self->{imapd}->{mailboxes}->{$mailbox} or return; - +sub inbox_lookup ($$;$) { + my ($self, $mailbox, $examine) = @_; + my ($ibx, $exists, $uidmax, $uid_base) = (undef, 0, 0, 0); + $mailbox = lc $mailbox; + $ibx = $self->{imapd}->{mailboxes}->{$mailbox} or return; + my $over = $ibx->over; + if ($over != $ibx) { # not a dummy + $mailbox =~ /\.([0-9]+)\z/ or + die "BUG: unexpected dummy mailbox: $mailbox\n"; + $uid_base = $1 * UID_SLICE; + + # ->num_highwater caches for writers, so use ->meta_accessor + $uidmax = $ibx->mm->meta_accessor('num_highwater') // 0; + if ($examine) { + $self->{uid_base} = $uid_base; + $self->{ibx} = $ibx; + $self->{uo2m} = uo2m_ary_new($self, \$exists); + } else { + $exists = $over->imap_exists; + } + ensure_slices_exist($self->{imapd}, $ibx, $over->max); + } else { + if ($examine) { + $self->{uid_base} = $uid_base; + $self->{ibx} = $ibx; + delete $self->{uo2m}; + } # if "INBOX.foo.bar" is selected and "INBOX.foo.bar.0", # check for new UID ranges (e.g. "INBOX.foo.bar.1") if (my $z = $self->{imapd}->{mailboxes}->{"$mailbox.0"}) { ensure_slices_exist($self->{imapd}, $z, $z->over->max); } - - $uid_base = $exists = 0; - $uidnext = 1; } - ($ibx, $exists, $uidnext, $uid_base); + ($ibx, $exists, $uidmax + 1, $uid_base); } sub cmd_examine ($$$) { my ($self, $tag, $mailbox) = @_; - my ($ibx, $exists, $uidnext, $base) = inbox_lookup($self, $mailbox); - return "$tag NO Mailbox doesn't exist: $mailbox\r\n" if !$ibx; - $self->{uid_base} = $base; - delete $self->{uo2m}; - # XXX: do we need this? RFC 5162/7162 my $ret = $self->{ibx} ? "* OK [CLOSED] previous closed\r\n" : ''; - $self->{ibx} = $ibx; + my ($ibx, $exists, $uidnext, $base) = inbox_lookup($self, $mailbox, 1); + return "$tag NO Mailbox doesn't exist: $mailbox\r\n" if !$ibx; $ret .= <<EOF; * $exists EXISTS\r * $exists RECENT\r |