X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FIMAP.pm;h=9599f494587b68d1dccf064465c96a426da3cac7;hb=c51c22c349529d9c377160abcc7961a6ca7b7d5c;hp=d8c898f4b511e1f93bfdcfeac59cc5c7e87a99f0;hpb=54c25a9cfb9a5eee44672b126eb75b9bb20aa957;p=public-inbox.git diff --git a/lib/PublicInbox/IMAP.pm b/lib/PublicInbox/IMAP.pm index d8c898f4..9599f494 100644 --- a/lib/PublicInbox/IMAP.pm +++ b/lib/PublicInbox/IMAP.pm @@ -40,9 +40,7 @@ use PublicInbox::Syscall qw(EPOLLIN EPOLLONESHOT); use PublicInbox::GitAsyncCat; use Text::ParseWords qw(parse_line); use Errno qw(EAGAIN); -use PublicInbox::Search; use PublicInbox::IMAPsearchqp; -*mdocid = \&PublicInbox::Search::mdocid; my $Address; for my $mod (qw(Email::Address::XS Mail::Address)) { @@ -117,7 +115,7 @@ sub new ($$$) { my $wbuf; if ($sock->can('accept_SSL') && !$sock->accept_SSL) { return CORE::close($sock) if $! != EAGAIN; - $ev = PublicInbox::TLS::epollbit(); + $ev = PublicInbox::TLS::epollbit() or return CORE::close($sock); $wbuf = [ \&PublicInbox::DS::accept_tls_step, \&greet ]; } $self->SUPER::new($sock, $ev | EPOLLONESHOT); @@ -246,6 +244,7 @@ sub uo2m_extend ($$;$) { my $base = $self->{uid_base}; ++$beg; my $uids = $self->{ibx}->over->uid_range($beg, $base + UID_SLICE); + return $uo2m if !scalar(@$uids); my @tmp; # [$UID_OFFSET] => $MSN my $write_method = $_[2] // 'msg_more'; if (ref($uo2m)) { @@ -301,7 +300,7 @@ sub msn2uid ($) { # converts a set of message sequence numbers in requests to UIDs: sub msn_to_uid_range ($$) { my $msn2uid = $_[0]; - $_[1] =~ s!([0-9]+)!$msn2uid->[$1 - 1] // ($msn2uid->[-1] + 1)!sge; + $_[1] =~ s!([0-9]+)!$msn2uid->[$1 - 1] // ($msn2uid->[-1] // 0 + 1)!sge; } # called by PublicInbox::InboxIdle @@ -616,17 +615,23 @@ sub fetch_run_ops { sub fetch_blob_cb { # called by git->cat_async via git_async_cat my ($bref, $oid, $type, $size, $fetch_arg) = @_; my ($self, undef, $msgs, $range_info, $ops, $partial) = @$fetch_arg; + my $ibx = $self->{ibx} or return $self->close; # client disconnected my $smsg = shift @$msgs or die 'BUG: no smsg'; if (!defined($oid)) { # it's possible to have TOCTOU if an admin runs # public-inbox-(edit|purge), just move onto the next message - warn "E: $smsg->{blob} missing in $self->{ibx}->{inboxdir}\n"; + warn "E: $smsg->{blob} missing in $ibx->{inboxdir}\n"; return requeue_once($self); } else { $smsg->{blob} eq $oid or die "BUG: $smsg->{blob} != $oid"; } + my $pre; + if (!$self->{wbuf} && (my $nxt = $msgs->[0])) { + $pre = git_async_prefetch($ibx->git, $nxt->{blob}, + \&fetch_blob_cb, $fetch_arg); + } fetch_run_ops($self, $smsg, $bref, $ops, $partial); - requeue_once($self); + $pre ? $self->zflush : requeue_once($self); } sub emit_rfc822 { @@ -1105,67 +1110,6 @@ sub search_uid_range { # long_response 1; # more } -sub date_search { - my ($q, $k, $d) = @_; - my $sql = $q->{sql}; - - # Date: header - if ($k eq 'SENTON') { - my $end = $d + 86399; # no leap day... - my $da = strftime('%Y%m%d%H%M%S', gmtime($d)); - my $db = strftime('%Y%m%d%H%M%S', gmtime($end)); - $q->{xap} .= " dt:$da..$db"; - $$sql .= " AND ds >= $d AND ds <= $end" if defined($sql); - } elsif ($k eq 'SENTBEFORE') { - $q->{xap} .= ' d:..'.strftime('%Y%m%d', gmtime($d)); - $$sql .= " AND ds <= $d" if defined($sql); - } elsif ($k eq 'SENTSINCE') { - $q->{xap} .= ' d:'.strftime('%Y%m%d', gmtime($d)).'..'; - $$sql .= " AND ds >= $d" if defined($sql); - - # INTERNALDATE (Received) - } elsif ($k eq 'ON') { - my $end = $d + 86399; # no leap day... - $q->{xap} .= " ts:$d..$end"; - $$sql .= " AND ts >= $d AND ts <= $end" if defined($sql); - } elsif ($k eq 'BEFORE') { - $q->{xap} .= " ts:..$d"; - $$sql .= " AND ts <= $d" if defined($sql); - } elsif ($k eq 'SINCE') { - $q->{xap} .= " ts:$d.."; - $$sql .= " AND ts >= $d" if defined($sql); - } else { - die "BUG: $k not recognized"; - } -} - -# IMAP to Xapian search key mapping -my %I2X = ( - SUBJECT => 's:', - BODY => 'b:', - FROM => 'f:', - TEXT => '', # n.b. does not include all headers - TO => 't:', - CC => 'c:', - # BCC => 'bcc:', # TODO - # KEYWORD # TODO ? dfpre,dfpost,... -); - -# IMAP allows searching arbitrary headers via "HEADER $HDR_NAME $HDR_VAL" -# which gets silly expensive. We only allow the headers we already index. -my %H2X = (%I2X, 'MESSAGE-ID' => 'm:', 'LIST-ID' => 'l:'); - -sub xap_append ($$$$) { - my ($q, $rest, $k, $xk) = @_; - delete $q->{sql}; # can't use over.sqlite3 - defined(my $arg = shift @$rest) or return "BAD $k no arg"; - - # AFAIK Xapian can't handle [*"] in probabilistic terms - $arg =~ tr/*"//d; - ${$q->{xap}} .= qq[ $xk"$arg"]; - undef; -} - sub parse_query ($$) { my ($self, $query) = @_; my $q = PublicInbox::IMAPsearchqp::parse($self, $query); @@ -1183,9 +1127,8 @@ sub refill_xap ($$$$) { my ($beg, $end) = @$range_info; my $srch = $self->{ibx}->search; my $opt = { mset => 2, limit => 1000 }; - my $nshard = $srch->{nshard} // 1; - my $mset = $srch->query("$q uid:$beg..$end", $opt); - @$uids = map { mdocid($nshard, $_) } $mset->items; + my $mset = $srch->mset("$q uid:$beg..$end", $opt); + @$uids = @{$srch->mset_to_artnums($mset)}; if (@$uids) { $range_info->[0] = $uids->[-1] + 1; # update $beg return; # possibly more