about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@yhbt.net>2020-06-25 10:09:36 +0000
committerEric Wong <e@yhbt.net>2020-06-27 10:08:26 +0000
commit2a06fc8e54607e7d418ee746ab4e17ad48716c6d (patch)
tree9d8aeede8fbfffd0b4b6cccccfad3943c92c6074
parent358f61264330da1e510c07868372c02dfa8f6b2c (diff)
downloadpublic-inbox-2a06fc8e54607e7d418ee746ab4e17ad48716c6d.tar.gz
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.
-rw-r--r--lib/PublicInbox/IMAP.pm29
1 files 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;
         }