#!/usr/bin/perl =head1 NAME convert-multi-users - converts all users' IMAP folders to MBOX format =head1 SYNOPSIS convert-multi-users.plx imap-root mbox-root =head1 DESCRIPTION Apply maildir-to-mbox.plx against all folders for all users. I'm assuming that the input hierarchy looks like this: imap/ user1/ x1 x2 folder1/ y1 y2 folder2/ subfolder1/ z1 z2 subfolder2/ folder3/ user2/ folder1/ ... Difficulty: folder names can (and do) have spaces in them. Output hierarchy: mbox/ user1/ mbox (contains x1, x2) folder1/mbox (contains y1, y2) folder2/mbox folder2/subfolder1/mbox (contains z1, z2) folder2/subfolder2/mbox folder3/mbox user1/ mbox folder1/mbox =cut use strict; use warnings; use FindBin qw( $Bin ); use File::Path qw( mkpath rmtree ); my $maildir_to_mbox = "$Bin/maildir-to-mbox.plx"; # ====================================================================== # process options # get program name w/ no path my $prog = $0; $prog =~ s!.*/!!; # check args @ARGV == 2 or die "usage: $prog imap-root mbox-root"; my ( $imap, $mbox ) = @ARGV; # don't overwrite existing mbox files -e $mbox and die "$prog: $mbox already exists"; # make sure we have a clean temp area to work in my $mbox_tmp = "$mbox.tmp"; rmtree $mbox_tmp; mkdir $mbox_tmp, 0777; # ====================================================================== # subroutines # just list everything in the given directory, omitting '.' and '..' sub ls ( $ ) { my ( $dir ) = @_; opendir my $dh, $dir or die "$prog: opendir '$dir': $!"; return grep { $_ ne '.' && $_ ne '..' } readdir $dh; } # do a breadth-first search through the user directories. sort the # return list so that we get locality of reference when we do the # actual conversion. sub find_message_dirs ( $ @ ) { my ( $imap, @users ) = @_; my @rv; my %seen; my @candidates = @users; while ( @candidates ) { my $cand = shift @candidates; my $n_messages = 0; foreach my $file ( ls "$imap/$cand" ) { my $sub = "$cand/$file"; if ( -d "$imap/$sub" && ! $seen{$sub} ) { push @candidates, $sub; $seen{$sub} = 1; } elsif ( $file =~ /^\d+\.?$/ ) { ++$n_messages; } } if ( $n_messages ) { push @rv, $cand; } } return sort @rv; } # ====================================================================== # main processing # get list of users my @users = sort grep { -d "$imap/$_" } ls $imap; print STDERR "$prog: $imap: found " . @users . " users\n"; # find out which subdirs have messages my @dirs_with_messages = find_message_dirs( $imap, @users ); # now try to transform them my $n_errors = 0; foreach my $dir ( @dirs_with_messages ) { my $src = "$imap/$dir"; my $dest = "$mbox/$dir"; eval { mkpath $dest, 0, 0777 or die "mkpath '$dest': $!"; print STDERR "$dir:\n"; my @args = ( $maildir_to_mbox, $src, "$dest/mbox" ); system( @args ) == 0 or die "system @args: $?"; }; if ( $@ ) { ++$n_errors; warn "$prog: $src: $@\n"; } } if ( $n_errors ) { die "WARNING: $n_errors directories did not convert properly!\n", "$prog: output left in $mbox_tmp\n"; } else { rename $mbox_tmp, $mbox; rmtree $mbox_tmp; exit 0; }