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
RevLine 
[1141]1#!/usr/bin/perl -w
2
[1445]3=head1 NAME
4
5md2mb.pl - Import a maildir kmail environment into a thunderbird one
6
7=cut
8
[1141]9use strict;
10use File::Find;
11use File::Copy;
12use File::Basename;
13use File::Path;
[1389]14use File::Glob ':glob';
[1445]15use Getopt::Long;
16use Pod::Usage;
[1447]17use List::Util qw(first);
[1141]18
[1445]19# settings
[1453]20my $cmd = 'formail';
[1141]21my $debug = 0;
[1450]22my $file = 0; # is the newroot a file (1) or a dir (0) ?
[1445]23my $help = 0;
24my $man = 0;
[1449]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;
[1458]32my $touch = 1;
[1141]33
[1445]34# parse command-line options
35GetOptions(
[1456]36 'cmd|c=s' => \$cmd,
[1454]37 'debug|d+' => \$debug,
38 'file|f' => \$file,
39 'help|h' => \$help,
40 'man|m' => \$man,
[1458]41 'notouch|n' => sub { $touch = 0 },
[1454]42 'oldroot|o=s' => \$oldroot,
43 'profile|p=s' => \$profile,
44 'subdir|s=s' => \$subdir,
[1445]45) or pod2usage(2);
46pod2usage(1) if ($help);
47pod2usage(-exitstatus => 0, -verbose => 2) if ($man);
[1449]48defined $subdir or pod2usage("Error: -subdir is a mandatory argument\n");
[1445]49
[1449]50# the new root is constructed from the profile and the chosen subdirectory name
[1455]51my $newroot = "$profile/$subdir" if defined $profile;
[1449]52
[1446]53# debug mode overview
54if ($debug) {
55 print <<EOF;
56DEBUG MODE, not doing anything, just printing
57--- current state ---
[1454]58debug = $debug
[1446]59cmd = $cmd
60oldroot = $oldroot
[1449]61profile = $profile
62subdir = $subdir
63newroot = $newroot (constructed)
[1446]64--- end ---
65EOF
66}
67
[1448]68# some sanity checks before proceeding
[1453]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
[1457]82defined $oldroot or pod2usage(<<EOF);
83Cannot locate KMail mailboxes automatically. Please specify their location by
84rerunning the program with the -oldroot option.
85EOF
[1448]86-d $oldroot or die "cannot find mailbox root `$oldroot'";
[1457]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
[1449]91-d $profile or die "cannot find Thunderbird profile directory `$profile'";
[1448]92
[1446]93# create destination path
[1141]94if ($debug) {
[1450]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));
[1141]97} else {
[1450]98 mkpath("$newroot",0, 0755) if ((not -d "$newroot") && (not $file));
[1141]99}
100
[1446]101# the main work is done here
102if ($debug) {
103 print "DESCENDING INTO oldroot($oldroot)\n";
104}
[1141]105find(\&md2mb,($oldroot));
106
[1451]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
[1446]123# rename `inbox' to `Inbox'
[1390]124if ((-z "$newroot/Inbox") || (! -e "$newroot/Inbox")) {
[1446]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 }
[1390]131}
132
[1141]133sub md2mb {
134
135if (-f $File::Find::name) {
[1389]136 if (($File::Find::name =~ /\.ids$/) ||
[1141]137 ($File::Find::name =~ /\.sorted$/) ||
[1389]138 ($File::Find::name =~ /\.index$/)) {
139 print "SKIP FILE: $File::Find::name\n" if ($debug);
140 return;
141 }
[1141]142}
143if (-d $File::Find::name) {
[1389]144 if (($File::Find::name =~ /\/cur$/) ||
[1141]145 ($File::Find::name =~ /\/new$/) ||
[1389]146 ($File::Find::name =~ /\/tmp$/)) {
147 print "SKIP DIR: $File::Find::name\n" if ($debug);
148 return;
149 }
[1141]150}
151my $destname = $File::Find::name;
[1389]152# Target name is under a different root dir
[1141]153$destname =~ s|^$oldroot||;
[1389]154# Target name is not under a .directory dir but under a .sdb one
[1390]155$destname =~ s|\.([^/]+)\.directory/|$1.sbd/|g;
[1389]156# Here we create the target dir and target name
[1141]157my $outputfile="$newroot/$destname";
[1412]158my $cdir = dirname("$outputfile");
[1389]159# Handle case where target file name is empty
[1141]160$outputfile="$newroot" if ($destname =~ /^\s*$/);
[1389]161# When we treat a dir, we will have to handle what it has below
[1141]162if (-d $File::Find::name) {
[1328]163 if ($debug) {
[1389]164 print "DIR SRC: $File::Find::name\n";
[1328]165 }
[1389]166 my @files = (bsd_glob("$File::Find::name/cur/*"),bsd_glob("$File::Find::name/new/*"));
[1141]167 if (@files) {
168 if ($debug) {
[1389]169 print "DIR ($File::Find::name) DIR TARGET: mkdir -p $cdir\n" if (not -d "$cdir");
[1141]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
[1389]178 $file =~ s/'/'"'"'/g; # escape ' (single quote)
[1141]179 # NOTE! The output file must not contain single quotes (')!
180 my $run = "cat '$file' | $cmd >> '$outputfile'";
181 if ($debug) {
[1389]182 print "COPYING CONTENT maildir($file) to $outputfile\n";
183 print "CMD: $run\n";
[1141]184 } else {
[1389]185 print "Copying maildir content from $file to $outputfile\n";
[1141]186 system($run) == 0 or warn "cannot run \"$run\".";
187 }
188 }
189}
190if (-f $File::Find::name) {
[1389]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 }
[1141]197 if ($debug) {
[1389]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";
[1141]200 } else {
[1389]201 print "Copying mailbox content from $File::Find::name to $cdir\n";
[1141]202 mkpath("$cdir",0, 0755) if (not -d "$cdir");
203 copy($File::Find::name,$cdir);
204 }
205}
206}
[1445]207__END__
208
209=head1 SYNOPSIS
210
[1449]211md2mb.pl [options] -s name
[1445]212
213 Options:
[1457]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
[1458]219 -notouch | -n do not create empty files corresponding to .sdb
220 dirs
[1457]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
[1445]225
226=head1 OPTIONS
227
228=over 4
229
[1457]230=item B<-cmd> I<cmd>
[1453]231
[1457]232Use I<cmd> to process your maildirs. By default uses B<formail> in
[1453]233your C<$PATH>, but you can use this option to specify the full path to the
234executable to use instead.
235
[1446]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
[1450]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
[1445]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
[1458]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
[1449]261=item B<-oldroot> I<path>
[1448]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
[1449]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
[1445]279=back
280
[1449]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
[1445]299=head1 DESCRIPTION
300
301B<md2mb.pl> will import a B<kmail> maildir environment, and transform it into a
[1453]302B<thunderbird> one. It relies on B<formail> (or an equivalent utility) being
303available on your system.
[1445]304
[1448]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
[1449]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
[1451]319If you have used a structure with subfolders in KMail, mails in subfolders
[1458]320should show up correctly in Thunderbird.
[1451]321
[1445]322=head1 AUTHOR
323
[1448]324=over 4
325
326=item *
327
[1445]328Bruno Cornec, http://brunocornec.wordpress.com
329
[1448]330=item *
331
332Edward Baudrez, C<< ebaudrez@cpan.org >>
333
334=back
335
[1445]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.