about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@yhbt.net>2020-06-10 07:05:13 +0000
committerEric Wong <e@yhbt.net>2020-06-13 07:55:45 +0000
commitcaf3331f0496c709e5543c75ae1dbb48bba54921 (patch)
tree6479fe5db1265de4c11663d5cab4a8bd624e742e
parentd0dcab33e0b02bf3299deea40f96ef5fff10fe73 (diff)
downloadpublic-inbox-caf3331f0496c709e5543c75ae1dbb48bba54921.tar.gz
We can share a bit of code with FETCH to refill UID
ranges which hit the SQLite overview.
-rw-r--r--lib/PublicInbox/IMAP.pm84
1 files changed, 35 insertions, 49 deletions
diff --git a/lib/PublicInbox/IMAP.pm b/lib/PublicInbox/IMAP.pm
index 41c80664..f6106a1e 100644
--- a/lib/PublicInbox/IMAP.pm
+++ b/lib/PublicInbox/IMAP.pm
@@ -650,26 +650,31 @@ sub fetch_smsg { # long_response
         1; # more
 }
 
-sub fetch_uid { # long_response
-        my ($self, $tag, $uids, $range_info, $ops) = @_;
-
-        while (!@$uids) { # rare
-                my ($beg, $end, $range_csv) = @$range_info;
-                if (scalar(@$uids = @{$self->{ibx}->over->
-                                        uid_range($beg, $end)})) {
-                        $range_info->[0] = $uids->[-1] + 1;
-                } elsif (!$range_csv) {
-                        $self->write(\"$tag OK Fetch done\r\n");
+sub refill_uids ($$$;$) {
+        my ($self, $uids, $range_info, $sql) = @_;
+        my ($beg, $end, $range_csv) = @$range_info;
+        my $over = $self->{ibx}->over;
+        while (1) {
+                if (scalar(@$uids = @{$over->uid_range($beg, $end, $sql)})) {
+                        $range_info->[0] = $uids->[-1] + 1; # update $beg
                         return;
+                } elsif (!$range_csv) {
+                        return 0;
                 } else {
                         my $next_range = range_step($self, \$range_csv);
-                        if (!ref($next_range)) { # error
-                                $self->write(\"$tag $next_range\r\n");
-                                return;
-                        }
-                        @$range_info = @$next_range;
+                        return $next_range if !ref($next_range); # error
+                        ($beg, $end, $range_csv) = @$range_info = @$next_range;
+                        # continue looping
                 }
-                # continue looping
+        }
+}
+
+sub fetch_uid { # long_response
+        my ($self, $tag, $uids, $range_info, $ops) = @_;
+        if (defined(my $err = refill_uids($self, $uids, $range_info))) {
+                $err ||= 'OK Fetch done';
+                $self->write("$tag $err\r\n");
+                return;
         }
         my ($i, $k);
         my $msn = $range_info->[3];
@@ -967,15 +972,15 @@ sub parse_date ($) { # 02-Oct-1993
 }
 
 sub uid_search_uid_range { # long_response
-        my ($self, $tag, $beg, $end, $sql) = @_;
-        my $uids = $self->{ibx}->over->uid_range($$beg, $end, $sql);
-        if (@$uids) {
-                $$beg = $uids->[-1] + 1;
-                $self->msg_more(join(' ', '', @$uids));
-        } else {
-                $self->write(\"\r\n$tag OK Search done\r\n");
-                undef;
+        my ($self, $tag, $uids, $sql, $range_info) = @_;
+        if (defined(my $err = refill_uids($self, $uids, $range_info, $sql))) {
+                $err ||= 'OK Search done';
+                $self->write("\r\n$tag $err\r\n");
+                return;
         }
+        $self->msg_more(join(' ', '', @$uids));
+        @$uids = ();
+        1; # more
 }
 
 sub date_search {
@@ -1079,12 +1084,8 @@ sub parse_query {
                 return 'BAD Xapian not configured for mailbox';
         }
 
-        if (my $uid = $q->{uid}) {
-                ((@$uid > 1) || $uid->[0] =~ /,/) and
-                        return 'BAD multiple ranges not supported, yet';
-                ($q->{sql} // $q->{xap}) and
-                        return 'BAD ranges and queries do not mix, yet';
-                $q->{uid} = join(',', @$uid); # TODO: multiple ranges
+        if (my $uid = delete $q->{uid}) {
+                $q->{uid} = join(',', @$uid);
         }
         $q;
 }
@@ -1095,28 +1096,13 @@ sub cmd_uid_search ($$$;) {
         my $q = parse_query($self, \@_);
         return "$tag $q\r\n" if !ref($q);
         my $sql = delete $q->{sql};
-
+        my $range_csv = delete $q->{uid} // '1:*';
+        my $range_info = range_step($self, \$range_csv);
+        return "$tag $range_info\r\n" if !ref($range_info);
         if (!scalar(keys %$q)) {
                 $self->msg_more('* SEARCH');
-                my $beg = 1;
-                my $end = $ibx->over->max;
-                uid_clamp($self, \$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);
-                        $end = $ibx->over->max if $end eq '*';
-                        uid_clamp($self, \$beg, \$end);
-                        $self->msg_more('* SEARCH');
-                        long_response($self, \&uid_search_uid_range,
-                                        $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";
-                } else {
-                        "$tag BAD Error\r\n";
-                }
+                                $tag, [], $sql, $range_info);
         } else {
                 "$tag BAD Error\r\n";
         }