diff options
Diffstat (limited to 'lib/PublicInbox/WatchMaildir.pm')
-rw-r--r-- | lib/PublicInbox/WatchMaildir.pm | 88 |
1 files changed, 54 insertions, 34 deletions
diff --git a/lib/PublicInbox/WatchMaildir.pm b/lib/PublicInbox/WatchMaildir.pm index 24989130..b82b5102 100644 --- a/lib/PublicInbox/WatchMaildir.pm +++ b/lib/PublicInbox/WatchMaildir.pm @@ -335,6 +335,27 @@ sub mic_for ($$$) { # mic = Mail::IMAPClient $mic; } +sub imap_import_msg ($$$$$$) { + my ($self, $itrk, $url, $r_uidval, $uid, $raw) = @_; + # our target audience expects LF-only, save storage + $$raw =~ s/\r\n/\n/sg; + + my $inboxes = $self->{imap}->{$url}; + if (ref($inboxes)) { + for my $ibx (@$inboxes) { + my $eml = PublicInbox::Eml->new($$raw); + my $x = import_eml($self, $ibx, $eml); + } + } elsif ($inboxes eq 'watchspam') { + my $eml = PublicInbox::Eml->new($raw); + my $arg = [ $self, $eml, "$url UID:$uid" ]; + $self->{config}->each_inbox(\&remove_eml_i, $arg); + } else { + die "BUG: destination unknown $inboxes"; + } + $itrk->update_last($url, $r_uidval, $uid); +} + sub imap_fetch_all ($$$) { my ($self, $mic, $uri) = @_; my $sec = imap_section($uri); @@ -367,52 +388,51 @@ sub imap_fetch_all ($$$) { } return if $l_uid >= $r_uid; # nothing to do + warn "I: $url fetching UID $l_uid:$r_uid\n"; $mic->Uid(1); # the default, we hope + my $uids; my $req = $mic->imap4rev1 ? 'BODY.PEEK[]' : 'RFC822.PEEK'; my $key = $req; $key =~ s/\.PEEK//; - my $inboxes = $self->{imap}->{$url}; - warn "I: $url fetching $l_uid..$r_uid\n"; - my $uid = -1; + my $uid; my $warn_cb = $SIG{__WARN__} || sub { print STDERR @_ }; local $SIG{__WARN__} = sub { + $uid //= -1; $warn_cb->("$url UID:$uid\n"); $warn_cb->(@_); }; my $err; - $itrk->{dbh}->begin_work; - for my $u ($l_uid..$r_uid) { - $uid = $u; - local $0 = "UID:$uid $mbx $sec"; - my $r = $mic->fetch_hash($uid, $req); - unless ($r) { # network error? - $err = "E: $url UID FETCH $uid error: $!\n"; - last; - } - - # messages get deleted, so holes appear - defined(my $raw = delete $r->{$uid}->{$key}) or next; - - # our target audience expects LF-only, save storage - $raw =~ s/\r\n/\n/sg; - - if (ref($inboxes)) { - for my $ibx (@$inboxes) { - my $eml = PublicInbox::Eml->new($raw); - my $x = import_eml($self, $ibx, $eml); + do { + $uids = $mic->search("UID $l_uid:*") or + return "E: $url UID SEARCH $l_uid:* error: $!"; + return if scalar(@$uids) == 0; + + # RFC 3501 doesn't seem to indicate order of UID SEARCH + # responses, so sort it ourselves + @$uids = sort { $a <=> $b } @$uids; + + # Did we actually get new messages? + return if $uids->[0] < $l_uid; + + $l_uid = $uids->[-1] + 1; # for next search + + $itrk->{dbh}->begin_work; + while (defined(($uid = shift(@$uids)))) { + local $0 = "UID:$uid $mbx $sec"; + my $r = $mic->fetch_hash($uid, $req); + unless ($r) { # network error? + $err = "E: $url UID FETCH $uid error: $!"; + last; } - } elsif ($inboxes eq 'watchspam') { - my $eml = PublicInbox::Eml->new($raw); - my $arg = [ $self, $eml, "$uri UID:$uid" ]; - $self->{config}->each_inbox(\&remove_eml_i, $arg); - } else { - die "BUG: destination unknown $inboxes"; + # messages get deleted, so holes appear + defined(my $raw = delete $r->{$uid}->{$key}) or next; + imap_import_msg($self, $itrk, $url, $r_uidval, $uid, + \$raw); + last if $self->{quit}; } - $itrk->update_last($url, $r_uidval, $uid); - last if $self->{quit}; - } - _done_for_now($self); - $itrk->{dbh}->commit; + _done_for_now($self); + $itrk->{dbh}->commit; + } until ($err || $self->{quit}); $err; } |