From 2a06fc8e54607e7d418ee746ab4e17ad48716c6d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 25 Jun 2020 10:09:36 +0000 Subject: imap: always send EXISTS on uo2m_extend 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 0a6993c6..888c9bec 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; } -- cgit v1.2.3-24-ge0c7