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 |
|