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-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 E789F1FBD9 for ; Wed, 10 Jun 2020 07:05:22 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 20/82] imap: do not include ".PEEK" in responses Date: Wed, 10 Jun 2020 07:04:17 +0000 Message-Id: <20200610070519.18252-21-e@yhbt.net> In-Reply-To: <20200610070519.18252-1-e@yhbt.net> References: <20200610070519.18252-1-e@yhbt.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: They're not specified in RFC 3501 for responses, and at least mutt fails to handle it. --- lib/PublicInbox/IMAP.pm | 32 ++++++++++++++------------------ t/imap.t | 12 ++++++------ t/imapd.t | 14 ++++++++++---- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/lib/PublicInbox/IMAP.pm b/lib/PublicInbox/IMAP.pm index 2aa7ab346c1..54c616eee2f 100644 --- a/lib/PublicInbox/IMAP.pm +++ b/lib/PublicInbox/IMAP.pm @@ -33,9 +33,6 @@ die "neither Email::Address::XS nor Mail::Address loaded: $@" if !$Address; sub LINE_MAX () { 512 } # does RFC 3501 have a limit like RFC 977? my %FETCH_NEED_BLOB = ( # for future optimization - 'BODY.PEEK[HEADER]' => 1, - 'BODY.PEEK[TEXT]' => 1, - 'BODY.PEEK[]' => 1, 'BODY[HEADER]' => 1, 'BODY[TEXT]' => 1, 'BODY[]' => 1, @@ -388,8 +385,8 @@ sub uid_fetch_cb { # called by git->cat_async $want->{INTERNALDATE} and $self->msg_more(' INTERNALDATE "'.$smsg->internaldate.'"'); $want->{FLAGS} and $self->msg_more(' FLAGS ()'); - for ('RFC822', 'BODY[]', 'BODY.PEEK[]') { - next unless $want->{$_}; + for ('RFC822', 'BODY[]') { + $want->{$_} or next; $self->msg_more(" $_ {".length($$bref)."}\r\n"); $self->msg_more($$bref); } @@ -399,14 +396,14 @@ sub uid_fetch_cb { # called by git->cat_async $want->{ENVELOPE} and $self->msg_more(' ENVELOPE '.eml_envelope($eml)); - for my $f ('RFC822.HEADER', 'BODY[HEADER]', 'BODY.PEEK[HEADER]') { - next unless $want->{$f}; - $self->msg_more(" $f {".length(${$eml->{hdr}})."}\r\n"); + for ('RFC822.HEADER', 'BODY[HEADER]') { + $want->{$_} or next; + $self->msg_more(" $_ {".length(${$eml->{hdr}})."}\r\n"); $self->msg_more(${$eml->{hdr}}); } - for my $f ('RFC822.TEXT', 'BODY[TEXT]') { - next unless $want->{$f}; - $self->msg_more(" $f {".length($$bref)."}\r\n"); + for ('RFC822.TEXT', 'BODY[TEXT]') { + $want->{$_} or next; + $self->msg_more(" $_ {".length($$bref)."}\r\n"); $self->msg_more($$bref); } $want->{BODYSTRUCTURE} and @@ -567,18 +564,16 @@ sub partial_prepare ($$$) { # recombine [ "BODY[1.HEADER.FIELDS", "(foo", "bar)]" ] # back to: "BODY[1.HEADER.FIELDS (foo bar)]" - return unless $att =~ /\ABODY(?:\.PEEK)?\[/s; + return unless $att =~ /\ABODY\[/s; until (rindex($att, ']') >= 0) { my $next = shift @$want or return; $att .= ' ' . uc($next); } - if ($att =~ /\ABODY(?:\.PEEK)?\[ - ([0-9]+(?:\.[0-9]+)*)? # 1 - section_idx - (?:\.(HEADER|MIME|TEXT))? # 2 - section_name + if ($att =~ /\ABODY\[([0-9]+(?:\.[0-9]+)*)? # 1 - section_idx + (?:\.(HEADER|MIME|TEXT))? # 2 - section_name \](?:<([0-9]+)(?:\.([0-9]+))?>)?\z/sx) { # 3, 4 $partial->{$att} = [ \&partial_body, $1, $2, $3, $4 ]; - } elsif ($att =~ /\ABODY(?:\.PEEK)?\[ - (?:([0-9]+(?:\.[0-9]+)*)\.)? # 1 - section_idx + } elsif ($att =~ /\ABODY\[(?:([0-9]+(?:\.[0-9]+)*)\.)? # 1 - section_idx (?:HEADER\.FIELDS(\.NOT)?)\x20 # 2 \(([A-Z0-9\-\x20]+)\) # 3 - hdrs \](?:<([0-9]+)(?:\.([0-9]+))?>)?\z/sx) { # 4 5 @@ -623,6 +618,7 @@ sub fetch_common ($$$$) { my (%partial, %want); while (defined(my $att = shift @$want)) { $att = uc($att); + $att =~ s/\ABODY\.PEEK\[/BODY\[/; # we're read-only my $x = $FETCH_ATT{$att}; if ($x) { %want = (%want, %$x); @@ -633,7 +629,7 @@ sub fetch_common ($$$$) { # stabilize partial order for consistency and ease-of-debugging: if (scalar keys %partial) { - $want{-partial} = [ map { + $want{-partial} = [ map {; [ $_, @{$partial{$_}} ] } sort keys %partial ]; } diff --git a/t/imap.t b/t/imap.t index 9b64f1646c6..fe6352b678c 100644 --- a/t/imap.t +++ b/t/imap.t @@ -27,11 +27,11 @@ use PublicInbox::IMAPD; { my $partial_prepare = \&PublicInbox::IMAP::partial_prepare; my $x = {}; - my $r = $partial_prepare->($x, [], my $p = 'BODY.PEEK[9]'); + my $r = $partial_prepare->($x, [], my $p = 'BODY[9]'); ok($r, $p); - $r = $partial_prepare->($x, [], $p = 'BODY.PEEK[9]<5>'); + $r = $partial_prepare->($x, [], $p = 'BODY[9]<5>'); ok($r, $p); - $r = $partial_prepare->($x, [], $p = 'BODY.PEEK[9]<5.1>'); + $r = $partial_prepare->($x, [], $p = 'BODY[9]<5.1>'); ok($r, $p); $r = $partial_prepare->($x, [], $p = 'BODY[1.1]'); ok($r, $p); @@ -47,9 +47,9 @@ use PublicInbox::IMAPD; my $partial_hdr_get = \&PublicInbox::IMAP::partial_hdr_get; my $partial_hdr_not = \&PublicInbox::IMAP::partial_hdr_not; is_deeply($x, { - 'BODY.PEEK[9]' => [ $partial_body, 9, undef, undef, undef ], - 'BODY.PEEK[9]<5>' => [ $partial_body, 9, undef, 5, undef ], - 'BODY.PEEK[9]<5.1>' => [ $partial_body, 9, undef, 5, 1 ], + 'BODY[9]' => [ $partial_body, 9, undef, undef, undef ], + 'BODY[9]<5>' => [ $partial_body, 9, undef, 5, undef ], + 'BODY[9]<5.1>' => [ $partial_body, 9, undef, 5, 1 ], 'BODY[1.1]' => [ $partial_body, '1.1', undef, undef, undef ], 'BODY[HEADER.FIELDS (DATE FROM)]' => [ $partial_hdr_get, undef, 'DATE FROM', undef, undef ], diff --git a/t/imapd.t b/t/imapd.t index fc90948e182..1ec0d5c370f 100644 --- a/t/imapd.t +++ b/t/imapd.t @@ -317,11 +317,17 @@ is(scalar keys %$ret, 3, 'got all 3 messages'); my @cmd = qw(-learn rm --all); run_script(\@cmd, $env, $rdr) or BAIL_OUT('-learn rm'); } -my $r2 = $mic->fetch_hash('1:*', 'RFC822') or BAIL_OUT "FETCH $@"; +my $r2 = $mic->fetch_hash('1:*', 'BODY.PEEK[]') or BAIL_OUT "FETCH $@"; is(scalar keys %$r2, 3, 'still got all 3 messages'); -like($r2->{1}->{RFC822}, qr/dummy message #1/, 'got dummy message 1'); -is($r2->{2}->{RFC822}, $ret->{2}->{RFC822}, 'message 2 unchanged'); -is($r2->{3}->{RFC822}, $ret->{3}->{RFC822}, 'message 3 unchanged'); +like($r2->{1}->{'BODY[]'}, qr/dummy message #1/, 'got dummy message 1'); +is($r2->{2}->{'BODY[]'}, $ret->{2}->{RFC822}, 'message 2 unchanged'); +is($r2->{3}->{'BODY[]'}, $ret->{3}->{RFC822}, 'message 3 unchanged'); +$r2 = $mic->fetch_hash(2, 'BODY.PEEK[HEADER.FIELDS (message-id)]') + or BAIL_OUT "FETCH $@"; +is($r2->{2}->{'BODY[HEADER.FIELDS (MESSAGE-ID)]'}, + 'Message-ID: <20200418222508.GA13918@dcvr>'."\r\n\r\n", + 'BODY.PEEK[HEADER.FIELDS ...] drops .PEEK'); + ok($mic->logout, 'logged out'); $td->kill;