line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Convert::BulkDecoder; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# Convert::BulkDecoder - Extract binary data from mail and news messages |
4
|
|
|
|
|
|
|
# RCS Info : $Id: BulkDecoder.pm,v 1.12 2005-06-19 17:35:38+02 jv Exp jv $ |
5
|
|
|
|
|
|
|
# Author : Johan Vromans |
6
|
|
|
|
|
|
|
# Created On : Wed Jan 29 16:59:58 2003 |
7
|
|
|
|
|
|
|
# Last Modified By: Johan Vromans |
8
|
|
|
|
|
|
|
# Last Modified On: Mon Jul 11 11:18:53 2022 |
9
|
|
|
|
|
|
|
# Update Count : 91 |
10
|
|
|
|
|
|
|
# Status : Unknown, Use with caution! |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
$VERSION = "1.041"; |
13
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
696
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
15
|
1
|
|
|
1
|
|
411
|
use integer; |
|
1
|
|
|
|
|
12
|
|
|
1
|
|
|
|
|
4
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub new { |
18
|
0
|
|
|
0
|
0
|
|
my ($pkg, %atts) = @_; |
19
|
0
|
0
|
|
|
|
|
$pkg = ref $pkg if ref $pkg; |
20
|
|
|
|
|
|
|
|
21
|
0
|
|
|
|
|
|
my $self = bless { |
22
|
|
|
|
|
|
|
# Set explicit defaults. |
23
|
|
|
|
|
|
|
tmpdir => "/var/tmp", |
24
|
|
|
|
|
|
|
destdir => "", |
25
|
|
|
|
|
|
|
force => 0, |
26
|
|
|
|
|
|
|
verbose => 1, |
27
|
|
|
|
|
|
|
crc => 1, |
28
|
|
|
|
|
|
|
md5 => 1, |
29
|
|
|
|
|
|
|
debug => 0, |
30
|
|
|
|
|
|
|
neat => \&_neat, |
31
|
|
|
|
|
|
|
}, $pkg; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Copy constructor attributes. |
34
|
0
|
|
|
|
|
|
foreach ( keys(%$self) ) { |
35
|
0
|
0
|
|
|
|
|
if ( defined($atts{$_}) ) { |
36
|
0
|
|
|
|
|
|
$self->{$_} = delete($atts{$_}); |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# Bail of if any remain. |
41
|
0
|
|
|
|
|
|
my $err = ""; |
42
|
0
|
|
|
|
|
|
foreach my $k ( sort keys %atts ) { |
43
|
0
|
|
|
|
|
|
$err .= $pkg . ": invalid constructor attribute: $k\n"; |
44
|
|
|
|
|
|
|
} |
45
|
0
|
0
|
|
|
|
|
die($err) if $err; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
# Polish. |
48
|
0
|
|
|
|
|
|
foreach ( $self->{destdir}, $self->{tmpdir} ) { |
49
|
0
|
0
|
|
|
|
|
next unless $_; |
50
|
0
|
|
|
|
|
|
$_ .= "/"; |
51
|
0
|
|
|
|
|
|
s;/+$;/;; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
0
|
0
|
|
|
|
|
if ( $self->{md5} ) { |
55
|
0
|
|
|
|
|
|
require Digest::MD5; |
56
|
0
|
|
|
|
|
|
$self->{_md5} = Digest::MD5->new; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
0
|
|
|
|
|
|
$self; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub decode { |
63
|
|
|
|
|
|
|
|
64
|
0
|
|
|
0
|
0
|
|
my ($self, $a) = @_; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# Try uudecode, or find out better. |
67
|
0
|
|
|
|
|
|
my $ret = $self->uudecode($a); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# MIME. |
70
|
0
|
0
|
|
|
|
|
$ret = $self->mimedecode($a) if $ret eq 'M'; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# yEnc. |
73
|
0
|
0
|
|
|
|
|
$ret = $self->ydecode($a) if $ret =~ /^Y/; |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# UNSUPPORTED -- FOR TESTING ONLY! |
76
|
|
|
|
|
|
|
# $ret = $self->ydecode_ydecode($a, $1) if $ret =~ /^Y(.*)/; |
77
|
|
|
|
|
|
|
|
78
|
0
|
|
|
|
|
|
$ret; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub uudecode { |
82
|
0
|
|
|
0
|
0
|
|
my ($self, $a) = @_; |
83
|
|
|
|
|
|
|
|
84
|
0
|
|
|
|
|
|
my $doing = 0; |
85
|
0
|
|
|
|
|
|
my $size = 0; |
86
|
0
|
|
|
|
|
|
my $name; |
87
|
0
|
|
|
|
|
|
$self->{result} = "EMPTY"; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# Process the message lines. |
90
|
0
|
|
|
|
|
|
foreach ( @$a ) { |
91
|
0
|
0
|
|
|
|
|
if ( $doing ) { # uudecoding... |
92
|
0
|
0
|
|
|
|
|
if ( /^end/ ) { |
93
|
0
|
|
|
|
|
|
close(OUT); |
94
|
0
|
0
|
|
|
|
|
$self->{md5} = $self->{_md5}->b64digest if $self->{md5}; |
95
|
0
|
|
|
|
|
|
$self->{size} = $size; |
96
|
0
|
|
|
|
|
|
$doing = 2; # done |
97
|
0
|
|
|
|
|
|
$self->{result} = "OK"; |
98
|
0
|
|
|
|
|
|
last; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
# Select lines to process. |
101
|
0
|
0
|
|
|
|
|
next if /[a-z]/; |
102
|
0
|
0
|
|
|
|
|
next unless int((((ord() - 32) & 077) + 2) / 3) |
103
|
|
|
|
|
|
|
== int(length() / 4); |
104
|
|
|
|
|
|
|
# Decode. |
105
|
0
|
|
|
|
|
|
my $t = unpack("u",$_); |
106
|
0
|
0
|
|
|
|
|
print OUT $t or die("print(".$self->{file}."): $!\n"); |
107
|
0
|
|
|
|
|
|
$size += length($t); |
108
|
0
|
0
|
|
|
|
|
$self->{_md5}->add($t) if $self->{md5}; |
109
|
0
|
|
|
|
|
|
next; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# Check for MIME. |
113
|
0
|
0
|
|
|
|
|
if ( m;^content-type:.*(image/|multipart);i ) { |
114
|
0
|
|
|
|
|
|
return 'M'; # MIME |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
0
|
0
|
|
|
|
|
if ( m/^=ybegin\s+.*\s+name=(.+)/i ) { |
118
|
0
|
|
|
|
|
|
return "Y$1"; # yEnc |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# Otherwise, search for the uudecode 'begin' line. |
122
|
0
|
0
|
|
|
|
|
if ( /^begin\s+\d+\s+(.+)$/ ) { |
123
|
0
|
|
|
|
|
|
$name = $self->{neat}->($1); |
124
|
0
|
|
|
|
|
|
$self->{type} = "U"; |
125
|
0
|
|
|
|
|
|
$self->{name} = $name; |
126
|
0
|
|
|
|
|
|
$self->{file} = $self->{destdir} . $name; |
127
|
0
|
|
|
|
|
|
$doing = 2; # Done |
128
|
|
|
|
|
|
|
warn("Decoding(UU) to ", $self->{file}, "\n") |
129
|
0
|
0
|
|
|
|
|
if $self->{verbose}; |
130
|
|
|
|
|
|
|
# Skip duplicates. |
131
|
|
|
|
|
|
|
# Note that testing for -s fails if it is a |
132
|
|
|
|
|
|
|
# notexisting symlink. |
133
|
0
|
0
|
0
|
|
|
|
if ( (-l $self->{file} || -s _ ) && !$self->{force} ) { |
|
|
|
0
|
|
|
|
|
134
|
0
|
|
|
|
|
|
$self->{size} = -s _; |
135
|
0
|
|
|
|
|
|
$self->{result} = "DUP"; |
136
|
0
|
|
|
|
|
|
last; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
open (OUT, ">".$self->{file}) |
140
|
0
|
0
|
|
|
|
|
or die("create(".$self->{file}."): $!\n"); |
141
|
0
|
|
|
|
|
|
binmode(OUT); |
142
|
0
|
|
|
|
|
|
$doing = 1; # Doing |
143
|
0
|
|
|
|
|
|
$self->{result} = "FAIL"; |
144
|
0
|
|
|
|
|
|
next; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
0
|
|
|
|
|
|
push(@{$self->{parts}}, |
148
|
|
|
|
|
|
|
{ type => $self->{type}, |
149
|
|
|
|
|
|
|
size => $self->{size}, |
150
|
|
|
|
|
|
|
md5 => $self->{md5}, |
151
|
|
|
|
|
|
|
result => $self->{result}, |
152
|
|
|
|
|
|
|
name => $self->{name}, |
153
|
0
|
|
|
|
|
|
file => $self->{file} }); |
154
|
0
|
|
|
|
|
|
return $self->{result}; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
my @crctab; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub ydecode { |
160
|
0
|
|
|
0
|
0
|
|
my ($self, $a) = @_; |
161
|
0
|
|
|
|
|
|
$self->{type} = "Y"; |
162
|
0
|
|
|
|
|
|
$self->{result} = "EMPTY"; |
163
|
|
|
|
|
|
|
|
164
|
0
|
0
|
0
|
|
|
|
_fill_crctab() unless @crctab || !$self->{crc}; |
165
|
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
|
my @lines = @$a; |
167
|
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
|
my ($ydec_part, $ydec_line, $ydec_size, $ydec_name, $ydec_pcrc, |
169
|
|
|
|
|
|
|
$ydec_begin, $ydec_end); |
170
|
0
|
|
|
|
|
|
my $pcrc; |
171
|
|
|
|
|
|
|
|
172
|
0
|
|
|
|
|
|
while ( $_ = shift(@lines) ) { |
173
|
|
|
|
|
|
|
# Newlines a fakes and should not be decoded. |
174
|
0
|
|
|
|
|
|
chomp; |
175
|
0
|
|
|
|
|
|
s/\r//g; |
176
|
|
|
|
|
|
|
# If we've started decoding $ydec_name will be set. |
177
|
0
|
0
|
|
|
|
|
if ( !$ydec_name ) { |
178
|
|
|
|
|
|
|
# Skip until beginning of yDecoded part. |
179
|
0
|
0
|
|
|
|
|
next unless /^=ybegin/; |
180
|
0
|
0
|
|
|
|
|
if ( / part=(\d+)/ ) { |
181
|
0
|
|
|
|
|
|
$ydec_part = $1; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
0
|
0
|
|
|
|
|
if ( / size=(\d+)/ ) { |
185
|
0
|
|
|
|
|
|
$self->{size} = $ydec_size = $1; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
else { |
188
|
0
|
|
|
|
|
|
die("Mandatory field 'size' missing\n"); |
189
|
|
|
|
|
|
|
} |
190
|
0
|
0
|
|
|
|
|
if ( / line=(\d+)/ ) { |
191
|
0
|
|
|
|
|
|
$ydec_line = $1; |
192
|
|
|
|
|
|
|
} |
193
|
0
|
0
|
|
|
|
|
if( / name=(.*)$/ ) { |
194
|
0
|
|
|
|
|
|
$ydec_name = $self->{neat}->($1); |
195
|
0
|
|
|
|
|
|
$self->{file} = $self->{destdir} . $ydec_name; |
196
|
0
|
|
|
|
|
|
$self->{name} = $ydec_name; |
197
|
0
|
0
|
0
|
|
|
|
if ( !defined($ydec_part) || $ydec_part == 1 ) { |
198
|
|
|
|
|
|
|
warn("Decoding(yEnc) to ", $self->{file}, "\n") |
199
|
0
|
0
|
|
|
|
|
if $self->{verbose}; |
200
|
0
|
0
|
|
|
|
|
if ( -s $self->{file} ) { |
201
|
0
|
0
|
|
|
|
|
if ( $self->{force} ) { |
202
|
0
|
|
|
|
|
|
unlink($self->{file}); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
else { |
205
|
0
|
|
|
|
|
|
$self->{size} = -s _; |
206
|
0
|
|
|
|
|
|
$self->{result} = "DUP"; |
207
|
0
|
|
|
|
|
|
last; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
else { |
213
|
0
|
|
|
|
|
|
die("Unknown attach name\n"); |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
# Multipart messages contain more information on. |
217
|
|
|
|
|
|
|
# the second line. |
218
|
0
|
0
|
|
|
|
|
if ( $ydec_part ) { |
219
|
0
|
|
|
|
|
|
$_ = shift(@lines); |
220
|
0
|
|
|
|
|
|
chomp; |
221
|
0
|
|
|
|
|
|
s/\r//g; |
222
|
0
|
0
|
|
|
|
|
if ( /^=ypart/ ) { |
223
|
0
|
0
|
|
|
|
|
if ( / begin=(\d+)/ ) { |
224
|
|
|
|
|
|
|
# We need this to check if the size of this message |
225
|
|
|
|
|
|
|
# is correct. |
226
|
0
|
|
|
|
|
|
$ydec_begin = $1; |
227
|
0
|
|
|
|
|
|
$pcrc = 0xffffffff; |
228
|
0
|
|
|
|
|
|
undef $ydec_pcrc; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
else { |
231
|
0
|
|
|
|
|
|
warn("No begin field found in part, ignoring\n"); |
232
|
0
|
|
|
|
|
|
undef $ydec_part; |
233
|
|
|
|
|
|
|
} |
234
|
0
|
0
|
|
|
|
|
if ( / end=(\d+)/ ) { |
235
|
|
|
|
|
|
|
# We need this to calculate the size of this message. |
236
|
0
|
|
|
|
|
|
$ydec_end = $1; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
else { |
239
|
0
|
|
|
|
|
|
warn("No end field found in part, ignoring"); |
240
|
0
|
|
|
|
|
|
undef $ydec_part; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
else { |
244
|
0
|
|
|
|
|
|
warn("Article described as multipart message, however ". |
245
|
|
|
|
|
|
|
"it doesn't seem that way\n"); |
246
|
0
|
|
|
|
|
|
undef $ydec_part; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
else { |
250
|
0
|
|
|
|
|
|
$pcrc = 0xffffffff; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
# If the $ydec_part is different from 1 |
254
|
|
|
|
|
|
|
# we need to open the file for appending. |
255
|
0
|
0
|
|
|
|
|
if ( -e $self->{file} ) { |
256
|
0
|
0
|
0
|
|
|
|
if ( defined($ydec_part) && $ydec_part != 1 ) { |
|
|
0
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# If we have a multipart message, the file exists |
258
|
|
|
|
|
|
|
# and we are not at the first part, we should just |
259
|
|
|
|
|
|
|
# open the file as an append. We assume that this is |
260
|
|
|
|
|
|
|
# the multipart we were already processing. |
261
|
|
|
|
|
|
|
#print "Opening $ydec_name for appending\n"; |
262
|
0
|
0
|
|
|
|
|
if ( !open(OUT, ">>".$self->{file}) ) { |
263
|
|
|
|
|
|
|
die("Couldn't open ".$self->{file}. |
264
|
0
|
|
|
|
|
|
" for appending: $!\n"); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
elsif ( !open(OUT, ">".$self->{file}) ) { |
268
|
0
|
|
|
|
|
|
die("Couldn't create ".$self->{file}.": $!\n"); |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
else { |
272
|
|
|
|
|
|
|
# File doesn't exist. We open it for writing O' so plain. |
273
|
0
|
0
|
0
|
|
|
|
if ( defined($ydec_part) && $ydec_part != 1 ) { |
274
|
0
|
|
|
|
|
|
die("Missing ".$self->{file}. " for appending: $!\n"); |
275
|
|
|
|
|
|
|
} |
276
|
0
|
0
|
|
|
|
|
if ( !open(OUT, ">".$self->{file}) ) { |
277
|
0
|
|
|
|
|
|
die("Couldn't create ".$self->{file}.": $!\n"); |
278
|
|
|
|
|
|
|
} |
279
|
0
|
|
|
|
|
|
$self->{result} = "FAIL"; |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
# Cancel any file translations. |
282
|
0
|
|
|
|
|
|
binmode(OUT); |
283
|
|
|
|
|
|
|
# Excellent.. We have determed all the info for this file we |
284
|
|
|
|
|
|
|
# need.. Skip till next line, this should contain the real |
285
|
|
|
|
|
|
|
# data. |
286
|
0
|
|
|
|
|
|
next; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# Looking for the end tag. |
290
|
0
|
0
|
|
|
|
|
if ( /^=yend/ ) { |
291
|
|
|
|
|
|
|
# We are done.. Check the sanity of article. |
292
|
|
|
|
|
|
|
# and unset $ydec_name in case that there are more |
293
|
|
|
|
|
|
|
# ydecoded files in the same article. |
294
|
0
|
|
|
|
|
|
$self->{result} = "OK"; |
295
|
0
|
0
|
|
|
|
|
if ( / part=(\d+)/ ) { |
296
|
0
|
0
|
|
|
|
|
if ( $ydec_part != $1 ) { |
297
|
0
|
|
|
|
|
|
die("Part number '$1' different from beginning part '$ydec_part'\n"); |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
} |
300
|
0
|
0
|
|
|
|
|
if ( / size=(\d+)/ ) { |
301
|
|
|
|
|
|
|
# Check size, but first calculate it. |
302
|
0
|
|
|
|
|
|
my $size; |
303
|
0
|
0
|
|
|
|
|
if ( defined($ydec_part) ) { |
304
|
0
|
|
|
|
|
|
$size = ($ydec_end - $ydec_begin + 1); |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
else { |
307
|
0
|
|
|
|
|
|
$size = $ydec_size; |
308
|
|
|
|
|
|
|
} |
309
|
0
|
0
|
|
|
|
|
if ( $1 != $size ) { |
310
|
0
|
|
|
|
|
|
die("Size '$1' different from beginning size '$size'\n"); |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
} |
313
|
0
|
0
|
0
|
|
|
|
if ( / pcrc32=([0-9a-f]+)/i && @crctab ) { |
314
|
0
|
0
|
0
|
|
|
|
if ( defined($ydec_pcrc) && ($ydec_pcrc != $1) ) { |
315
|
0
|
|
|
|
|
|
die("CRC '$1' different from beginning CRC '$ydec_pcrc'\n"); |
316
|
|
|
|
|
|
|
} |
317
|
0
|
|
|
|
|
|
$ydec_pcrc = hex($1); |
318
|
0
|
|
|
|
|
|
$pcrc = $pcrc ^ 0xffffffff; |
319
|
0
|
0
|
|
|
|
|
if ( $pcrc == $ydec_pcrc ) { |
320
|
|
|
|
|
|
|
warn("Part $ydec_part, checksum OK\n") |
321
|
0
|
0
|
|
|
|
|
if $self->{verbose}; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
else { |
324
|
0
|
|
|
|
|
|
warn(sprintf("Part $ydec_part, checksum mismatch, ". |
325
|
|
|
|
|
|
|
"got 0x%08x, expected 0x%08x\n", |
326
|
|
|
|
|
|
|
$pcrc, $ydec_pcrc)); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
} |
330
|
0
|
0
|
0
|
|
|
|
if ( !defined($ydec_part) && / crc32=([0-9a-f]+)/i && @crctab ) { |
|
|
|
0
|
|
|
|
|
331
|
0
|
|
|
|
|
|
$ydec_pcrc = hex($1); |
332
|
0
|
|
|
|
|
|
$pcrc = $pcrc ^ 0xffffffff; |
333
|
0
|
0
|
|
|
|
|
if ( $pcrc == $ydec_pcrc ) { |
334
|
|
|
|
|
|
|
warn("Checksum OK\n") |
335
|
0
|
0
|
|
|
|
|
if $self->{verbose}; |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
else { |
338
|
0
|
|
|
|
|
|
warn(sprintf("Checksum mismatch, ". |
339
|
|
|
|
|
|
|
"got 0x%08x, expected 0x%08x\n", |
340
|
|
|
|
|
|
|
$pcrc, $ydec_pcrc)); |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
} |
344
|
0
|
|
|
|
|
|
undef $ydec_name; |
345
|
|
|
|
|
|
|
# Dont encode the endline, we skip to the next line |
346
|
|
|
|
|
|
|
# in search for any more parts. |
347
|
0
|
|
|
|
|
|
next; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# If we got here, we are within an encoded article, an |
351
|
|
|
|
|
|
|
# we will take meassures to decode it. |
352
|
|
|
|
|
|
|
# We decode line by line. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# Decoder by jvromans@squirrel.nl. |
355
|
0
|
|
|
|
|
|
s/=(.)/chr(ord($1)+(256-64) & 255)/ge; |
|
0
|
|
|
|
|
|
|
356
|
0
|
|
|
|
|
|
tr{\000-\377}{\326-\377\000-\325}; |
357
|
|
|
|
|
|
|
|
358
|
0
|
|
|
|
|
|
my $data = $_; |
359
|
|
|
|
|
|
|
# CRC check code by jvromans@squirrel.nl. |
360
|
0
|
0
|
|
|
|
|
if ( @crctab ) { |
361
|
0
|
|
|
|
|
|
foreach ( split(//, $data) ) { |
362
|
0
|
|
|
|
|
|
$pcrc = $crctab[($pcrc^ord($_))&0xff] ^ (($pcrc >> 8) & 0x00ffffff); |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
0
|
|
|
|
|
|
print OUT $data; |
367
|
0
|
0
|
|
|
|
|
$self->{_md5}->add($data) if $self->{md5}; |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
0
|
|
|
|
|
|
close(OUT); |
371
|
0
|
0
|
|
|
|
|
$self->{md5} = $self->{_md5}->b64digest if $self->{md5}; |
372
|
0
|
|
|
|
|
|
push(@{$self->{parts}}, |
373
|
|
|
|
|
|
|
{ type => $self->{type}, |
374
|
|
|
|
|
|
|
size => $self->{size}, |
375
|
|
|
|
|
|
|
md5 => $self->{md5}, |
376
|
|
|
|
|
|
|
result => $self->{result}, |
377
|
|
|
|
|
|
|
name => $self->{name}, |
378
|
0
|
|
|
|
|
|
file => $self->{file} }); |
379
|
0
|
|
|
|
|
|
return $self->{result}; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub _fill_crctab { |
383
|
0
|
|
|
0
|
|
|
@crctab = |
384
|
|
|
|
|
|
|
( 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, |
385
|
|
|
|
|
|
|
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, |
386
|
|
|
|
|
|
|
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, |
387
|
|
|
|
|
|
|
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, |
388
|
|
|
|
|
|
|
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, |
389
|
|
|
|
|
|
|
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, |
390
|
|
|
|
|
|
|
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, |
391
|
|
|
|
|
|
|
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, |
392
|
|
|
|
|
|
|
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, |
393
|
|
|
|
|
|
|
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, |
394
|
|
|
|
|
|
|
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, |
395
|
|
|
|
|
|
|
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, |
396
|
|
|
|
|
|
|
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, |
397
|
|
|
|
|
|
|
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, |
398
|
|
|
|
|
|
|
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, |
399
|
|
|
|
|
|
|
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, |
400
|
|
|
|
|
|
|
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, |
401
|
|
|
|
|
|
|
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, |
402
|
|
|
|
|
|
|
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, |
403
|
|
|
|
|
|
|
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, |
404
|
|
|
|
|
|
|
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, |
405
|
|
|
|
|
|
|
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, |
406
|
|
|
|
|
|
|
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, |
407
|
|
|
|
|
|
|
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, |
408
|
|
|
|
|
|
|
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, |
409
|
|
|
|
|
|
|
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, |
410
|
|
|
|
|
|
|
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, |
411
|
|
|
|
|
|
|
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, |
412
|
|
|
|
|
|
|
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, |
413
|
|
|
|
|
|
|
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, |
414
|
|
|
|
|
|
|
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, |
415
|
|
|
|
|
|
|
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, |
416
|
|
|
|
|
|
|
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, |
417
|
|
|
|
|
|
|
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, |
418
|
|
|
|
|
|
|
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, |
419
|
|
|
|
|
|
|
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, |
420
|
|
|
|
|
|
|
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, |
421
|
|
|
|
|
|
|
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, |
422
|
|
|
|
|
|
|
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, |
423
|
|
|
|
|
|
|
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, |
424
|
|
|
|
|
|
|
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, |
425
|
|
|
|
|
|
|
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, |
426
|
|
|
|
|
|
|
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, |
427
|
|
|
|
|
|
|
); |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
sub ydecode_ydecode { |
431
|
0
|
|
|
0
|
0
|
|
my ($self, $a, $name) = @_; |
432
|
0
|
|
|
|
|
|
my $tmp = $self->{tmpdir} . "mfetch.$$."; |
433
|
|
|
|
|
|
|
|
434
|
0
|
|
|
|
|
|
$self->{type} = "Y"; |
435
|
0
|
0
|
|
|
|
|
if ( $name ) { |
436
|
0
|
|
|
|
|
|
$self->{file} = $self->{destdir} . $name; |
437
|
|
|
|
|
|
|
warn("Decoding(ydecode) to ", $self->{file}, "\n") |
438
|
0
|
0
|
|
|
|
|
if $self->{verbose}; |
439
|
0
|
0
|
|
|
|
|
if ( -s $self->{file} ) { |
440
|
0
|
0
|
|
|
|
|
if ( $self->{force} ) { |
441
|
0
|
|
|
|
|
|
unlink($self->{file}); |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
else { |
444
|
0
|
|
|
|
|
|
$self->{size} = -s _; |
445
|
0
|
|
|
|
|
|
$self->{result} = "DUP"; |
446
|
0
|
|
|
|
|
|
goto QXIT; |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
|
451
|
0
|
|
|
|
|
|
my @files; |
452
|
0
|
|
|
|
|
|
my $copy = 0; |
453
|
0
|
|
|
|
|
|
my $part; |
454
|
0
|
|
|
|
|
|
foreach ( @$a ) { |
455
|
0
|
0
|
0
|
|
|
|
if ( $copy && /^=yend/ ) { |
456
|
0
|
|
|
|
|
|
print TMP $_; |
457
|
0
|
|
|
|
|
|
close(TMP); |
458
|
0
|
|
|
|
|
|
$copy = 0; |
459
|
0
|
|
|
|
|
|
next; |
460
|
|
|
|
|
|
|
} |
461
|
0
|
0
|
0
|
|
|
|
if ( !$copy && /^=ybegin.*\s+part=(\d+)/ ) { |
462
|
0
|
|
|
|
|
|
my $file = sprintf("$tmp%03d", $part = $1); |
463
|
0
|
|
|
|
|
|
$files[$1-1] = $file; |
464
|
0
|
0
|
|
|
|
|
$copy = $1 if /\s+line=(\d+)/; |
465
|
0
|
0
|
|
|
|
|
$self->{size} = $1 if /\s+size=(\d+)/; |
466
|
0
|
0
|
|
|
|
|
$self->{name} = $1 if /\s+name=(.+)/; |
467
|
0
|
|
|
|
|
|
$self->{file} = $self->{destdir} . $self->{name}; |
468
|
0
|
0
|
|
|
|
|
if ( -s $self->{file} ) { |
469
|
0
|
0
|
|
|
|
|
if ( $self->{force} ) { |
470
|
0
|
|
|
|
|
|
unlink($self->{file}); |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
else { |
473
|
0
|
|
|
|
|
|
$self->{size} = -s _; |
474
|
0
|
|
|
|
|
|
$self->{result} = "DUP"; |
475
|
0
|
|
|
|
|
|
goto QXIT; |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
} |
478
|
0
|
0
|
|
|
|
|
open(TMP, ">$file") || die("$file: $!\n"); |
479
|
0
|
|
|
|
|
|
binmode(TMP); |
480
|
0
|
|
|
|
|
|
$copy++; |
481
|
|
|
|
|
|
|
} |
482
|
0
|
0
|
|
|
|
|
if ( $copy > 1 ) { # check length |
483
|
|
|
|
|
|
|
# If it starts with an unescaped period, the line will be |
484
|
|
|
|
|
|
|
# one too short. Add the period since ydecode requires it. |
485
|
0
|
0
|
0
|
|
|
|
if ( /^\./ && length($_) == $copy ) { |
486
|
0
|
|
|
|
|
|
$_ = ".$_"; |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
} |
489
|
0
|
0
|
|
|
|
|
print TMP $_ if $copy; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
system("ydecode", "-k", |
493
|
0
|
0
|
|
|
|
|
$self->{destdir} ? "--output=".$self->{destdir} : (), |
494
|
|
|
|
|
|
|
@files); |
495
|
|
|
|
|
|
|
|
496
|
0
|
|
|
|
|
|
$self->{result} = "FAIL"; |
497
|
0
|
0
|
|
|
|
|
if ( -s $self->{file} == $self->{size} ) { |
498
|
0
|
|
|
|
|
|
unlink(@files); |
499
|
0
|
0
|
|
|
|
|
if ( $self->{md5} ) { |
500
|
|
|
|
|
|
|
open(F, $self->{file}) |
501
|
0
|
0
|
|
|
|
|
or die($self->{file} . " (reopen) $!\n"); |
502
|
0
|
|
|
|
|
|
binmode(F); |
503
|
0
|
|
|
|
|
|
local($/) = undef; |
504
|
0
|
|
|
|
|
|
$self->{_md5}->add(); |
505
|
0
|
|
|
|
|
|
close(F); |
506
|
0
|
|
|
|
|
|
$self->{md5} = $self->{_md5}->b64digest; |
507
|
|
|
|
|
|
|
} |
508
|
0
|
|
|
|
|
|
$self->{result} = "OK"; |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
QXIT: |
511
|
0
|
|
|
|
|
|
push(@{$self->{parts}}, |
512
|
|
|
|
|
|
|
{ type => $self->{type}, |
513
|
|
|
|
|
|
|
size => $self->{size}, |
514
|
|
|
|
|
|
|
md5 => $self->{md5}, |
515
|
|
|
|
|
|
|
result => $self->{result}, |
516
|
|
|
|
|
|
|
name => $self->{name}, |
517
|
0
|
|
|
|
|
|
file => $self->{file} }); |
518
|
0
|
|
|
|
|
|
return $self->{result}; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
sub mimedecode { |
522
|
0
|
|
|
0
|
0
|
|
my ($self, $a) = @_; |
523
|
|
|
|
|
|
|
|
524
|
0
|
|
|
|
|
|
require MIME::Parser; |
525
|
|
|
|
|
|
|
|
526
|
0
|
|
|
|
|
|
$self->{type} = "M"; |
527
|
0
|
|
|
|
|
|
my $parser = new MIME::Parser; |
528
|
|
|
|
|
|
|
# Store everything in memory. |
529
|
0
|
|
|
|
|
|
$parser->output_to_core(1); |
530
|
0
|
|
|
|
|
|
my $e = $parser->parse_data($a); |
531
|
|
|
|
|
|
|
|
532
|
0
|
0
|
0
|
|
|
|
unless ( defined $e->{ME_Parts} && @{$e->{ME_Parts}} ) { |
|
0
|
|
|
|
|
|
|
533
|
0
|
|
|
|
|
|
$e->{ME_Parts} = [ $e ]; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
0
|
|
|
|
|
|
foreach my $part ( @{$e->{ME_Parts}} ) { |
|
0
|
|
|
|
|
|
|
537
|
0
|
|
|
|
|
|
my $name; |
538
|
0
|
|
|
|
|
|
foreach ( 'Content-Type', 'Content-Disposition' ) { |
539
|
|
|
|
|
|
|
|
540
|
0
|
|
|
|
|
|
my $ct = $part->{mail_inet_head}->{mail_hdr_hash}->{$_}; |
541
|
0
|
0
|
0
|
|
|
|
next unless defined $ct && defined ($ct = ${$ct->[0]}); |
|
0
|
|
|
|
|
|
|
542
|
0
|
0
|
|
|
|
|
if ( $ct =~ m{((file)?name)="([^"]+)"}i ) { |
543
|
0
|
|
|
|
|
|
$name = $self->{name} = $self->{neat}->($3); |
544
|
0
|
|
|
|
|
|
$self->{file} = $self->{destdir} . $name; |
545
|
|
|
|
|
|
|
warn("Decoding(MIME) to ", $self->{file}, "\n") |
546
|
0
|
0
|
|
|
|
|
if $self->{verbose}; |
547
|
0
|
0
|
0
|
|
|
|
if ( -s $self->{file} && !$self->{force} ) { |
548
|
0
|
|
|
|
|
|
$self->{size} = -s _; |
549
|
0
|
|
|
|
|
|
$self->{result} = "DUP"; |
550
|
0
|
|
|
|
|
|
push(@{$self->{parts}}, |
551
|
|
|
|
|
|
|
{ type => $self->{type}, |
552
|
|
|
|
|
|
|
size => $self->{size}, |
553
|
|
|
|
|
|
|
result => $self->{result}, |
554
|
|
|
|
|
|
|
name => $self->{name}, |
555
|
0
|
|
|
|
|
|
file => $self->{file} }); |
556
|
0
|
|
|
|
|
|
next; |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
# Skip body. |
562
|
0
|
0
|
|
|
|
|
next unless $name; |
563
|
0
|
0
|
|
|
|
|
next if $name eq $self->{destdir}."body"; |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
# Skip duplicates. |
566
|
0
|
0
|
0
|
|
|
|
if ( -s $name && !$self->{force} ) { |
567
|
0
|
|
|
|
|
|
$self->{size} = -s _; |
568
|
0
|
|
|
|
|
|
$self->{result} = "DUP"; |
569
|
0
|
|
|
|
|
|
push(@{$self->{parts}}, |
570
|
|
|
|
|
|
|
{ type => $self->{type}, |
571
|
|
|
|
|
|
|
size => $self->{size}, |
572
|
|
|
|
|
|
|
result => $self->{result}, |
573
|
|
|
|
|
|
|
name => $self->{name}, |
574
|
0
|
|
|
|
|
|
file => $self->{file} }); |
575
|
0
|
|
|
|
|
|
next; |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
# Store it. |
579
|
0
|
|
|
|
|
|
my $bh = $part->{ME_Bodyhandle}; |
580
|
0
|
0
|
0
|
|
|
|
if ( $bh && defined $bh->{MBC_Data} && open (OUT, ">".$self->{file}) ) { |
|
|
|
0
|
|
|
|
|
581
|
0
|
|
|
|
|
|
binmode(OUT); |
582
|
0
|
|
|
|
|
|
my $size = 0; |
583
|
0
|
|
|
|
|
|
foreach ( @{$bh->{MBC_Data}} ) { |
|
0
|
|
|
|
|
|
|
584
|
0
|
|
|
|
|
|
print OUT $_; |
585
|
0
|
0
|
|
|
|
|
$self->{_md5}->add($_) if $self->{md5}; |
586
|
0
|
|
|
|
|
|
$size += length($_); |
587
|
|
|
|
|
|
|
} |
588
|
0
|
|
|
|
|
|
close (OUT); |
589
|
0
|
0
|
|
|
|
|
$self->{md5} = $self->{_md5}->b64digest if $self->{md5}; |
590
|
0
|
|
|
|
|
|
$self->{size} = $size; |
591
|
0
|
|
|
|
|
|
$self->{result} = "OK"; |
592
|
0
|
|
|
|
|
|
push(@{$self->{parts}}, |
593
|
|
|
|
|
|
|
{ type => $self->{type}, |
594
|
|
|
|
|
|
|
size => $self->{size}, |
595
|
|
|
|
|
|
|
md5 => $self->{md5}, |
596
|
|
|
|
|
|
|
result => $self->{result}, |
597
|
|
|
|
|
|
|
name => $self->{name}, |
598
|
0
|
|
|
|
|
|
file => $self->{file} }); |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
else { |
601
|
0
|
|
|
|
|
|
$self->{result} = "FAIL"; |
602
|
0
|
|
|
|
|
|
push(@{$self->{parts}}, |
603
|
|
|
|
|
|
|
{ type => $self->{type}, |
604
|
|
|
|
|
|
|
result => $self->{result}, |
605
|
|
|
|
|
|
|
name => $self->{name}, |
606
|
0
|
|
|
|
|
|
file => $self->{file} }); |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
# Return values for the first file. |
611
|
0
|
|
|
|
|
|
while ( my($k,$v) = each(%{$self->{parts}->[0]}) ) { |
|
0
|
|
|
|
|
|
|
612
|
0
|
|
|
|
|
|
$self->{$k} = $v; |
613
|
|
|
|
|
|
|
} |
614
|
0
|
|
|
|
|
|
return $self->{result}; |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
sub _neat { |
619
|
0
|
|
|
0
|
|
|
local ($_) = @_; |
620
|
0
|
|
|
|
|
|
s/^\[a-z]://i; |
621
|
0
|
|
|
|
|
|
s/^.*?([^\\]+$)/$1/; |
622
|
|
|
|
|
|
|
# Spaces and unprintables to _. |
623
|
0
|
|
|
|
|
|
s/\s+/_/g; |
624
|
0
|
|
|
|
|
|
s/\.\.+/./g; |
625
|
0
|
|
|
|
|
|
s/[\0-\040'`"\177-\240\/]/_/g; |
626
|
|
|
|
|
|
|
# Remove leading dots. |
627
|
0
|
|
|
|
|
|
s/^\.+//; |
628
|
0
|
|
|
|
|
|
$_; |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
1; |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
__END__ |