output asked headers in the order they were asked; avoid header name spoofing by...
[hband-tools.git] / user-tools / mail-extract-raw-headers
blob72ff56ce59666167a5155b4779a709e341027333
1 #!/usr/bin/env perl
3 =pod
5 =head1 NAME
7 mail-extract-raw-headers - Get named headers from RFC822-format input.
9 =head1 SYNOPSIS
11 mail-extract-raw-headers [OPTIONS] <NAME> [<NAME> [...]]
13 =head1 OPTIONS
15 =over 4
17 =item -k, --keep-newlines, --keep-linefeeds
19 Keep linefeeds in multiline text.
21 =item -n, --header-names
23 Output the header name(s) too, not only the contents.
25 =back
27 =cut
30 use Getopt::Long qw/:config no_ignore_case bundling no_getopt_compat/;
31 use Pod::Usage;
32 use Data::Dumper;
33 no if ($] >= 5.018), 'warnings' => 'experimental::smartmatch';
35 $OptKeepLF = 0;
36 $OptNames = 0;
38 GetOptions(
39 'k|keep-newlines|keep-linefeeds' => \$OptKeepLF,
40 'n|header-names' => \$OptNames,
41 'help|?' => sub { pod2usage(-exitval=>0, -verbose=>99); },
42 ) or pod2usage(-exitval=>2, -verbose=>99);
44 if(not @ARGV)
46 pod2usage(-exitval=>2, -verbose=>99);
49 @asked_headers = map {lc} @ARGV;
52 sub getheaders($)
54 my $hname = lc shift;
55 my @return;
57 for my $header_ref (@Headers)
59 if(lc $header_ref->{"name"} eq $hname)
61 push @return, $header_ref->{"content"};
64 return @return;
67 %found_headers = ();
69 # read headers
70 while(<STDIN>)
72 if(/^\r?\n?$/)
74 # End of Headers
75 last;
78 # does not care line ending
79 s/\r?\n?$//;
81 if(my($header_name, $content) = /^(\S+?):[ ]?(.*)/)
83 if(lc $header_name ~~ @asked_headers)
85 my $header_name_pretty = $header_name =~ s/[^-]*/\L\u$&/gr;
86 my $header_hash = { "name" => $header_name, "pretty_name" => $header_name_pretty, "content" => $content, };
87 push @{$found_headers{lc $header_name}}, $header_hash;
88 $last_header_ref = $header_hash;
90 else
92 $last_header_ref = undef;
95 elsif(/^\s+(.*)/)
97 # it is a folded header
98 if(defined $last_header_ref)
100 $last_header_ref->{"content"} .= "\n" if $OptKeepLF;
101 $last_header_ref->{"content"} .= $1;
104 else
106 die "$0: can not parse line $.\n";
110 for my $asked_header (@asked_headers)
112 for my $header (@{$found_headers{$asked_header}})
114 # avoid non-whitespace character at the beginning of lines in the header content,
115 # so header names can not be spoofed.
116 my $safe_content = $header->{'content'} =~ s/\n([^\t ])/\n $1/gr;
118 if($OptNames)
120 printf "%s: %s\n", $header->{'name'}, $safe_content;
122 else
124 printf "%s\n", $safe_content;