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 63B841F5AF for ; Thu, 25 Jun 2020 10:09:37 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 1/2] imap: always send EXISTS on uo2m_extend Date: Thu, 25 Jun 2020 10:09:36 +0000 Message-Id: <20200625100937.5552-2-e@yhbt.net> In-Reply-To: <20200625100937.5552-1-e@yhbt.net> References: <20200625100937.5552-1-e@yhbt.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: Clients which are NOT in an IDLE state still need to be notified of message existence. Unlike the EXPUNGE response, untagged EXISTS responses seem to be allowed at any time according to RFC 3501. We'll also perform uo2m_extend on the NOOP command, since NOOP is the recommended command for message polling. --- lib/PublicInbox/IMAP.pm | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/PublicInbox/IMAP.pm b/lib/PublicInbox/IMAP.pm index 0a6993c64c4..888c9becfe0 100644 --- a/lib/PublicInbox/IMAP.pm +++ b/lib/PublicInbox/IMAP.pm @@ -190,8 +190,6 @@ sub cmd_capability ($$) { '* '.capa($self)."\r\n$tag OK Capability done\r\n"; } -sub cmd_noop ($$) { "$_[1] OK Noop done\r\n" } - # uo2m: UID Offset to MSN, this is an arrayref by default, # but uo2m_hibernate can compact and deduplicate it sub uo2m_ary_new ($) { @@ -233,7 +231,7 @@ sub uo2m_pack ($) { # extend {uo2m} to account for new messages which arrived since # {uo2m} was created. -sub uo2m_extend ($$) { +sub uo2m_extend ($$;$) { my ($self, $new_uid_max) = @_; defined(my $uo2m = $self->{uo2m}) or return($self->{uo2m} = uo2m_ary_new($self)); @@ -245,20 +243,30 @@ sub uo2m_extend ($$) { ++$beg; my $uids = $self->{ibx}->over->uid_range($beg, $base + UID_SLICE); my @tmp; # [$UID_OFFSET] => $MSN + my $write_method = $_[2] // 'msg_more'; if (ref($uo2m)) { my $msn = $uo2m->[-1]; $tmp[$_ - $beg] = ++$msn for @$uids; + $self->$write_method("* $msn EXISTS\r\n"); push @$uo2m, @tmp; $uo2m; } else { my $msn = unpack('S', substr($uo2m, -2, 2)); $tmp[$_ - $beg] = ++$msn for @$uids; + $self->$write_method("* $msn EXISTS\r\n"); $uo2m .= uo2m_pack(\@tmp); my %dedupe = ($uo2m => undef); $self->{uo2m} = (keys %dedupe)[0]; } } +sub cmd_noop ($$) { + my ($self, $tag) = @_; + defined($self->{uid_base}) and + uo2m_extend($self, $self->{uid_base} + UID_SLICE); + \"$tag OK Noop done\r\n"; +} + # the flexible version which works on scalars and array refs. # Must call uo2m_extend before this sub uid2msn ($$) { @@ -295,14 +303,10 @@ sub msn_to_uid_range ($$) { # called by PublicInbox::InboxIdle sub on_inbox_unlock { my ($self, $ibx) = @_; - my $old = uo2m_last_uid($self); my $uid_end = $self->{uid_base} + UID_SLICE; - uo2m_extend($self, $uid_end); + uo2m_extend($self, $uid_end, 'write'); my $new = uo2m_last_uid($self); - if ($new > $old) { - my $msn = uid2msn($self, $new); - $self->write(\"* $msn EXISTS\r\n"); - } elsif ($new == $uid_end) { # max exceeded $uid_end + if ($new == $uid_end) { # max exceeded $uid_end # continue idling w/o inotify my $sock = $self->{sock} or return; $ibx->unsubscribe_unlock(fileno($sock)); @@ -329,14 +333,13 @@ sub cmd_idle ($$) { my ($self, $tag) = @_; # IDLE seems allowed by dovecot w/o a mailbox selected *shrug* my $ibx = $self->{ibx} or return "$tag BAD no mailbox selected\r\n"; - $self->{-idle_tag} = $tag; - my $max = $ibx->over->max; my $uid_end = $self->{uid_base} + UID_SLICE; + uo2m_extend($self, $uid_end); my $sock = $self->{sock} or return; my $fd = fileno($sock); + $self->{-idle_tag} = $tag; # only do inotify on most recent slice - if ($max < $uid_end) { - uo2m_extend($self, $uid_end); + if ($ibx->over->max < $uid_end) { $ibx->subscribe_unlock($fd, $self); $self->{imapd}->idler_start; }