source: ProjectBuilder/projects/md2mb/devel/md2mb/bin/md2mb.pl@ 1458

Last change on this file since 1458 was 1458, checked in by ebaudrez, 12 years ago

make $touch 1 by default

File size: 10.1 KB
Line 
1#!/usr/bin/perl -w
2
3=head1 NAME
4
5md2mb.pl - Import a maildir kmail environment into a thunderbird one
6
7=cut
8
9use strict;
10use File::Find;
11use File::Copy;
12use File::Basename;
13use File::Path;
14use File::Glob ':glob';
15use Getopt::Long;
16use Pod::Usage;
17use List::Util qw(first);
18
19# settings
20my $cmd = 'formail';
21my $debug = 0;
22my $file = 0; # is the newroot a file (1) or a dir (0) ?
23my $help = 0;
24my $man = 0;
25my $oldroot = first { -d } "$ENV{HOME}/.Mail", "$ENV{HOME}/Mail";
26my @default_profiles = bsd_glob("$ENV{HOME}/.thunderbird/*.default");
27my $profile = shift @default_profiles;
28# if there is more than one default profile (quite unlikely, but you never
29# know), unset $profile again and let the user resolve this
30if (@default_profiles) { undef $profile }
31my $subdir;
32my $touch = 1;
33
34# parse command-line options
35GetOptions(
36 'cmd|c=s' => \$cmd,
37 'debug|d+' => \$debug,
38 'file|f' => \$file,
39 'help|h' => \$help,
40 'man|m' => \$man,
41 'notouch|n' => sub { $touch = 0 },
42 'oldroot|o=s' => \$oldroot,
43 'profile|p=s' => \$profile,
44 'subdir|s=s' => \$subdir,
45) or pod2usage(2);
46pod2usage(1) if ($help);
47pod2usage(-exitstatus => 0, -verbose => 2) if ($man);
48defined $subdir or pod2usage("Error: -subdir is a mandatory argument\n");
49
50# the new root is constructed from the profile and the chosen subdirectory name
51my $newroot = "$profile/$subdir" if defined $profile;
52
53# debug mode overview
54if ($debug) {
55 print <<EOF;
56DEBUG MODE, not doing anything, just printing
57--- current state ---
58debug = $debug
59cmd = $cmd
60oldroot = $oldroot
61profile = $profile
62subdir = $subdir
63newroot = $newroot (constructed)
64--- end ---
65EOF
66}
67
68# some sanity checks before proceeding
69system("$cmd </dev/null >/dev/null 2>/dev/null") == 0 or die <<EOF;
70Cannot run `$cmd' or locate it in your \$PATH!
71
72I need the program `formail' to process your mailboxes. You can provide the
73full path to the formail utility using the `-cmd' command-line switch.
74
75Perhaps `formail' is not installed on your system. Try installing the `formail'
76package using your distribution's package manager. The formail utility might be
77contained in the `procmail' package (e.g., Ubuntu 11.10), so you may need to
78look for the latter instead.
79
80Aborting ...
81EOF
82defined $oldroot or pod2usage(<<EOF);
83Cannot locate KMail mailboxes automatically. Please specify their location by
84rerunning the program with the -oldroot option.
85EOF
86-d $oldroot or die "cannot find mailbox root `$oldroot'";
87defined $profile or pod2usage(<<EOF);
88Cannot locate the default Thunderbird profile directory automatically. Please
89specify its location by rerunning the program with the -profile option.
90EOF
91-d $profile or die "cannot find Thunderbird profile directory `$profile'";
92
93# create destination path
94if ($debug) {
95 print "TARGET DIR: mkdir -p $newroot\n" if ((not -d "$newroot") && (not $file));
96 print "CMD: mkdir -p $newroot\n" if ((not -d "$newroot") && (not $file));
97} else {
98 mkpath("$newroot",0, 0755) if ((not -d "$newroot") && (not $file));
99}
100
101# the main work is done here
102if ($debug) {
103 print "DESCENDING INTO oldroot($oldroot)\n";
104}
105find(\&md2mb,($oldroot));
106
107# now go back again and create empty files corresponding to the `.sbd'
108# directories
109if ($touch) {
110 print "DESCENDING AGAIN INTO oldroot($oldroot)\n" if ($debug);
111 find(sub {
112 return if (! -d); # consider only directories ...
113 return if (! /\.sbd$/); # ... with the right name
114 s/\.sbd//; # strip .sbd suffix
115 if ($debug) {
116 print "WOULD CREATE file($_) IF NEEDED\n";
117 } else {
118 open my $fh, '>>', $_ or die "cannot open $_: $!";
119 }
120 }, $newroot);
121}
122
123# rename `inbox' to `Inbox'
124if ((-z "$newroot/Inbox") || (! -e "$newroot/Inbox")) {
125 if ($debug) {
126 print "RENAMING inbox($newroot/inbox) INTO Inbox($newroot/Inbox)\n" if (-e "$newroot/inbox");
127 } else {
128 print "Renaming inbox into Inbox\n";
129 move("$newroot/inbox","$newroot/Inbox") if (-e "$newroot/inbox");
130 }
131}
132
133sub md2mb {
134
135if (-f $File::Find::name) {
136 if (($File::Find::name =~ /\.ids$/) ||
137 ($File::Find::name =~ /\.sorted$/) ||
138 ($File::Find::name =~ /\.index$/)) {
139 print "SKIP FILE: $File::Find::name\n" if ($debug);
140 return;
141 }
142}
143if (-d $File::Find::name) {
144 if (($File::Find::name =~ /\/cur$/) ||
145 ($File::Find::name =~ /\/new$/) ||
146 ($File::Find::name =~ /\/tmp$/)) {
147 print "SKIP DIR: $File::Find::name\n" if ($debug);
148 return;
149 }
150}
151my $destname = $File::Find::name;
152# Target name is under a different root dir
153$destname =~ s|^$oldroot||;
154# Target name is not under a .directory dir but under a .sdb one
155$destname =~ s|\.([^/]+)\.directory/|$1.sbd/|g;
156# Here we create the target dir and target name
157my $outputfile="$newroot/$destname";
158my $cdir = dirname("$outputfile");
159# Handle case where target file name is empty
160$outputfile="$newroot" if ($destname =~ /^\s*$/);
161# When we treat a dir, we will have to handle what it has below
162if (-d $File::Find::name) {
163 if ($debug) {
164 print "DIR SRC: $File::Find::name\n";
165 }
166 my @files = (bsd_glob("$File::Find::name/cur/*"),bsd_glob("$File::Find::name/new/*"));
167 if (@files) {
168 if ($debug) {
169 print "DIR ($File::Find::name) DIR TARGET: mkdir -p $cdir\n" if (not -d "$cdir");
170 } else {
171 mkpath("$cdir",0, 0755) if (not -d "$cdir");
172 }
173 }
174 foreach my $file (@files) {
175 next unless -f $file; # skip non-regular files
176 next unless -s $file; # skip empty files
177 next unless -r $file; # skip unreadable files
178 $file =~ s/'/'"'"'/g; # escape ' (single quote)
179 # NOTE! The output file must not contain single quotes (')!
180 my $run = "cat '$file' | $cmd >> '$outputfile'";
181 if ($debug) {
182 print "COPYING CONTENT maildir($file) to $outputfile\n";
183 print "CMD: $run\n";
184 } else {
185 print "Copying maildir content from $file to $outputfile\n";
186 system($run) == 0 or warn "cannot run \"$run\".";
187 }
188 }
189}
190if (-f $File::Find::name) {
191 if (($File::Find::name =~ /\/cur\//) ||
192 ($File::Find::name =~ /\/new\//) ||
193 ($File::Find::name =~ /\/tmp\//)) {
194 print "SKIP FILE: $File::Find::name\n" if ($debug);
195 return;
196 }
197 if ($debug) {
198 print "FILE ($File::Find::name) TARGET DIR: mkdir -p $cdir\n" if (not -d "$cdir");
199 print "CMD: cp $File::Find::name $cdir\n";
200 } else {
201 print "Copying mailbox content from $File::Find::name to $cdir\n";
202 mkpath("$cdir",0, 0755) if (not -d "$cdir");
203 copy($File::Find::name,$cdir);
204 }
205}
206}
207__END__
208
209=head1 SYNOPSIS
210
211md2mb.pl [options] -s name
212
213 Options:
214 -cmd | -c <cmd> command to process mail
215 -debug | -d debug mode
216 -file | -f whether $newroot is a file or a directory
217 -help | -h brief help message
218 -man | -m full documentation
219 -notouch | -n do not create empty files corresponding to .sdb
220 dirs
221 -oldroot | -o <path> location of the KMail mailboxes
222 -profile | -p <path> path to the Thunderbird profile to install to
223 -subdir | -s <name> subdir that will be created to hold the
224 imported mails
225
226=head1 OPTIONS
227
228=over 4
229
230=item B<-cmd> I<cmd>
231
232Use I<cmd> to process your maildirs. By default uses B<formail> in
233your C<$PATH>, but you can use this option to specify the full path to the
234executable to use instead.
235
236=item B<-debug>
237
238Enter debug mode. This will print what would be done. No commands are executed,
239so this is safe to use when testing.
240
241=item B<-file>
242
243Specifies that $newroot is a file. If this option is omitted, it is assumed
244that $newroot is a directory instead.
245
246=item B<-help>
247
248Print a brief help message and exits.
249
250=item B<-man>
251
252Prints the manual page and exits.
253
254=item B<-notouch>
255
256Do not create empty files corresponding to the F<.sbd> dirs created by this
257script. By default, those empty files are created to make KMail's subfolders
258show up in Thunderbird. You probably don't need to use this option, but it is
259here nevertheless in case you need it.
260
261=item B<-oldroot> I<path>
262
263Specify where your B<KMail> mailboxes are to be found. By default assumes a
264folder called F<.Mail> or F<Mail> in your homedir, preferring F<.Mail> if it
265exists.
266
267=item B<-profile> I<path>
268
269Specify the path to the Thunderbird profile. Your imported mails will go inside
270a directory in this profile. By default uses the default profile in the
271F<.thunderbird> directory in your home directory, if it is unique.
272
273=item B<-subdir> I<name>
274
275Specify the subdirectory I<name> that will be created inside the Thunderbird
276profile to hold the imported mails. This option is mandatory; there is no
277default.
278
279=back
280
281=head1 EXAMPLES
282
283 # this will fetch all mails from the folder .Mail or Mail in your home
284 # directory, and import them into your default Thunderbird profile, in
285 # a directory called Mail/pop.home.musique-ancienne.org/
286 #
287 # usually, this is all you need to specify:
288
289 perl md2mb.pl -s Mail/pop.home.musique-ancienne.org/
290
291 # on your computer, the mails may end up in
292 # /users/segolene/.thunderbird/qk2f4dl6.default/Mail/pop.home.musique-ancienne.org/
293
294 # if md2mb.pl cannot figure out where your default Thunderbird profile
295 # is, use the following:
296
297 perl md2mb.pl -p ~/.thunderbird/qk2f4dl6.default -s Mail/pop.home.musique-ancienne.org/
298
299=head1 DESCRIPTION
300
301B<md2mb.pl> will import a B<kmail> maildir environment, and transform it into a
302B<thunderbird> one. It relies on B<formail> (or an equivalent utility) being
303available on your system.
304
305By default, B<md2mb.pl> assumes that your B<kmail> mailboxes are stored in a
306folder called F<.Mail> or F<Mail> in your homedir. If this assumption is
307incorrect, you need to specify the correct folder with B<-oldroot>.
308
309The mails will be imported into the Thunderbird profile that is either
310specified with B<-profile> or determined automatically. The script will try to
311determine the default Thunderbird profile automatically. If there is a folder
312that ends in F<.default> in the F<.thunderbird> directory in your home dir, and
313if it is unique, that one will be used.
314
315The mails finally end up in a subdirectory below the profile. You must specify
316the subdirectory on the command line with B<-subdir>, as shown in the examples
317above.
318
319If you have used a structure with subfolders in KMail, mails in subfolders
320should show up correctly in Thunderbird.
321
322=head1 AUTHOR
323
324=over 4
325
326=item *
327
328Bruno Cornec, http://brunocornec.wordpress.com
329
330=item *
331
332Edward Baudrez, C<< ebaudrez@cpan.org >>
333
334=back
335
336=head1 LICENSE
337
338Released under the GPLv2 or the Artistic license at your will.
339
340=cut
Note: See TracBrowser for help on using the repository browser.