-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathmdbox-recover.pl
executable file
·84 lines (77 loc) · 2.33 KB
/
mdbox-recover.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#!/usr/bin/env perl
use strict;
# Usage mdbox-recover.pl m.123
# Try to extract as many mails from the input mdbox file as possible
# and write them to separate msg.* files in the current directory.
my $STATE_META = 0;
my $STATE_BODY = 1;
my $BYTES_MAX = 4096;
my $offset = 0;
my ($fin, $fout);
my $state = $STATE_META;
my $msgnum = 1;
open($fin, "<$ARGV[0]") || die "$!";
open($fout, ">msg.$msgnum") || die "$!";
while (1) {
my $data;
seek($fin, $offset, 0);
my $bytes = read($fin, $data, $BYTES_MAX);
last if ($bytes <= 0);
my $idx = index($data, "\001\002N 00000000");
my $idx2 = index($data, "\n\001\003\n");
if ($idx != -1 && $idx + 50 > $bytes && $bytes == $BYTES_MAX) {
$bytes -= 50;
$data = substr($data, 0, $bytes);
$idx = -1;
}
if ($idx != -1 && ($idx2 == -1 || $idx < $idx2)) {
# pre-magic found. skip over it and we'll start writing the mail
$idx2 = index(substr($data, $idx), "\n");
#print "begin $offset $idx $idx2\n";
if ($idx2 != -1) {
# successfully skipped over the metadata headers
$bytes = $idx + $idx2 + 1;
if ($state == $STATE_META) {
$state = $STATE_BODY;
} else {
# end of metadata block missing, finish the previous mail
print $fout substr($data, 0, $idx);
}
} else {
# truncated / broken data? just keep writing to previous file
print $fout $data;
}
} elsif ($idx2 == -1 && $state == $STATE_META && $bytes < $BYTES_MAX) {
# trailing metadata in file, skip
} else {
$idx = $idx2;
if ($idx + 50 > $bytes && $bytes == $BYTES_MAX) {
# check again in next loop
$idx = -1;
}
if ($idx == -1 && $bytes == $BYTES_MAX) {
# leave some extra to find the pre/post magics
$bytes -= 50;
$data = substr($data, 0, $bytes);
}
#print "end $offset $bytes $idx\n" if ($idx >= 0);
if ($idx != -1 && substr($data, $idx + 4, 2) =~ /[ZR][0-9a-f]/) {
# end of message, start new one
#print "ok ".substr($data, $idx + 4, 100)."\n";
$bytes = $idx + 4;
print $fout substr($data, 0, $idx);
close $fout; $msgnum++;
open($fout, ">msg.$msgnum") || die "$!";
$state = $STATE_META;
} else {
# continue writing to file
print $fout $data;
}
}
$offset += $bytes;
}
if (tell($fout) == 0) {
unlink("msg.$msgnum");
}
close $fin;
close $fout;