| #!/usr/bin/perl |
| # |
| # maildir-scan-headers - grep a set of mail files for patterns, and list |
| # all headers specified. |
| |
| sub usage { |
| die "usage: maildir-scan-headers [-h headers] [--headers headers] |
| [-re regexp] [-i] [-raw] [-sort] fileordir1 fileordir2 ... \n"; |
| |
| } |
| |
| my $expect_attachment = 0; |
| my $wanted = ''; |
| my $regexp = ''; |
| my $sort = 0; |
| my $casei = 0; |
| my $raw = 0; |
| my @files = (); |
| |
| use Getopt::Long qw(:config no_ignore_case); |
| GetOptions( |
| "headers|h=s" => \$wanted, |
| "re=s" => \$regexp, |
| "casei|i" => \$casei, |
| "raw" => \$raw, |
| "sort" => \$sort, |
| 'help' => \&usage, |
| '<>' => sub { push (@files, $_[0]); } |
| ); |
| |
| $wanted =~ s/[ ,\|;:]+/\|/gs; |
| if ($regexp) { |
| $wanted = qr{${regexp}}; |
| } elsif ($casei) { |
| $wanted = qr{(?:$wanted)}i; |
| } else { |
| $wanted = qr{(?:$wanted)}; |
| } |
| |
| foreach my $file (@files) { |
| if (-d $file) { |
| use File::Find; |
| File::Find::find (sub { |
| -f $_ and do_file ($File::Find::name); |
| }, $file); |
| } else { |
| do_file ($file); |
| } |
| } |
| |
| sub do_file { |
| my $file = shift; |
| return if ($file =~ /\/\,\d/); # MH deleted mail |
| |
| open (IN, "<$file") or warn "cannot read $file\n"; |
| |
| my $hdrs = ''; |
| while (<IN>) |
| { |
| if (/^$/) { last; } |
| |
| if ($expect_attachment && !$raw && /X-Spam-Flag: YES/) { |
| while (<IN>) { |
| /^Content-Description: original message before SpamAssassin/ and last; |
| } |
| $_ = <IN>; $_ = <IN>; $_ = <IN>; |
| $hdrs = ''; |
| next; |
| } |
| |
| $hdrs .= $_; |
| } |
| |
| close IN; |
| |
| |
| $hdrs =~ s/\n([ \t])/\\n$1/gs; # folding |
| $hdrs =~ s/\t/\\t/gs; # tabs |
| $hdrs =~ s/\|/[pipe]/gs; # pipe chars |
| |
| my @ok = ($hdrs =~ /^(${wanted}:.*)$/gom); |
| if ($sort) { @ok = sort @ok; } |
| $hdrs = join ("|", @ok); |
| |
| return unless $hdrs =~ /\S/; |
| print "$file $hdrs\n"; |
| } |