From 95da261efcf7c15b5e522344e207a3a04a374961 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 10 Jun 2020 07:04:50 +0000 Subject: imap: allow UID range search on timestamps Since it seems somewhat common for IMAP clients to limit searches by sent Date: or INTERNALDATE, we can rely on the NNTP/WWW-optimized overview DB. For other queries, we'll have to depend on the Xapian DB. --- lib/PublicInbox/DummyInbox.pm | 2 +- lib/PublicInbox/IMAP.pm | 13 ++++++++----- lib/PublicInbox/Over.pm | 13 +++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) (limited to 'lib/PublicInbox') diff --git a/lib/PublicInbox/DummyInbox.pm b/lib/PublicInbox/DummyInbox.pm index e38f9e5a..b6c48db1 100644 --- a/lib/PublicInbox/DummyInbox.pm +++ b/lib/PublicInbox/DummyInbox.pm @@ -13,7 +13,7 @@ sub max { undef } # Msgmap::max sub msg_range { [] } # Msgmap::msg_range no warnings 'once'; -*query_xover = \&msg_range; +*uid_range = *query_xover = \&msg_range; *over = \&mm; *subscribe_unlock = *unsubscribe_unlock = *get_art = *description = *base_url = \&max; diff --git a/lib/PublicInbox/IMAP.pm b/lib/PublicInbox/IMAP.pm index f9af530a..78042b9e 100644 --- a/lib/PublicInbox/IMAP.pm +++ b/lib/PublicInbox/IMAP.pm @@ -811,10 +811,11 @@ sub parse_date ($) { # 02-Oct-1993 } sub uid_search_uid_range { # long_response - my ($self, $tag, $beg, $end) = @_; - my $uids = $self->{ibx}->mm->msg_range($beg, $end, 'num'); + my ($self, $tag, $beg, $end, $sql) = @_; + my $uids = $self->{ibx}->over->uid_range($$beg, $end, $sql); if (@$uids) { - $self->msg_more(join('', map { " $_->[0]" } @$uids)); + $$beg = $uids->[-1] + 1; + $self->msg_more(join(' ', '', @$uids)); } else { $self->write(\"\r\n$tag OK Search done\r\n"); undef; @@ -936,13 +937,15 @@ sub cmd_uid_search ($$$;) { my $ibx = $self->{ibx} or return "$tag BAD No mailbox selected\r\n"; my $q = parse_query($self, \@_); return "$tag $q\r\n" if !ref($q); + my $sql = delete $q->{sql}; if (!scalar(keys %$q)) { $self->msg_more('* SEARCH'); my $beg = $self->{uid_min} // 1; my $end = $ibx->mm->max; uid_clamp($self, \$beg, \$end); - long_response($self, \&uid_search_uid_range, $tag, \$beg, $end); + long_response($self, \&uid_search_uid_range, + $tag, \$beg, $end, $sql); } elsif (my $uid = $q->{uid}) { if ($uid =~ /\A([0-9]+):([0-9]+|\*)\z/s) { my ($beg, $end) = ($1, $2); @@ -950,7 +953,7 @@ sub cmd_uid_search ($$$;) { uid_clamp($self, \$beg, \$end); $self->msg_more('* SEARCH'); long_response($self, \&uid_search_uid_range, - $tag, \$beg, $end); + $tag, \$beg, $end, $sql); } elsif ($uid =~ /\A[0-9]+\z/s) { $uid = $ibx->over->get_art($uid) ? " $uid" : ''; "* SEARCH$uid\r\n$tag OK Search done\r\n"; diff --git a/lib/PublicInbox/Over.pm b/lib/PublicInbox/Over.pm index 286fb7f6..402cbf7c 100644 --- a/lib/PublicInbox/Over.pm +++ b/lib/PublicInbox/Over.pm @@ -215,4 +215,17 @@ SELECT num,ts,ds,ddd FROM over WHERE num = ? LIMIT 1 load_from_row($smsg); } +# IMAP search +sub uid_range { + my ($self, $beg, $end, $sql) = @_; + my $dbh = $self->connect; + my $q = 'SELECT num FROM over WHERE num >= ? AND num <= ?'; + + # This is read-only, anyways; but caller should verify it's + # only sending \A[0-9]+\z for ds and ts column ranges + $q .= $$sql if $sql; + $q .= ' ORDER BY num ASC LIMIT ' . DEFAULT_LIMIT; + $dbh->selectcol_arrayref($q, undef, $beg, $end); +} + 1; -- cgit v1.2.3-24-ge0c7