]> Sergey Matveev's repositories - public-inbox.git/commitdiff
imap: do not include ".PEEK" in responses
authorEric Wong <e@yhbt.net>
Wed, 10 Jun 2020 07:04:17 +0000 (07:04 +0000)
committerEric Wong <e@yhbt.net>
Sat, 13 Jun 2020 07:55:45 +0000 (07:55 +0000)
They're not specified in RFC 3501 for responses, and at least
mutt fails to handle it.

lib/PublicInbox/IMAP.pm
t/imap.t
t/imapd.t

index 2aa7ab346c1fb1462cdc3391906d513047e84796..54c616eee2fd307f39a102384be59dcd9416f99e 100644 (file)
@@ -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 ];
        }
index 9b64f1646c69f4e062ac222bef2434fb5a0d48e1..fe6352b678c32fe59a810a5f87d98df1382e926b 100644 (file)
--- 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 ],
index fc90948e1829c0b67ab1ffea74923e72ea914b92..1ec0d5c370fcd6220e2c95d5f527f605bf598d19 100644 (file)
--- 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;