From 59f7d24923af08155469420e43e04bce398065da Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 10 Jun 2020 07:04:46 +0000 Subject: [PATCH] imap: EXAMINE/STATUS: return correct counts We can share code between them and account for each 50K mailbox slice. However, we must overreport these for non-zero slices and just return lots of empty data for high-numbered slices because some MUAs still insist on non-UID fetches. --- lib/PublicInbox/IMAP.pm | 53 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/lib/PublicInbox/IMAP.pm b/lib/PublicInbox/IMAP.pm index 8c6fa7b6..e726307a 100644 --- a/lib/PublicInbox/IMAP.pm +++ b/lib/PublicInbox/IMAP.pm @@ -208,42 +208,43 @@ sub ensure_ranges_exist ($$$) { push @$l, map { qq[* LIST (\\HasNoChildren) "." $_\r\n] } @created; } -sub cmd_examine ($$$) { - my ($self, $tag, $mailbox) = @_; - my ($ibx, $mm, $max); - +sub inbox_lookup ($$) { + my ($self, $mailbox) = @_; + my ($ibx, $exists, $uidnext); if ($mailbox =~ /\A(.+)\.([0-9]+)\z/) { # old mail: inbox.comp.foo.$uid_block_idx my ($mb_top, $uid_min) = ($1, $2 * UID_BLOCK + 1); - $ibx = $self->{imapd}->{mailboxes}->{lc $mailbox} or - return "$tag NO Mailbox doesn't exist: $mailbox\r\n"; - - $mm = $ibx->mm; - $max = $mm->max // 0; + $ibx = $self->{imapd}->{mailboxes}->{lc $mailbox} or return; + $exists = $ibx->mm->max // 0; $self->{uid_min} = $uid_min; - ensure_ranges_exist($self->{imapd}, $ibx, $max); + ensure_ranges_exist($self->{imapd}, $ibx, $exists); my $uid_end = $uid_min + UID_BLOCK - 1; - $max = $uid_end if $max > $uid_end; + $exists = $uid_end if $exists > $uid_end; + $uidnext = $exists + 1; } else { # check for dummy inboxes - $ibx = $self->{imapd}->{mailboxes}->{lc $mailbox} or - return "$tag NO Mailbox doesn't exist: $mailbox\r\n"; + $ibx = $self->{imapd}->{mailboxes}->{lc $mailbox} or return; delete $self->{uid_min}; - $max = 0; - $mm = $ibx->mm; + $exists = 0; + $uidnext = 1; } + ($ibx, $exists, $uidnext); +} - my $uidnext = $max + 1; +sub cmd_examine ($$$) { + my ($self, $tag, $mailbox) = @_; + my ($ibx, $exists, $uidnext) = inbox_lookup($self, $mailbox); + return "$tag NO Mailbox doesn't exist: $mailbox\r\n" if !$ibx; # XXX: do we need this? RFC 5162/7162 my $ret = $self->{ibx} ? "* OK [CLOSED] previous closed\r\n" : ''; $self->{ibx} = $ibx; $ret .= <{uidvalidity}]\r $tag OK [READ-ONLY] EXAMINE/SELECT done\r @@ -537,23 +538,21 @@ sub uid_fetch_m { # long_response sub cmd_status ($$$;@) { my ($self, $tag, $mailbox, @items) = @_; - my $ibx = $self->{imapd}->{mailboxes}->{lc $mailbox} or - return "$tag NO Mailbox doesn't exist: $mailbox\r\n"; return "$tag BAD no items\r\n" if !scalar(@items); ($items[0] !~ s/\A\(//s || $items[-1] !~ s/\)\z//s) and return "$tag BAD invalid args\r\n"; - - my $mm = $ibx->mm; - my ($max, @it); + my ($ibx, $exists, $uidnext) = inbox_lookup($self, $mailbox); + return "$tag NO Mailbox doesn't exist: $mailbox\r\n" if !$ibx; + my @it; for my $it (@items) { $it = uc($it); push @it, $it; if ($it =~ /\A(?:MESSAGES|UNSEEN|RECENT)\z/) { - push(@it, ($max //= $mm->max // 0)); + push @it, $exists; } elsif ($it eq 'UIDNEXT') { - push(@it, ($max //= $mm->max // 0) + 1); + push @it, $uidnext; } elsif ($it eq 'UIDVALIDITY') { - push(@it, $ibx->{uidvalidity}); + push @it, $ibx->{uidvalidity}; } else { return "$tag BAD invalid item\r\n"; } -- 2.44.0