]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/LeiLcat.pm
imap+nntp: share COMPRESS implementation
[public-inbox.git] / lib / PublicInbox / LeiLcat.pm
index 0f585ff5a6293f51009483fdf722d0100573aa1f..8d89cb7303f2b081b8005daea1dfdf2875f1747b 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2021 all contributors <meta@public-inbox.org>
+# Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 
 # lcat: local cat, display a local message by Message-ID or blob,
@@ -11,28 +11,64 @@ use PublicInbox::LeiViewText;
 use URI::Escape qw(uri_unescape);
 use PublicInbox::MID qw($MID_EXTRACT);
 
-sub lcat_imap_uid_uri ($$) {
-       my ($lei, $uid_uri) = @_;
-       my $lms = $lei->{lse}->lms or return;
-       my $oidhex = $lms->imap_oid($lei, $uid_uri);
-       if (ref(my $err = $oidhex)) { # art2folder error
-               $lei->qerr(@{$err->{qerr}}) if $err->{qerr};
+sub lcat_folder ($$;$$) {
+       my ($lei, $folder, $beg, $end) = @_;
+       my $lms = $lei->{-lms_rw} //= $lei->lms // return;
+       my $folders = [ $folder ];
+       eval { $lms->arg2folder($lei, $folders) };
+       return $lei->child_error(0, "# unknown folder: $folder") if $@;
+       my %range;
+       if (defined($beg)) { # NNTP article range
+               $range{min} = $beg;
+               $range{max} = $end // $beg;
        }
-       push @{$lei->{lcat_blob}}, $oidhex; # cf. LeiToMail->wq_atexit_child
+       for my $f (@$folders) {
+               my $fid = $lms->fid_for($f);
+               push @{$lei->{lcat_todo}}, { fid => $fid, %range };
+       }
+}
+
+sub lcat_imap_uri ($$) {
+       my ($lei, $uri) = @_;
+       # cf. LeiXSearch->lcat_dump
+       my $lms = $lei->{-lms_rw} //= $lei->lms // return;
+       if (defined $uri->uid) {
+               push @{$lei->{lcat_todo}}, $lms->imap_oidhex($lei, $uri);
+       } elsif (defined(my $fid = $lms->fid_for($$uri))) {
+               push @{$lei->{lcat_todo}}, { fid => $fid };
+       } else {
+               lcat_folder($lei, $$uri);
+       }
+}
+
+sub lcat_nntp_uri ($$) {
+       my ($lei, $uri) = @_;
+       my $mid = $uri->message; # already unescaped by URI::news
+       return "mid:$mid" if defined($mid);
+       my $lms = $lei->{-lms_rw} //= $lei->lms // return;
+       my ($ng, $beg, $end) = $uri->group;
+       $uri->group($ng);
+       lcat_folder($lei, $$uri, $beg, $end);
+       '""';
 }
 
 sub extract_1 ($$) {
        my ($lei, $x) = @_;
-       if ($x =~ m!\b(imaps?://[^>]+)!i) {
-               my $u = $1;
-               require PublicInbox::URIimap;
-               $u = PublicInbox::URIimap->new($u);
-               defined($u->uid) ? lcat_imap_uid_uri($lei, $u) :
-                               $lei->child_error(1 << 8, "# no UID= in $u");
-               '""'; # blank query, using {lcat_blob}
-       } elsif ($x =~ m!\b([a-z]+?://\S+)!i) {
-               my $u = $1;
+       if ($x =~ m!\b(maildir:.+)!i) {
+               lcat_folder($lei, $1);
+               '""'; # blank query, using {lcat_todo}
+       } elsif ($x =~ m!\b(([a-z]+)://\S+)!i) {
+               my ($u, $scheme) = ($1, $2);
                $u =~ s/[\>\]\)\,\.\;]+\z//;
+               if ($scheme =~ m!\A(imaps?)\z!i) {
+                       require PublicInbox::URIimap;
+                       lcat_imap_uri($lei, PublicInbox::URIimap->new($u));
+                       return '""'; # blank query, using {lcat_todo}
+               } elsif ($scheme =~ m!\A(?:nntps?|s?news)\z!i) {
+                       require PublicInbox::URInntps;
+                       $u = PublicInbox::URInntps->new($u);
+                       return lcat_nntp_uri($lei, $u);
+               } # http, or something else:
                require URI;
                $u = URI->new($u);
                my $p = $u->path;
@@ -62,7 +98,7 @@ sub extract_1 ($$) {
        } elsif ($x =~ /\bid:(\S+)/) { # notmuch convention
                "mid:$1";
        } elsif ($x =~ /\bblob:([0-9a-f]{7,})\b/) {
-               push @{$lei->{lcat_blob}}, $1; # cf. LeiToMail->wq_atexit_child
+               push @{$lei->{lcat_todo}}, $1; # cf. LeiToMail->wq_atexit_child
                '""'; # blank query
        } else {
                undef;
@@ -74,7 +110,7 @@ sub extract_all {
        my $strict = !$lei->{opt}->{stdin};
        my @q;
        for my $x (@argv) {
-               if (my $term = extract_1($lei,$x)) {
+               if (my $term = extract_1($lei, $x)) {
                        push @q, $term;
                } elsif ($strict) {
                        return $lei->fail(<<"");
@@ -82,37 +118,31 @@ could not extract Message-ID from $x
 
                }
        }
+       delete $lei->{-lms_rw};
        @q ? join(' OR ', @q) : $lei->fail("no Message-ID in: @argv");
 }
 
 sub _stdin { # PublicInbox::InputPipe::consume callback for --stdin
        my ($lei) = @_; # $_[1] = $rbuf
-       if (defined($_[1])) {
-               $_[1] eq '' and return eval {
-                       if (my $dfd = $lei->{3}) {
-                               chdir($dfd) or return $lei->fail("fchdir: $!");
-                       }
-                       my @argv = split(/\s+/, $lei->{mset_opt}->{qstr});
-                       $lei->{mset_opt}->{qstr} = extract_all($lei, @argv)
-                               or return;
-                       $lei->_start_query;
-               };
-               $lei->{mset_opt}->{qstr} .= $_[1];
-       } else {
-               $lei->fail("error reading stdin: $!");
-       }
+       $_[1] // return $lei->fail("error reading stdin: $!");
+       return $lei->{mset_opt}->{qstr} .= $_[1] if $_[1] ne '';
+       eval {
+               $lei->fchdir;
+               my @argv = split(/\s+/, $lei->{mset_opt}->{qstr});
+               $lei->{mset_opt}->{qstr} = extract_all($lei, @argv) or return;
+               $lei->_start_query;
+       };
+       $lei->fail($@) if $@;
 }
 
 sub lei_lcat {
        my ($lei, @argv) = @_;
        my $lxs = $lei->lxs_prepare or return;
-       $lei->ale->refresh_externals($lxs);
-       my $sto = $lei->_lei_store(1);
-       $lei->{lse} = $sto->search;
+       $lei->ale->refresh_externals($lxs, $lei);
+       $lei->_lei_store(1);
        my $opt = $lei->{opt};
-       my %mset_opt = map { $_ => $opt->{$_} } qw(threads limit offset);
+       my %mset_opt;
        $mset_opt{asc} = $opt->{'reverse'} ? 1 : 0;
-       $mset_opt{limit} //= 10000;
        $opt->{sort} //= 'relevance';
        $mset_opt{relevance} = 1;
        $lei->{mset_opt} = \%mset_opt;
@@ -129,4 +159,10 @@ no args allowed on command-line with --stdin
        $lei->_start_query;
 }
 
+sub _complete_lcat {
+       require PublicInbox::LeiRefreshMailSync;
+       PublicInbox::LeiRefreshMailSync::_complete_refresh_mail_sync(@_);
+       # TODO: message-ids?, blobs? could get expensive...
+}
+
 1;