hs12
changeset 16 0e1c0994309a
parent 15 9482d3366306
child 17 e9aa9cb9f61f
equal deleted inserted replaced
15:9482d3366306 16:0e1c0994309a
     1 #! /usr/bin/perl
       
     2 # $Id$
       
     3 # $URL$
       
     4 #
       
     5 # ** Just proof of concept ** to see if we really need to decode all the
       
     6 # mime parts.
       
     7 #
       
     8 
       
     9 use strict;
       
    10 use warnings;
       
    11 
       
    12 use Fatal qw(:void select);
       
    13 use File::Temp qw(tempfile);
       
    14 use if $ENV{DEBUG} => "Smart::Comments";
       
    15 use FindBin qw($Bin);
       
    16 
       
    17 sub print_message(*@);
       
    18 sub read_message();
       
    19 sub pass_mime($$);
       
    20 sub forward_to_boundary($*);
       
    21 sub read_header(*);
       
    22 
       
    23 #
       
    24 sub process($*;@);
       
    25 my $confdir = -f "$Bin/.build" ? $Bin : "/etc/$0";
       
    26 my @mimes;
       
    27 
       
    28 $SIG{__WARN__} = sub { print STDERR "### ", @_ };
       
    29 
       
    30 MAIN: {
       
    31 
       
    32 	open ( my $fh, "< $confdir/mimes.conf")
       
    33 		or warn "can't read config!\n";
       
    34 	my @mimes = map { chomp; $_ } grep !/(?:^\s*#|^\s*$)/, <$fh>;
       
    35 	
       
    36     # create an r/o tmp file containing the message  for sequential
       
    37     # processing and optional failback in face of some processing error
       
    38     my $message = read_message();
       
    39 
       
    40     # during processing everything is printed into some tmp file
       
    41     # - this way we can abort processing at any time and just send
       
    42     # the above temporary file down the river
       
    43     my $tmpout = tempfile();
       
    44     my $stdout = select $tmpout;
       
    45 
       
    46     # now we start processing but at the beginning - of course
       
    47     seek($message, 0, 0);
       
    48     process(\@mimes, $message, boundary => undef);
       
    49 
       
    50     # everything is done, probably some rest is still unprocessed (some
       
    51     # epilogue, but this shouldn't be a problem at all
       
    52     {
       
    53         local $/ = \10240;
       
    54         if ($tmpout) {
       
    55             seek($tmpout, 0, 0);
       
    56             select $stdout;
       
    57             print while <$tmpout>;
       
    58         }
       
    59         print while <$message>;
       
    60     }
       
    61 
       
    62     exit 0;
       
    63 }
       
    64 
       
    65 sub print_message(*@) {
       
    66     my ($m, %arg) = @_;
       
    67 
       
    68     while (<$m>) {
       
    69         print;
       
    70         last if $arg{to} and /^--\Q$arg{to}\E/;
       
    71     }
       
    72 }
       
    73 
       
    74 sub process($*;@) {
       
    75     my ($mimes, $m, %arg)    = @_;
       
    76     my ($header, %header) = read_header($m);
       
    77     my ($type, $boundary);
       
    78 
       
    79     if ($header{"content-type"}) {
       
    80         ($type) = ($header{"content-type"} =~ /^([^;]*)/);
       
    81         (undef, $boundary)
       
    82             = ($header{"content-type"} =~ /boundary=(['"])(.*?)\1/);
       
    83         ### h{content-type}:  $header{"content-type"}
       
    84         ### type:	      $type
       
    85         ### bound:            $boundary
       
    86     }
       
    87 
       
    88     $boundary ||= $arg{boundary};
       
    89 
       
    90     if (not $type or pass_mime($type, $mimes)) {
       
    91         warn "passing: " . ($type ? $type : "no mime type") . "\n";
       
    92         print $header;
       
    93         print_message($m, to => $boundary);
       
    94         return;
       
    95     }
       
    96 
       
    97     if ($type =~ m{^multipart/}) {
       
    98         warn "forward to next multipart boundary: $boundary\n";
       
    99         print $header;
       
   100         print_message($m, to => $boundary);
       
   101 
       
   102         while (not eof($m)) {
       
   103             process($mimes, $m, boundary => $boundary);
       
   104         }
       
   105 
       
   106 	return;
       
   107     }
       
   108 
       
   109     warn "removed: $type\n";
       
   110 
       
   111     my ($eol) = ($header =~ /(\s*)$/);
       
   112     $header =~ s/\s*$//;
       
   113     $header =~ s/^/-- /gm;
       
   114 
       
   115     print "Content-Type: text/plain" . $eol x 2
       
   116 	. "Content removed (" . localtime() . ")$eol"
       
   117 	. $header
       
   118 	. $eol;
       
   119 
       
   120     while (<$m>) {
       
   121 	if (/^--\Q$boundary\E/) {
       
   122 	    print;
       
   123 	    last;
       
   124 	}
       
   125     }
       
   126 
       
   127 }
       
   128 
       
   129 sub pass_mime($$) {
       
   130 	my ($type, $mimes) = @_;
       
   131     local $_ = $type;
       
   132 	my $re = join "|", map { $a = $_; $a =~ s/([^\da-z])/\\$1/gi; $a } @$mimes;
       
   133 	return m{$re};
       
   134 }
       
   135 
       
   136 sub read_message() {
       
   137     my $tmp = tempfile();
       
   138 
       
   139     local $/ = \102400;
       
   140     print {$tmp} $_ while <>;
       
   141     chmod 0400, $tmp or die "Can't fchmod on tmpfile: $!\n";
       
   142 
       
   143     return $tmp;
       
   144 }
       
   145 
       
   146 # in:	current message file handle
       
   147 # out:	($orignal_header, %parsed_header)
       
   148 sub read_header(*) {
       
   149     my ($msg) = @_;
       
   150     my $h = "";
       
   151 
       
   152     while (<$msg>) {
       
   153         $h .= $_;
       
   154         last if /^\s*$/m;
       
   155     }
       
   156 
       
   157     $_ = $h;    # unmodified header (excl. $from)
       
   158 
       
   159     ### $_
       
   160 
       
   161     s/\r?\n\s+(?=\S)/ /gm;    # continuation lines
       
   162     s/^(\S+):/\L$1:/gm;       # header fields to lower case
       
   163 
       
   164     return ($h,
       
   165             map { ($a = $_) =~ s/\s*$//; $a }
       
   166                 ":unix_from:" => split(/^(\S+):\s*/m, $_));
       
   167 }
       
   168 __END__
       
   169 # vim:ts=4