diff options
| -rw-r--r-- | lib/Net/IMAP/InterIMAP.pm | 2 | ||||
| -rwxr-xr-x | pullimap | 58 | 
2 files changed, 37 insertions, 23 deletions
diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index bd69d87..bad49da 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -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. @@ -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";  | 
