+ # break out long words individually to search for, because
+ # too many messages begin with "Pine.LNX." (or "alpine" or "nycvar")
+ if ($mid =~ /\w{9,}/) {
+ my @long = ($mid =~ m!(\w{3,})!g);
+ push(@try, join(' ', map { "m:$_" } @long));
+
+ # is the last element long enough to not trigger excessive
+ # wildcard matches?
+ if (length($long[-1]) > 8) {
+ $long[-1] .= '*';
+ push(@try, join(' ', map { "m:$_" } @long));
+ }
+ }
+
+ foreach my $m (@try) {
+ # If Xapian can't handle the wildcard since it
+ # has too many results. $@ can be
+ # Search::Xapian::QueryParserError or even:
+ # "something terrible happened at ../Search/Xapian/Enquire.pm"
+ my $mset = eval { $srch->mset($m, $opt) } or next;
+ my @mids = map {
+ $_->{mid}
+ } @{$srch->mset_to_smsg($ibx, $mset)};
+ return \@mids if scalar(@mids);
+ }
+}
+
+sub ext_msg_i {
+ my ($other, $ctx) = @_;
+
+ return if $other->{name} eq $ctx->{-inbox}->{name} || !$other->base_url;
+
+ my $mm = $other->mm or return;
+
+ # try to find the URL with Msgmap to avoid forking
+ my $num = $mm->num_for($ctx->{mid});
+ if (defined $num) {
+ push @{$ctx->{found}}, $other;
+ } else {
+ # no point in trying the fork fallback if we
+ # know Xapian is up-to-date but missing the
+ # message in the current repo
+ push @{$ctx->{again}}, $other;
+ }
+}
+
+sub ext_msg_step {
+ my ($pi_cfg, $section, $ctx) = @_;
+ if (defined($section)) {
+ return if $section !~ m!\Apublicinbox\.([^/]+)\z!;
+ my $ibx = $pi_cfg->lookup_name($1) or return;
+ ext_msg_i($ibx, $ctx);
+ } else { # undef == "EOF"
+ finalize_exact($ctx);
+ }
+}