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
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";