From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id DCB4E1FA13 for ; Fri, 28 May 2021 00:07:57 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 5/6] lei: handle a single IMAP message in most places Date: Fri, 28 May 2021 00:07:56 +0000 Message-Id: <20210528000757.20500-6-e@80x24.org> In-Reply-To: <20210528000757.20500-1-e@80x24.org> References: <20210528000757.20500-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: "lei import" can now import a single IMAP message via Likewise, "lei inspect" can show the blob information for UID URLs and "lei lcat" can display the blob without network access if imported. "lei lcat" also gets rid of some unused code and supports "blob:$OIDHEX" syntax as described in the comments (and used by our "text" output format). v2: enforce UID in URL, fail without --- lib/PublicInbox/LeiInspect.pm | 24 ++++++++++++++++++++++-- lib/PublicInbox/LeiLcat.pm | 33 ++++++++++++++++++++------------- lib/PublicInbox/LeiToMail.pm | 8 +++++++- lib/PublicInbox/NetReader.pm | 9 +++++++-- t/lei-import-imap.t | 15 +++++++++++++++ 5 files changed, 71 insertions(+), 18 deletions(-) diff --git a/lib/PublicInbox/LeiInspect.pm b/lib/PublicInbox/LeiInspect.pm index 46b9197f..7205979e 100644 --- a/lib/PublicInbox/LeiInspect.pm +++ b/lib/PublicInbox/LeiInspect.pm @@ -24,6 +24,19 @@ sub inspect_blob ($$) { $ent; } +sub inspect_imap_uid ($$) { + my ($lei, $uid_uri) = @_; + my $ent = {}; + my $lse = $lei->{lse} or return $ent; + my $lms = $lse->lms or return $ent; + my $oidhex = $lms->imap_oid($lei, $uid_uri); + if (ref(my $err = $oidhex)) { # art2folder error + $lei->qerr(@{$err->{qerr}}) if $err->{qerr}; + } + $ent->{$$uid_uri} = $oidhex; + $ent; +} + sub inspect_sync_folder ($$) { my ($lei, $folder) = @_; my $ent = {}; @@ -49,8 +62,15 @@ sub inspect1 ($$$) { my $ent; if ($item =~ /\Ablob:(.+)/) { $ent = inspect_blob($lei, $1); - } elsif ($item =~ m!\Aimaps?://!i || - $item =~ m!\A(?:maildir|mh):!i || -d $item) { + } elsif ($item =~ m!\Aimaps?://!i) { + require PublicInbox::URIimap; + my $uri = PublicInbox::URIimap->new($item); + if (defined($uri->uid)) { + $ent = inspect_imap_uid($lei, $uri); + } else { + $ent = inspect_sync_folder($lei, $item); + } + } elsif ($item =~ m!\A(?:maildir|mh):!i || -d $item) { $ent = inspect_sync_folder($lei, $item); } else { # TODO: more things return $lei->fail("$item not understood"); diff --git a/lib/PublicInbox/LeiLcat.pm b/lib/PublicInbox/LeiLcat.pm index 87729acf..c4712662 100644 --- a/lib/PublicInbox/LeiLcat.pm +++ b/lib/PublicInbox/LeiLcat.pm @@ -9,27 +9,31 @@ use strict; use v5.10.1; use PublicInbox::LeiViewText; use URI::Escape qw(uri_unescape); -use URI; use PublicInbox::MID qw($MID_EXTRACT); -sub lcat_redispatch { - my ($lei, $out, $op_p) = @_; - my $l = bless { %$lei }, ref($lei); - delete $l->{sock}; - $l->{''} = $op_p; # daemon only - eval { - $l->qerr("# updating $out"); - up1($l, $out); - $l->qerr("# $out done"); - }; - $l->err($@) if $@; +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}; + } + push @{$lei->{lcat_blob}}, $oidhex; # cf. LeiToMail->wq_atexit_child } sub extract_1 ($$) { my ($lei, $x) = @_; - if ($x =~ m!\b([a-z]+?://\S+)!i) { + 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->fail("# no UID= in $u"); + '""'; # blank query, using {lcat_blob} + } elsif ($x =~ m!\b([a-z]+?://\S+)!i) { my $u = $1; $u =~ s/[\>\]\)\,\.\;]+\z//; + require URI; $u = URI->new($u); my $p = $u->path; my $term; @@ -57,6 +61,9 @@ sub extract_1 ($$) { $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 + '""'; # blank query } else { undef; } diff --git a/lib/PublicInbox/LeiToMail.pm b/lib/PublicInbox/LeiToMail.pm index ad6b9439..b3aec50b 100644 --- a/lib/PublicInbox/LeiToMail.pm +++ b/lib/PublicInbox/LeiToMail.pm @@ -702,8 +702,14 @@ sub write_mail { # via ->wq_io_do sub wq_atexit_child { my ($self) = @_; - delete $self->{wcb}; my $lei = $self->{lei}; + if (!$self->{-wq_worker_nr} && $lei->{lcat_blob}) { + for my $oid (@{$lei->{lcat_blob}}) { + my $smsg = { blob => $oid, pct => 100 }; + write_mail($self, $smsg); + } + } + delete $self->{wcb}; $lei->{ale}->git->async_wait_all; my $nr = delete($lei->{-nr_write}) or return; return if $lei->{early_mua} || !$lei->{-progress} || !$lei->{pkt_op_p}; diff --git a/lib/PublicInbox/NetReader.pm b/lib/PublicInbox/NetReader.pm index 73b8b1cd..76d2fe62 100644 --- a/lib/PublicInbox/NetReader.pm +++ b/lib/PublicInbox/NetReader.pm @@ -469,7 +469,10 @@ E: $orig_uri UIDVALIDITY mismatch (got $r_uidval) EOF my $uri = $orig_uri->clone; + my $single_uid = $uri->uid; my ($itrk, $l_uid, $l_uidval) = itrk_last($self, $uri, $r_uidval, $mic); + $itrk = $l_uid = undef if defined($single_uid); + return <search("UID $l_uid:*")) { + if (defined $single_uid) { + $uids = [ $single_uid ]; + } elsif (!($uids = $mic->search("UID $l_uid:*"))) { return if $!{EINTR} && $self->{quit}; return "E: $uri UID SEARCH $l_uid:* error: $!"; } @@ -541,7 +546,7 @@ EOF } run_commit_cb($self); $itrk->update_last($r_uidval, $last_uid) if $itrk; - } until ($err || $self->{quit}); + } until ($err || $self->{quit} || defined($single_uid)); $err; } diff --git a/t/lei-import-imap.t b/t/lei-import-imap.t index 5283cc23..59d481d5 100644 --- a/t/lei-import-imap.t +++ b/t/lei-import-imap.t @@ -75,5 +75,20 @@ test_lei({ tmpdir => $tmpdir }, sub { lei_ok 'forget-mail-sync', $url; lei_ok 'ls-mail-sync'; unlike($lei_out, qr!\Q$host_port\E!, 'sync info gone after forget'); + my $uid_url = "$url/;UID=".$stats->{'uid.max'}; + lei_ok 'import', $uid_url; + lei_ok 'inspect', $uid_url; + $lei_out =~ /([a-f0-9]{40,})/ or + xbail 'inspect missed blob with UID URL'; + my $blob = $1; + lei_ok 'lcat', $uid_url; + like $lei_out, qr/^Subject: /sm, + 'lcat shows mail text with UID URL'; + like $lei_out, qr/\bblob:$blob\b/, 'lcat showed blob'; + my $orig = $lei_out; + lei_ok 'lcat', "blob:$blob"; + is($lei_out, $orig, 'lcat understands blob:...'); + ok(!lei('lcat', $url), "lcat doesn't work on IMAP URL w/o UID"); }); + done_testing;