From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 50DF61FBC5 for ; Wed, 10 Jun 2020 07:06:28 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 49/82] imap: EXAMINE/STATUS: return correct counts Date: Wed, 10 Jun 2020 07:04:46 +0000 Message-Id: <20200610070519.18252-50-e@yhbt.net> In-Reply-To: <20200610070519.18252-1-e@yhbt.net> References: <20200610070519.18252-1-e@yhbt.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: 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 8c6fa7b62c9..e726307a678 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"; }