exec perl -x -S $0 ${1+"$@"}
if ($] !~ /^5\..*/) {
foreach (split(/:/, $ENV{PATH})) { exec("$_/perl5", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
}
die "Your perl is too old; I need perl 5.\n";
}
eval join("\n", <DATA>);
if ($@) { die "$@"; }
__END__
require 5;
$| = 1;
die "must not run as root" if ($< == 0);
if ("-i" eq $ARGV[0]) {
$interactive = 1;
shift @ARGV;
}
if ("-f" eq $ARGV[0]) {
$force = 1;
shift @ARGV;
}
if ("-h" eq $ARGV[0] || @ARGV < 1) {
print "usage: rehash [-i] [-f] none|basic|full [imapd.conf]\n";
print " -i interactive\n";
print " -f keep going on errors\n";
exit;
}
$MOVE_DOMAIN_CONF = 1;
$MOVE_DOMAIN_SIEVE = 2;
$MOVE_DOMAIN_PART = 3;
$tonone = 1 if ("none" eq $ARGV[0]);
$tobasic = 1 if ("basic" eq $ARGV[0]);
$tofull = 1 if ("full" eq $ARGV[0]);
unless ($tonone || $tobasic || $tofull) {
print "rehash: one of none/basic/full required\n";
exit;
}
shift @ARGV;
my @bdirs = ("a".."z");
my @fdirs = ("A".."W");
my $dirs = [@bdirs,@fdirs] if $tonone;
if ($tobasic) {
$dirs = \@bdirs;
$old = \@fdirs;
}
if ($tofull) {
$dirs = \@fdirs;
$old = \@bdirs;
}
sub ouch {
my $msg = shift;
if ($force) {
print "fatal error: $msg\n";
} else {
print "error: $msg\n";
exit 1;
}
}
sub dir_hash_c {
my $name = shift;
my ($h, $n);
if ($tofull) {
$n = 0;
foreach my $b (split(/ */, $name)) {
$n = (($n << 3) ^ ($n >> 5)) ^ ord($b);
}
$h = chr(ord('A') + ($n % 23));
return $h;
}
elsif ($tobasic) {
$h = lc(substr($name, 0, 1));
if (!($h =~ /[a-z]/)) { $h = 'q'; }
return $h;
}
}
$imapdconf = shift || "/etc/imapd.conf";
$yn = "y";
$sievedir = "/usr/sieve";
$nosievedir = 0;
$hashispool = 0;
$virtdomains = 0;
open CONF, $imapdconf or die "can't open $imapdconf";
while (<CONF>) {
if (/^configdirectory:\s*(.*)$/) {
$conf = $1;
}
if (/^sieveusehomedir:\s+(1|t|yes|on)/) {
$nosievedir = 1;
print "you are storing sieve scripts in user's home directories.\n";
}
if (/^sievedir:\s+(.*)$/) {
$sievedir = $1;
print "you are using $sievedir as your sieve directory.\n";
}
if (/^partition-.*:\s*(.*)$/) {
if (grep /$1/, @parts) {
next;
}
push @parts, $1;
}
if (/^hashimapspool:\s*(1|t|yes|on)/) {
$hashispool = 1;
print "i will also hash partitions.\n";
}
if (/^virtdomains:\s+(1|t|yes|on)/) {
$virtdomains = 1;
print "i will deal with virtual domains.\n";
}
}
close CONF;
if (! $conf) { $conf = "/var/imap"; }
if ($interactive) {
print "upgrade $conf? ";
$yn = <STDIN>;
}
if ($yn =~ /^y/) {
unless (-d $conf) { print "creating $conf...\n";
mkdir $conf, 0755;
}
print "converting configuration directory $conf...";
chdir $conf or die "couldn't change to $conf";
foreach $i ("user", "proc", "db", "socket", "log", "msg", "quota") {
unless (-d $i) {
print "creating $i...\n";
mkdir $i, 0755;
}
}
if($virtdomains) {
print "domain ";
chdir "domain" or die "couldn't change to domain subdir";
&move_domains($MOVE_DOMAIN_CONF);
chdir "..";
}
print "user ";
chdir "user" or die "couldn't change to user subdir";
&move_users;
chdir "..";
print "quota ";
chdir "quota" or die "couldn't change to quota subdir";
&move_quotas;
print "done\n";
}
unless ($nosievedir) {
print "converting $sievedir...\n";
mkdir $sievedir, 0755;
if (chdir $sievedir) {
&move_sieve;
}
}
my $i;
my $f;
while ($part = shift @parts) {
if ($interactive) {
print "upgrade $part? ";
$yn = <STDIN>;
}
if ($yn =~ /^y/) {
unless (-d $part) {
print "creating $part...\n";
mkdir $part, 0755;
}
print "converting data partition $part...";
chdir $part or die "couldn't chdir to $part";
if ($hashispool) {
&move_part;
chdir $part or die "couldn't chdir to $part";
mkdir "stage.", 0755;
}
print "done\n";
}
}
sub do_subdomain_conf {
if(-d "quota") {
chdir "quota";
&move_quotas;
chdir "..";
}
if(-d "user") {
chdir "user";
&move_users;
chdir "..";
}
}
sub move_domains {
my $type_of_move = shift;
if(!defined($type_of_move) || !$type_of_move) {
die "move_domains called badly";
}
my $i;
my $s;
my $h;
my $mbox;
foreach $i (@{$dirs}) {
if ($tonone) {
if (opendir SUB, $i) {
while ($s = readdir SUB) {
if ($s =~ /^\./s) { next; }
chdir "$i/$s";
&do_subdomain;
chdir "../..";
rename("$i/$s", "$s") or die "couldn't move $s back!";
}
closedir SUB;
rmdir "$i" or die "couldn't remove $i";
}
}
else {
unless (-d $i) {
mkdir ("$i", 0755) or ouch "couldn't create $i";
}
}
}
unless ($tonone) {
foreach $i (@{$old}) {
if (opendir SUB, $i) {
while ($s = readdir SUB) {
if ($s =~ /^\./s) { next; }
chdir "$i/$s";
if($type_of_move == $MOVE_DOMAIN_CONF) {
&do_subdomain_conf;
} elsif ($type_of_move == $MOVE_DOMAIN_SIEVE) {
&move_sieve;
} elsif ($type_of_move == $MOVE_DOMAIN_PART) {
&move_part;
} else {
die "bad domain move mode: $type_of_move";
}
chdir "../..";
$h = dir_hash_c($s);
print "moving $i/$s to $h/$s\n";
rename("$i/$s", "$h/$s") or ouch "couldn't move $s back!";
}
closedir SUB;
rmdir "$i" or die "couldn't remove $i";
}
}
opendir (USER, ".");
while ($f = readdir USER) {
if ($f =~ /^\./s) { next; }
my $flag = 0;
foreach $item (@{$dirs}) {
if($item eq $f) {
$flag = 1;
$break;
}
}
next if($flag);
print "$f\n";
$h = dir_hash_c($f);
rename ($f, "$h/$f") or ouch "couldn't move $f into $h";
}
closedir USER;
}
}
sub move_users {
my $i;
my $s;
my $h;
my $f;
my $mbox;
foreach $i (@{$dirs}) {
if ($tonone) {
if (opendir SUB, $i) {
while ($s = readdir SUB) {
if ($s =~ /^\./s) { next; }
rename("$i/$s", "$s") or die "couldn't move $s back!";
}
closedir SUB;
rmdir "$i" or die "couldn't remove $i";
}
} else {
unless (-d $i) {
mkdir ("$i", 0755) or ouch "couldn't create $i";
}
}
}
unless ($tonone) {
foreach $i (@{$old}) {
if (opendir SUB, $i) {
while ($s = readdir SUB) {
if ($s =~ /^\./s) { next; }
if ($s =~ /^(.+)\./) {
$h = dir_hash_c($1);
rename("$i/$s", "$h/$s") or ouch "couldn't move $s back!";
}
}
closedir SUB;
rmdir "$i" or die "couldn't remove $i";
}
}
opendir (USER, ".");
while ($f = readdir USER) {
if ($f =~ /^\./s) { next; }
if ($f =~ /^(.+)\./) {
print "$f\n";
$h = dir_hash_c($1);
rename ($f, "$h/$f") or ouch "couldn't move $f into $h";
}
}
closedir USER;
}
}
sub move_quotas {
my $i;
my $s;
my $h;
my $mbox;
foreach $i (@{$dirs}) {
if ($tonone) {
if (-d $i) {
rename ($i, ".$i") or die "couldn't rename $i to .$i";
opendir SUB, ".$i";
while ($s = readdir SUB) {
if ($s =~ /^\./s) { next; }
rename(".$i/$s", $s) or die "couldn't move $s back!";
}
closedir SUB;
rmdir ".$i" or die "couldn't remove .$i";
}
}
else {
if (-d $i) {
rename ($i, ".$i") or die "couldn't rename $i to .$i";
}
else {
mkdir (".$i", 0755);
}
}
}
unless ($tonone) {
foreach $i (@{$old}) {
if (opendir SUB, $i) {
while ($s = readdir SUB) {
if ($s =~ /^.+\.(.+)$/) {
$h = dir_hash_c($1);
rename("$i/$s", ".$h/$s")
or ouch "couldn't move $s back!";
}
}
closedir SUB;
rmdir "$i" or die "couldn't remove $i";
}
}
opendir QUOTA, ".";
while ($mbox = readdir QUOTA) {
if ($mbox =~ /^\./s) { next; }
if ($mbox =~ /^.*\.(.*)$/) {
$h = dir_hash_c($1);
rename($mbox, ".$h/$mbox")
or ouch "couldn't move $mbox into $h";
next;
}
$h = dir_hash_c($mbox);
rename($mbox, ".$h/$mbox")
or ouch "couldn't move $mbox into $h";
next;
}
closedir QUOTA;
foreach $i (@{$dirs}) {
rename (".$i", $i) or ouch "couldn't rename $i into place";
}
}
}
sub move_sieve {
my $i;
my $s;
my $h;
my $mbox;
foreach $i (@{$dirs}) {
unless ($tonone) {
if (-d $i) {
rename ($i, ".$i") or die "couldn't rename $i to .$i";
}
else {
mkdir (".$i", 0755);
}
}
else {
rmdir "$i";
}
}
unless ($tonone) {
foreach $i (@{$old}) {
if (opendir SUB, $i) {
while ($s = readdir SUB) {
unless ($s =~ /^\./) {
$h = dir_hash_c($s);
rename("$i/$s", ".$h/$s")
or ouch "couldn't move $s back!";
}
}
closedir SUB;
rmdir "$i" or die "couldn't remove $i";
}
}
foreach $i (@{$dirs}) {
rename (".$i", $i) or ouch "couldn't rename $i into place";
}
}
if($virtdomains && chdir "domain") {
&move_domains($MOVE_DOMAIN_SIEVE);
chdir "..";
}
}
sub move_part {
my $i;
my $s;
my $t;
my $h;
my $dir;
my $sub;
my $ismbox;
foreach $i (@{$dirs}) {
if ($tonone) {
if (-d $i) {
rename ($i, ".$i") or die "couldn't rename $i to .$i";
print "$i ";
opendir SUB, ".$i";
while ($s = readdir SUB) {
if ($s =~ /^\./s) { next; }
mkdir $s, 0755;
opendir MV, ".$i/$s";
while ($t = readdir MV) {
if ($t =~ /^\./s) { next; }
rename (".$i/$s/$t", "$s/$t")
or die "couldn't rename .$i/$s/$t to $s/$t";
}
closedir MV;
}
closedir SUB;
rmdir ".$i" or die "could not remove .$i";
}
print "done\n";
}
else {
mkdir (".$i", 0755) or ouch "couldn't create .$i";
}
}
unless ($tonone) {
foreach $i (@{$old}) {
if (opendir SUB, $i) {
while ($dir = readdir SUB) {
if ($dir =~ /^\./s) { next; }
print "$i/$dir ";
opendir DIR, "$i/$dir";
$ismbox = 0;
while ($sub = readdir DIR) {
if ($sub =~ /^\./s) { next; }
if ($sub =~ /(.*)\.(.*)/) { $ismbox = 1; next; }
print "/$sub ";
$h = dir_hash_c($sub);
mkdir (".$h/$dir", 0755); rename("$i/$dir/$sub", ".$h/$dir/$sub") or
ouch "couldn't move $dir/$sub into $h";
}
closedir DIR;
if ($ismbox) {
$h = dir_hash_c($dir);
mkdir (".$h/$dir", 0755); opendir DIR, "$i/$dir";
while ($sub = readdir DIR) {
if ($sub =~ /^\./s) { next; }
print "/$sub ";
rename("$i/$dir/$sub", ".$h/$dir/$sub") or
ouch "couldn't move $dir into $h";
}
closedir DIR;
}
rmdir "$i/$dir" or print "\ncouldn't remove '$dir'??\n";
}
closedir SUB;
rmdir "$i" or die "couldn't remove $i";
}
}
opendir PART, ".";
while ($dir = readdir PART) {
if ($dir =~ /^\./s) { next; }
if ($dir eq "lost+found") { next; }
if ($dir eq "stage.") { next; }
if ($dir eq "domain") {
if(chdir "domain") {
&move_domains($MOVE_DOMAIN_PART);
chdir "..";
}
next;
}
print "$dir ";
opendir DIR, $dir;
$ismbox = 0;
while ($sub = readdir DIR) {
if ($sub =~ /^\./s) { next; }
if ($sub =~ /(.*)\.(.*)/) { $ismbox = 1; next; }
$h = dir_hash_c($sub);
mkdir (".$h/$dir", 0755); rename("$dir/$sub", ".$h/$dir/$sub") or
ouch "couldn't move $dir/$sub into $h";
}
closedir DIR;
if ($ismbox) {
$h = dir_hash_c($dir);
mkdir (".$h/$dir", 0755); opendir DIR, $dir;
while ($sub = readdir DIR) {
if ($sub =~ /^\./s) { next; }
rename("$dir/$sub", ".$h/$dir/$sub") or
ouch "couldn't move $dir into $h";
}
closedir DIR;
}
rmdir $dir or print "\ncouldn't remove '$dir'??\n";
}
closedir PART;
foreach $i (@{$dirs}) {
rename (".$i", $i) or ouch "couldn't rename .$i to $i";
}
}
}