]> git.g-eek.se Git - interimap.git/commitdiff
pullimap: keep trying to pull new messages after issuing any IMAP command.
authorGuilhem Moulin <guilhem@fripost.org>
Wed, 9 Mar 2016 19:59:14 +0000 (20:59 +0100)
committerGuilhem Moulin <guilhem@fripost.org>
Wed, 9 Mar 2016 20:08:54 +0000 (21:08 +0100)
Indeed we might get an untagged EXISTS response, meaning that a new
message has been received meanwhile.

lib/Net/IMAP/InterIMAP.pm
pullimap

index bd69d87781eeb6ec78260c867c4d463ed3ea803e..bad49da3e91b52276c5e282db1731aa4cd5dbf43 100644 (file)
@@ -1053,7 +1053,7 @@ sub uidvalidity($;$) {
 }
 
 
-# $self->set_cache(@attributes)
+# $self->get_cache(@attributes)
 #   Return the persistent cache for the mailbox currently selected.  If
 #   some @attributes are given, return the list of values corresponding
 #   to these attributes.
index a1f82e2c84f2fd7d6f57e027d12eaf3f50398f58..02aedf6e2f64c0b3f318c8abbffe50554ae15ddc 100755 (executable)
--- a/pullimap
+++ b/pullimap
@@ -244,13 +244,18 @@ sub purge() {
         my @m = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/; # RFC 3501's date-month
         my $date = sprintf("%02d-%s-%04d", $now[3], $m[$now[4]], $now[5]+1900);
         my @uid = $IMAP->search("UID $set BEFORE $date");
-        return unless @uid;
 
-        $set = compact_set(@uid);
-        $IMAP->log("Removing ".($#uid+1)." UID(s) $set") unless $CONFIG{quiet};
+        $set = @uid ? compact_set(@uid) : undef;
+        $IMAP->log("Removing ".($#uid+1)." UID(s) $set") if defined $set and !$CONFIG{quiet};
     }
-    $IMAP->silent_store($set, '+', '\Deleted');
-    $IMAP->expunge($set);
+
+    if (defined $set) {
+        $IMAP->silent_store($set, '+', '\Deleted');
+        $IMAP->expunge($set);
+    }
+
+    # pull messages that have been received in the meantime
+    pull() if $IMAP->has_new_mails($MAILBOX);
 }
 
 # Use BODY.PEEK[] so if something gets wrong, unpulled messages
@@ -258,37 +263,46 @@ sub purge() {
 my $ATTRS = "ENVELOPE INTERNALDATE";
 $ATTRS .= " BODY.PEEK[]" unless $CONFIG{'no-delivery'};
 
+sub pull_callback($$) {
+    my ($uids, $mail) = @_;
+    return unless exists $mail->{RFC822} or $CONFIG{'no-delivery'}; # not for us
+
+    my $uid = $mail->{UID};
+    my $from = first { defined $_ and @$_ } @{$mail->{ENVELOPE}}[2,3,4];
+    $from = (defined $from and @$from) ? $from->[0]->[2].'@'.$from->[0]->[3] : '';
+    $IMAP->log("UID $uid from <$from> ($mail->{INTERNALDATE})") unless $CONFIG{quiet};
+
+    sendmail($from, $mail->{RFC822}) unless $CONFIG{'no-delivery'};
+
+    push @$uids, $uid;
+    writeUID($uid);
+}
+
 # Pull new messages from IMAP and deliver them to SMTP, then update the
 # statefile
 sub pull(;$) {
     my $ignore = shift // [];
     my @uid;
 
-    # invariant: we're at pos 8 + 4*(1+$#ignore + 1+$#uids) in the statefile
-    $IMAP->pull_new_messages($ATTRS, sub($) {
-        my $mail = shift;
-        return unless exists $mail->{RFC822} or $CONFIG{'no-delivery'}; # not for us
-
-        my $uid = $mail->{UID};
-        my $from = first { defined $_ and @$_ } @{$mail->{ENVELOPE}}[2,3,4];
-        $from = (defined $from and @$from) ? $from->[0]->[2].'@'.$from->[0]->[3] : '';
-        $IMAP->log("UID $uid from <$from> ($mail->{INTERNALDATE})") unless $CONFIG{quiet};
+    my $callback = sub($) { pull_callback(\@uid, shift) };
 
-        sendmail($from, $mail->{RFC822}) unless $CONFIG{'no-delivery'};
+    do {
+        # invariant: we're at pos 8 + 4*(1+$#ignore + 1+$#uids) in the statefile
+        $IMAP->pull_new_messages($ATTRS, $callback, @$ignore);
 
-        push @uid, $uid;
-        writeUID($uid);
-    }, @$ignore);
+        # now that everything has been deliverd, mark @ignore and @uid as \Seen
+        $IMAP->silent_store(compact_set(@$ignore, @uid), '+', '\Seen') if @$ignore or @uid;
+    }
+    # repeat if we got a message in the meantime
+    while ($IMAP->has_new_mails($MAILBOX));
 
     # terminate the SMTP transmission channel gracefully, cf RFC 5321 section 4.5.3.2
     smtp_send('QUIT' => '221') if defined $SMTP;
     undef $SMTP;
 
-    # now that everything has been deliverd, mark @ignore and @uid as \Seen
-    $IMAP->silent_store(compact_set(@$ignore, @uid), '+', '\Seen') if @$ignore or @uid;
-
     # update the statefile
-    sysseek($STATE, 4, SEEK_SET) or die "Can't seek: $!";
+    my $p = sysseek($STATE, 4, SEEK_SET) // die "Can't seek: $!";
+    die "Couldn't seek to 4" unless $p == 4; # safety check
     my ($uidnext) = $IMAP->get_cache('UIDNEXT');
     writeUID($uidnext);
     truncate($STATE, 8) // die "Can't truncate";