#!/usr/bin/perl

use strict;
use Getopt::Std;
use Sys::Hostname;
use File::Find;
use CGI ':standard';

use MATT::Utility;
use MATT::FreeBSD;
use MATT::Perl;

my $author  = "Matt Simerson <matt\@cadillac.net>";
my $version = "maildomain v2.5.1 by $author";

##
# ChangeLog - http://matt.simerson.net/computing/mail/toaster/maildomain/Changes.txt
##

my $update           = "/usr/local/sbin/update";    # custom Matt script updates clients
my $home             = "/usr/home";                 # where you store home directories
my $quotafs          = "/home";                     # mount point for quota enabled file system
my $qmailpath        = "/usr/var/qmail";            # where qmail is installed
my $qmailadminlimits = "$qmailpath/control/.qmailadmin-limits";
my $adminhost        = "admin.mail.safeserver.com"; # the "master" server in a cluster
my @fileservers      = qw( admin serv3 );           # all file servers in this array
my @mailservers      = qw( mail1 mail2 mail3 mail4 mail5 );

my $vbin           = "/usr/local/vpopmail/bin";
my $vadduser       = "$vbin/vadduser";      my $vmoduser         = "$vbin/vmoduser";
my $vadddomain     = "$vbin/vadddomain";    my $vdeldomain       = "$vbin/vdeldomain";
my $vpasswd        = "$vbin/vpasswd";       my $vmkpasswd        = "$vbin/vmkpasswd";
my $vuserinfo      = "$vbin/vuserinfo";     my $vsetuserquota    = "$vbin/vsetuserquota";
my $vdelivermail   = "$vbin/vdelivermail";  my $vaddaliasdomain  = "$vbin/vaddaliasdomain";
my $vdominfo       = "$vbin/vdominfo";

my $singleuid="";          #  If all your mail domains will be owned by a single user
                           #  (vpopmail) then set to the username of your vpopmail user

my $create_sys_user=1;     #  by default, when in single uid mode this script won't 
                           #  create a new system user. This flag overrides that. (y/n)

my $homedirtree=1;         #  Using a homedir tree? (/usr/home/a/ab/abcuser instead of
                           #  /usr/home/abcuser)

my $homedir_base="u";	   # If using a system user account, where do we put their 
                           # home dir? IE, is it based on user or domain name (u/d)

my $use_passwords=0;       # Do we want the users to be able to log in via (telnet/ssh)?
                           # Put the postmaster password into the system passwd files

my $show_function=1;       # A handy utility that lets support staff view the current 
                           # settings of a mail account.

my $vauth = "mysql";       # where vpopmail stores it's auth info (cdb, mysql, ldap)

my $delete_old_archives=0; # Delete archive files after restoring?

my $secure_levels=1;       # Adds multiple levels of security while running this script.


######################################################################
#            Do not modify anything below this line                  #
######################################################################

use vars qw/ $opt_v $iam $nl /;      getopts('v');
my $debug = 0; $debug = 1            if ($opt_v);

if ( $ENV{'GATEWAY_INTERFACE'} ) {
	#my %r = &parse_form_data();
	#&setup_global_vars(\%r);
	print header('text/html');
	$iam  = "www";
	$debug = 1;
	$nl = "<br>";
} else {
	$iam  = getpwuid($<);             # get our system username
	$nl = "\n";
};

my $sudo = &sudo_setup;              # what to prepend before commands
                                     # requiring root privileges
my $sl   = &set_securelevel($iam);   # secure level
&check_hostname($adminhost);         # warn if not admin host
my $name = "maildomain";             # this scripts filename

print "You are $iam running as UID: $< in support level: $sl.${nl}" if $debug;

#
# Redirect STDERR to STDOUT so we can see what's printed out in a die() call.
#
open(STDERR, ">&STDOUT");
select(STDERR); $|=1; select(STDOUT); $|=1;

my $rm       = FindTheBin("rm");
my $cp       = FindTheBin("cp");
my $chown    = FindTheBin("chown");
my $action   = $ARGV[0];

if ($iam eq "www" ) {
	my $action = param('action');
};

if    ( $action eq "add" )          { &add_account;  } 
elsif ( $action eq "vadd" )         { &vadd_domain;  } 
elsif ( $action eq "padd" )         { &padd_domain;  } 
elsif ( $action eq "hold" )         { &hold_user;    }
elsif ( $action eq "unhold" )       { &unhold_user;  }
elsif ( $action eq "suspend" )      { &hold_user;    }
#elsif ( $action eq "suspend" )      { &suspend;      }
elsif ( $action eq "restore" )      { &unhold_user;  }
#elsif ( $action eq "restore" )      { &restore;      }
elsif ( $action eq "vpassrestore" ) { &vpassrestore; }
elsif ( $action eq "modify" )       { &modify;       }
elsif ( $action eq "delete")        { &delete;       }
elsif ( $action eq "fix" )          { &fix;          }
elsif ( $action eq "adduser")       { &add_v_email;  }
elsif ( $action eq "show" )         { &show_settings;}
elsif ( $action eq "exec" )         { &exec_all;     }
elsif ( $action eq "count" )        { &count_users;  }
elsif ( $action eq "check" )        { &check;        }
else                                { &print_menu;   }

exit 0;

##
# Subroutines
##
# -----------------------------------------------------------------------

sub print_menu_line {
	my ($opt, $desc) = @_;
	if ( $iam eq "www" ) {
		print a({-href=>'/'}, "\t$opt");
		print "$desc${nl}";
	} else {
		print "\t$opt\t- $desc${nl}";
	};
};

sub print_menu {
	print $version;
	print "${nl}${nl}   Valid choices are: ${nl}${nl}";

	my (@options, @descrip);
	if ( $sl <= 1 ) { 
		if ( $singleuid eq "" ) {
			push @options, "add";
			push @descrip, "creates a new user & mail domain";
		} else {
			push @options, "add";
			push @descrip, "creates a new mail domain";
		};
	};
	if ( $sl <= "2" ) { 
		if ( $singleuid eq "" ) {
			push @options, "vadd";
			push @descrip, "add a new mail domain to an existing user";
		};
	};
	if ( $sl <= "2" ) {
		push @options, "padd";
		push @descrip, "add a mail domain pointer${nl}";
	};
	if ( $sl <= "1" ) {
		push @options, "hold";
		push @descrip, "Disable an accounts ability to retrieve email";
	};
	if ( $sl <= "2" ) {
		push @options, "unhold";
		push @descrip, "Enable an accounts ability to retrieve email${nl}";
	};
#	if ( $sl <= "1" ) {
#		if ( $singleuid eq "" ) {
#			print "\tsuspend - suspend a user and all their mail domains";
#			print "\trestore - restore a suspended user and their domains";
#		};
#	};
	if ( $sl <= "2" ) {
		if ( $vauth eq "cdb" ) {
			push @options, "vpassrestore";
			push @descrip, "restore the vpasswd file of a domain";
		};
	};
	if ( $sl <= "3" ) {
		if ($show_function) {
			push @options, "show";
			push @descrip, "display properties of a user or domain";
		};
		if ( $sl <= "1" ) {
			push @options, "fix";
			push @descrip, "various repair options${nl}";
		};
		push @options, "modify", "adduser";
		push @descrip, "make changes to a user or domain";
		push @descrip, "add a user to a maildomain";
	};
	if ( $sl <= "2" ) {
		push @options, "delete";
		if ( $singleuid eq "" ) {
			push @descrip, "remove a mail user or domain(s)${nl}";
		} else {
			push @descrip, "remove a mail domain${nl}";
		};
	};
	if ( $sl <= "0" ) {
		push @options, "exec", "check";
		push @descrip, "run a command on each server(s)";
		push @descrip, "various tests for consistency";
	};

	if ( $iam eq "www" ) {
		my @rows;
		my $i = 0;
		my $space = "<pre>    </pre>";
		my @col_head = ($space,"Options", $space, "Description");
		print start_form();
		print radio_group(-name=>"action", -value=>$options[0]);
		print radio_group(-name=>"action", -value=>$options[1]);
		print radio_group(-name=>"action", -value=>$options[2]);

		foreach my $opt (@options) {
			#my $check = radio_group(-name="action", -value="opt");
			my @bug = ( $opt, "", $descrip[$i] );
			push( @rows, th("").td(\@bug) );
			$i++;
		};
		print table( { -border=>'0' }, 
			caption("tables are cool"),
			Tr( [ th(\@col_head), @rows ] )
		);
	} else {
		my $i = 0;
		foreach my $opt (@options) {
			print "\t$opt\t-$descrip[$i]\n";
			$i++;
		};
	};
};

sub add_v_email {
	print $version;
	if ( $secure_levels ) { check_permissions("3") };
	if ( $ARGV[1] ne "" ) {
		system "$sudo $vadduser $ARGV[1] $ARGV[2]";
		print "+100 useradd Done.${nl}${nl}";
	} else {
		&print_error("${nl}   I need a user\@domain.com handed to me.");
	};
} 

sub fix {
	if ( $secure_levels ) { check_permissions("0") };
	print $version;
	if ( $ARGV[1] eq "homedirtree" ) {
		make_home_dir_tree();
	} elsif ( $ARGV[1] eq "default" ) {
		reset_default_delivery($ARGV[2])
	} elsif ( $ARGV[1] eq "permissions") {
		my $home = (getpwnam($ARGV[2]))[7];
		if ( -d $home ) {
			print "executing $sudo $chown -R $ARGV[2] $home..." if $debug;
			system "$sudo $chown -R $ARGV[2] $home";
			print "done.${nl}";
		} else {
			print "user: $ARGV[2] or home: $home doesn't exist!${nl}";
		};
	} else {
		print "${nl}I need you to pass me a command like this:${nl}${nl}";
		print "      $name fix homedirtree${nl}";
		print "      $name fix default <uid>${nl}";
		print "      $name fix permissions <user>${nl}${nl}";
	};
} 

sub add_account {
	my $action = $ARGV[0];
	my ($user, $domain, $pass, $quota, $foo);

	print $version;

	if ( $singleuid ne "" ) { 
		$user =   $singleuid;
		$domain = $ARGV[1];
		$pass   = $ARGV[2];
		$quota  = $ARGV[3];
		$foo    = $ARGV[4];
	} else {
		$user   = $ARGV[1];
		$domain = $ARGV[2];
		$pass   = $ARGV[3];
		$quota  = $ARGV[4];
		$foo    = $ARGV[5];
	};

	if ( $secure_levels ) { check_permissions("1") };
	if ( $quota > 0 ) {
		my $homedir = set_homedir( $user, $domain );

		if ( $singleuid eq "" ) {
			if ( &add_system_user($user, $homedir, $domain, $pass, $quota) ) {
				&add_mail_domain($user, $homedir, $domain, $pass, $quota);
			} else {
				die "FAILED.${nl}${nl}The user failed to be added. This must be fixed.${nl}${nl}";
			};
		} else { 
			if ( &DoesSysUserExist($singleuid) ) {
				&add_mail_domain($user, $homedir, $domain, $pass, $quota);
			} else {
				die "\tFAILED: The user $singleuid does not exist!${nl}${nl}";
			};
		}; 
		print "+100 adddomain Done.${nl}${nl}";
	} else {
		if ( $singleuid eq "" ) {
			&print_error("$name add <user> <domain> <password> <quota>");
		} else {
			&print_error("$name add <domain> <password> <quota>");
		};
	};
};

sub delete {
	print $version;
	if ( $secure_levels ) { check_permissions("2") };
	if ( $singleuid eq "" || ( $singleuid ne "" && $create_sys_user )) {
		if ( $ARGV[1] eq "domain" and $ARGV[2] ne "" ) {
			&delete_domain( $ARGV[2] );
			print "+100 deldomain Done.${nl}${nl}";
		} elsif ( $ARGV[1] eq "user" and $ARGV[2] ne "" ) {
			&delete_domain( &get_users_domain_list( $ARGV[2] ) ); 
			&delete_sys_user( $ARGV[2], $ARGV[3] );
		} else {
			print "${nl}I need you to pass me a command like this:${nl}${nl}";
			print "      $name delete domain <domainname>${nl}";
			print "  or  $name delete user   <username> [archive]${nl}${nl}";
			print "To archive the domain files pass any non-zero value with the";
			print " delete switch.${nl}${nl}";
		};
	} else {
		if ( $ARGV[1] ne "" ) {
			&delete_domain( $ARGV[1] );
			print "+100 deldomain Done.${nl}${nl}";
		} else {
			&print_error("      $name delete <domainname>");
		};
	};
};

# Adding a domain 
#

sub vadd_domain {
	print $version;
	if ( $secure_levels ) { check_permissions("2") };
	my ($user, $domain, $pass, $quota, $foo);
	my $homedir = set_homedir( $user, $domain );

	if ( $singleuid ne "" ) { 
		print "You shouldn't be using vadd!${nl}";
	} else {
		$user   = $ARGV[1];
		$domain = $ARGV[2];
		$pass   = $ARGV[3];
		$quota  = $ARGV[4];
		$foo    = $ARGV[5];
	};

	if ( $quota > 0 ) {
		if ( &DoesSysUserExist($user) ) {
			&add_mail_domain($user, $homedir, $domain, $pass, $quota);
		} else {
			die "\tFAILED: The user must exist to use the vadd feature.${nl}${nl}";
		};
	
		if ( $pass eq "null" ) {      # Check the password for the keyword "null"
			my @domvals = get_main_domain( $user );
			print "done.${nl}${nl}...\tSetting password for $domain to same as $domvals[0]...";
			print "the password for $domvals[0] is $domvals[1].${nl}" if $debug;
			set_pass_to_main( $homedir, $domain, $domvals[1] );
			system "$sudo $vmkpasswd $domain";
		};
	} else {
		&print_error("$name vadd <user> <domain> <password> <quota>");
		
	};
	print "+100 vadddomain Done.${nl}${nl}";
};

sub padd_domain {
	print $version;
	my $newdom   = $ARGV[1];
	my $existing = $ARGV[2];

	if ( $secure_levels ) { check_permissions("2") };
	if ($existing ne "" ) {
		if ( does_domain_exist_in_qmail($existing) ) {
			print "\tCreating alias for $newdom to $existing...";
			system "$sudo $vaddaliasdomain $newdom $existing";
			print "+100 padddomain Done.${nl}${nl}";
		} else {
			die "\tThe domain $existing must exist to use padd!${nl}${nl}";
		};
	} else {
		&print_error("$name padd <new_domain> <existing_domain>");
	};
};

sub add_mail_domain {
	my ($user, $homedir, $domain, $pass, $quota) = @_;
	my $chmod = FindTheBin("chmod");
	if ( ! does_domain_exist_in_qmail( $domain ) ) {
		system "$sudo $vadddomain -u $user -q ${quota}000000 $domain $pass";
		system "$sudo $chmod 750 $homedir/domains $homedir/domains/$domain";
		my @domain_list=get_users_domain_list( $user );    # make sure the domain got created
		#
		# Need to add a check here to verify the domain was created
		#
		if ( -e $qmailadminlimits ) {
			system "$sudo $cp $qmailadminlimits $homedir/domains/$domain/";
			system "$sudo $chown $user $homedir/domains/$domain/.qmailadmin-limits";
		};
		&update_command("mail");
		return 1;
	} else {
		warn "The domain $domain already exists!${nl}";
		return 0;
	};
};

sub add_system_user {
	my ($user, $homedir, $domain, $pass, $quota) = @_;
	my $pw = FindTheBin("pw");
	if ( &DoesSysUserExist($user) ) {
		warn "FAILED: $user already exists in /etc/passwd.${nl}";
		return 0;
	};
	print "\tAdding $user to the system password files...";
	if ( $use_passwords ) {
		open( FH, "|$sudo $pw useradd -n $user -d $homedir -c $domain -g vchkpw -h 0 -m");
			print FH $pass,"${nl}";
		close (FH);
	} else {
		system "$sudo $pw useradd -n $user -d $homedir -c $domain -g vchkpw -h- -m";
	};
	if ( &DoesSysUserExist($user) ) {
		if ( $quota ne "") {
			setupquota($user, $quota);
		};
		print "done.${nl}\tUpdating mail cluster...";
		&update_command("passwd");
		print "done.${nl}";
		return 1;
	} else {
		warn "FAILED.${nl}${nl}The user failed to be added.${nl}";
		return 0;
	};
};

# Holding a domain 
#   
#   To hold a domain, we simply remove the users ability to retrieve their mail.
#
sub hold_user {
	print $version;
	my $user = $ARGV[1];

	if ( $secure_levels ) { check_permissions("1") };
	if ( $user ne "" ) {
		print $version;
		print "${nl}${nl}\t Removing ${user}'s ability to retrieve email...${nl}";
		my @domains = get_users_domain_list( $user );
		foreach my $domain ( @domains ) {
			if ($domain) {
				print "holding domain: $domain...";
				system "$sudo $vmoduser -ipswr $domain";
				print "done.${nl}";
#				my @users = get_domains_userlist( $domain );
#				if ( $users[0] ) {
#					foreach my $user ( @users ) {
#						system "$sudo $vmoduser -ipswr $user\@$domain";
#						print "$sudo $vmoduser -ipswr $user\@$domain${nl}" if $debug;
#					};
#				};
			};
		};
		print "done.${nl}${nl}";
		print "+100 hold/unhold Done.${nl}${nl}";
	} else {
		&print_error("$name hold <username>${nl}");
	};
};

sub unhold_user {
	print $version;
	my $user = $ARGV[1];
	if ( $secure_levels ) { check_permissions("2") };
	if ( $user ne "" ) {
		print $version;
		print "${nl}${nl}   Enabling ${user}'s ability to retrieve email...${nl}";
		my @domains = get_users_domain_list( $user );
		foreach my $domain ( @domains ) {
			if ($domain) {
				print "Enabling domain: $domain...";
				system "$sudo $vmoduser -x $domain"; };
				print "done.${nl}";
#				my @users = get_domains_userlist( $domain );
#				foreach my $user ( @users ) {
#					if ($user) { system "$sudo $vmoduser -x $user\@$domain"; };
#				};
#			};
		};
		print "done.${nl}${nl}";
		print "+100 hold/unhold Done.${nl}${nl}";
	} else {
		&print_error("$name unhold <username>${nl}");
	};
};

# Suspending a domain 
#   
#   The mail server has two parameters it needs to find a user, the domain
#   mapping and the system user. To suspend a domain, we simply remove the  
#   domain mapping.

sub suspend {
	print $version;
	#
	# This way is now disabled.  Due to vpopmail changes (all for the better)
	# this stopped working and I need to revisit this and add a bunch of code
	# to make it do The Right Stuff[TM].
	#
	my $user = $ARGV[1];
	if ( $secure_levels ) { check_permissions("1") };
	if ( $user ne "" ) {
		print $version;
		&archive_user( $user );
		print "${nl}${nl}   Then we'll remove the domains from the config files...";
		my @domains = &get_users_domain_list( $user );
		foreach my $domain ( @domains ) {
			my $cmd = "$sudo $vdeldomain $domain";
			print "$cmd${nl}" if $debug;
			system $cmd;
		};
		print "done.${nl}${nl}  And then tell the mail servers about it...";
		&update_command("mail");
		print "done.${nl}${nl}";
	} else {
		&print_error("$name suspend <username>${nl}");
	};
};


# Restore a domain 

sub restore {
	print $version;
	my ($user) = @_;
	my $tar      = FindTheBin("tar");
	if ( $secure_levels ) { check_permissions("1") };
	if ( $user ne "" ) {
		if ( getpwnam($user) > 0 ) {           # Make sure user exists
			print $version;
			my $homedir = get_users_homedir( $user );
			
			my @pathparts = split("/", $homedir);
			my $userdir   = pop @pathparts;
			my $path      = join("/", @pathparts);
			chdir($path) or warn "couldn't cd to $path: $!${nl}";

			if ( !-e "$user.tar.gz" ) {
				warn "\tFAILED: $path/$user.tar.gz doesn't exist.${nl}";
				return 0;
			};

			if ( -d "$user" ) {
				warn "\tFAILED: $path/$user already exists.${nl}";
				return 0;
			};

			print "${nl}${nl}\tFirst extract all their files...";
			system "$sudo $tar -xzf $user.tar.gz";
			if ( $delete_old_archives ) {
				system "$sudo $rm $user.tar.gz";        # Delete the archive.
			};
			print "   Restoring $user's domains....";
			my @domains = get_users_domain_list( $user );
			foreach my $domain (@domains) {
				system "$sudo $vadddomain -u $user $domain secret";
			};

			#
			# We need to go back through now and add all the mail users to
			# the SQL database. Conversion to MySQL auth broke this - 12.12.02
			#

			print "done.${nl}${nl}  Finally, tell the mail servers about it...";
			&update_command("mail");
			print "done.${nl}${nl}";
		} else {
			die "   FAILED: The user $user doesn't exist.${nl}${nl}";
		};
	} else { 
		&print_error("$name restore <username>");
	};
};

# Restore a domains vpasswd file.

sub vpassrestore { 
	print $version;
	my $user   = $ARGV[1];
	my $domain = $ARGV[2];
	my $find   = FindTheBin("find");
	if ( $secure_levels ) { check_permissions("2") };
	if ( $user ne "" ) {
		my $userdir = get_users_homedir( $user );   
		my $domaindir = "$userdir/domains/$domain";
		my @vpr_userlist;
		my @dirtylist=`$sudo $find $domaindir -name Maildir -type directory`;
		print @dirtylist if $debug;
		foreach my $dir ( @dirtylist ) {
			chomp $dir;
			my @fields=split("/", $dir );
			if ( $fields[9] eq "Maildir" ) {
				push @vpr_userlist, $fields[8];
			} elsif ( $fields[10] eq "Maildir" ) {
				push @vpr_userlist, $fields[9];
			} elsif ( $fields[11] eq "Maildir" ) {
				push @vpr_userlist, $fields[10];
			} else {
				print "uh-oh, report this error to matt!${nl}";
			};
		};
		my $file = "/tmp/$domain";
		my $file2 = "$domaindir/vpasswd";
		open NEWVPASS, ">$file";
			my $counter = 0;
			foreach my $user ( @vpr_userlist ) {
				if ( $user ne "vpasswd" && $user ne "vpasswd.cdb" && $user !~ /^\./ ) {
					my $line = "$user:nWCF8/.cJUZ5.:1:0:$user:$domaindir/$user:100000000";
					print NEWVPASS "$line${nl}";
				};
				++$counter;
			};
		close NEWVPASS;
		system "$sudo $cp $file $file2";
		system "$sudo $vmkpasswd $domain";
		system "$sudo $rm $file";
		print "${nl}${nl}OK, the vpasswd file lives in $file2${nl}${nl}";
		print " The default passwords have been reset to 'temp'${nl}";
	} else { 
		&print_error("$name vpassrestore <username> <domain>");
	};
};


# Modify a domain 
#
#    The modify command can accept one of two options: quota, or password.
#    We expect the modify command to be passed to us with one of those 
#    keywords and a value to set. 
sub modify {
	print $version;
	if ( $secure_levels ) { check_permissions("3") };
	my $target = $ARGV[1]; my $two = $ARGV[2];
	my $thr    = $ARGV[3]; my $fou = $ARGV[4];

	if ( $target ne "" ) {
		if ( $target eq "quota" && $ARGV[4] ne "" ) {
			my $sub = $ARGV[2]; my $user = $ARGV[3]; my $quota = $ARGV[4];
			if ( $sub eq "main" ) {
				setupquota($user, $quota);
				my $maindomain = (get_main_domain($user))[0];
				print "main domain is: $maindomain${nl}" if $debug;
				system "$sudo $vsetuserquota postmaster\@${maindomain} ${quota}400000";
				print "completed.${nl}${nl}";
			} elsif ( $sub eq "domain" ) {
				my $domain = $user;
				print "${nl}Modifying postmaster\@${domain}'s quota to $quota megabytes....";
				system "$sudo $vsetuserquota postmaster\@$domain ${quota}400000";
				print "completed.${nl}${nl}";
			} elsif ( $sub eq "user" ) {
				if ( $user =~ /^all/ ) {
					my $domain=(split(/\@/, $user))[1];
					system "$sudo $vsetuserquota $domain ${quota}400000";
				} else {
					print "   ${nl}Modifying ${user}'s quota to $quota megabytes....";
					system "$sudo $vsetuserquota ${user} ${quota}400000";
				};
				print "completed.${nl}${nl}";
			};
		} elsif ( $target eq "password" && $ARGV[3] ne "" ) {
			my $user = $ARGV[2]; my $quota = $ARGV[3];
			print "\t${nl}Modifying ${user}'s password to $quota...";
			my $cmd = "$sudo $vpasswd $user $quota";
			system $cmd;
			print "done.${nl}${nl}";
			print "${nl}cmd is: ${cmd}${nl}" if $debug;
		} elsif ( $target eq "limits" && $ARGV[2] ne "" ) {
			my $user = $ARGV[2];
			edit_qmailadmin_limits($target, $user);
		} else {
			&print_modify_menu;
		};
	} else { 
		&print_modify_menu;
	};
};

sub print_modify_menu {
	print "${nl}I need you to pass me a command like this:${nl}${nl}";
	print "      $name modify password     <user\@domain.com> <newpass>${nl}";
	print "  or  $name modify limits       <username>${nl}";
	print "  or  $name modify quota main   <username> <value>${nl}";
	print "  or  $name modify quota domain <domainname> <value>${nl}";
	print "  or  $name modify quota user   <user\@domain> <value>${nl}";
	print "  or  $name modify quota user   <all\@domain> <value>${nl}";
	print "${nl}";
};

# Delete a domain
# 
#   The delete domain script can (optionally) be called with any non-zero value
#   and if so, it will first archive the domain home directory before blowing it
#   away. The pw utility does not, by default, remove the domain home directory
#   so we pass it the "-r" flag.
#

sub delete_sys_user {
	my ($user, $ar ) = @_;
	my $pw = FindTheBin("pw");
	if ( getpwnam($user) > 0 ) {                 # Make sure user exists
		if (getpwnam($user) < 100 ) {
			die "you naughty little bastard!${nl}";
		};
		print $version;
		if ( $ar ne "" ) {                   # Check for archive flag
			archive_user( $user );
		}; 
		print "   Deleting $user's home directory...."; 
		system "$sudo $pw userdel -n $user -r";
		print "done.${nl}${nl}  Now we'll tell all the pass servers about it...";
		&update_command("passwd");
		print "done.${nl}";
		print "+100 deldomain Done.${nl}${nl}";
	} else {
		print $version;
		print "   FAILED: That user doesn't exist.${nl}${nl}";
		print "+100 deldomain Done.${nl}${nl}";
	};
};

sub archive_user {
	my ($user)    = @_;
	my $tar      = FindTheBin("tar");
	my $homedir   = &get_users_homedir( $user );
	my @pathparts = split("/", $homedir);
	my $userdir   = pop @pathparts;
	my $path      = join("/", @pathparts);
	chdir($path) or warn "couldn't cd to $path: $!${nl}";
	if ( -e "$path/$user.tar.gz" && -d "$path/$user" ) {
		warn "\tOverwriting old tarfile $path/$user.tar.gz.${nl}";
		system "$sudo $rm $path/$user.tar.gz";
	};
	print "\tArchiving $user's files to $path/$user.tar.gz...."; 
	system "$sudo $tar -Pzcf $user.tar.gz $userdir";
	if ( -e "${homedir}.tar.gz" ) {
		print "done.${nl}${nl}";
		return 1;
	} else {
		warn "FAILED: couldn't complete archiving of $path/$user.tar.gz.${nl}${nl}";
		return 0;
	};
};

sub update_command {
	my ($cmd) = @_;
	print "$sudo $update $cmd" if $debug;
	system "$sudo $update $cmd";
};

sub delete_domain {
	my @domains = @_;
  	if ( $domains[0] ne "" ) {
		foreach my $domain ( @domains ) {
			print "\tRemoving the domain $domain from the config files...";
			system "$sudo $vdeldomain $domain";
			print "done.${nl}";
		};
		&update_command("mail");
	};
};

sub set_homedir {
	my ($user, $domain) = @_;
	my $homedir;
	my $tmp;
	if ( $homedir_base eq "u" ) {
		$tmp = $user;
	} else {
		$tmp = $domain;
	};
	if ( $homedirtree ) {
		my $tmp1 = substr($tmp, 0, 1);              # Grab the first char of their login
		my $tmp2 = substr($tmp, 0, 2);              # Grab the first two characters
		$homedir = "$home/$tmp1/$tmp2/$tmp";        # Define their home directory
	} else {
		$homedir = "$home/$user";
	};
	return $homedir;
};

sub get_domains_userlist {
	my ($domain) = @_;
	if (lc($vauth) eq "cdb") {
		my @users;
		my $domaindir = get_domains_homedir($domain);
		print "The domain $domain is at: $domaindir${nl}" if $debug;

		open (VPASS, "$domaindir/vpasswd");
			while ( <VPASS> ) {
				my @parts=split(/:/, $_);
				print "username is: $parts[0]${nl}" if $debug;
				push @users, $parts[0];
			};
		close VPASS;

		return @users;
	} else {
		warn "get_domains_userlist doesn't work with $vauth yet.${nl}";
		return 0;
	};
};

sub get_users_domain_list {
	my ($user)  = @_;
	my @domain_list;
	print $version;

	if ( &DoesSysUserExist($user) ) {
		my $homedir = &get_users_homedir($user);
		if ( $homedir) {
			print "found homedir${nl}";
			my $domaindir = "$homedir/domains";
			print "get_users_domain_list: domaindir: $domaindir${nl}" if $debug;
			if ( -d $domaindir ) {
				opendir DOMAINDIR, "$domaindir" or die "FAILED: Can't read $domaindir: $!${nl}";
				while ( defined (my $file = readdir DOMAINDIR) ) {
					next if $file =~ /^\..*$/;
					my @parts=split("/", $file);  # Strip off the path 
					push @domain_list, $parts[$#parts];
				};
				closedir DOMAINDIR;
				print "get_users_domain_list: @domain_list${nl}" if $debug;
				return @domain_list;
			};
		} else {
			my $uid = getpwnam($user);
			if ($uid < 100) { return 0; };
			my $homedir = (getpwnam($user))[7];
			my $mkdir = FindTheBin("mkdir"); $mkdir = "$mkdir -p";
			my ($maindomain) = &get_main_domain($user);
			if ($maindomain) {
				my $exists = &does_domain_exist_in_qmail($maindomain);
				if ($exists) {
					print "${nl}The home directory for $user is $homedir and has${nl}";
					print "$maindomain set up to use it! That domain is not working${nl}";
					print "and should likely be removed from the mail system. ${nl}";
					print "${nl}Shall I? ";

					my $ans = YesOrNo;
					if ($ans) {
						print "deleting main domain: $maindomain${nl}";
						print "$sudo $mkdir $homedir/domains/$maindomain${nl}" if $debug;
						system "$sudo $mkdir $homedir/domains/$maindomain";
						print "$sudo $chown -R $user $homedir${nl}" if $debug;
						system "$sudo $chown -R $user $homedir";
						&delete_domain($maindomain);
					};
				};
			} else {
				print "the domain $maindomain doesn't exist as a main domain.${nl}";
			};

			my $assign = "$qmailpath/users/assign";
			my @domains = &get_mail_domains_from_assign($assign, "uid", $uid);
			if ($domains[0] ne "" ) {
				print "${nl}Yikes! The home directory for $user is $homedir and it doesn't${nl}";
				print "exist. As such, the following domains should likely be removed:${nl}${nl}";
				foreach my $f ( @domains ) {
					print "\t$f->{'dom'}${nl}";
				};
				print "${nl}Shall I delete it? ";

				my $ans = YesOrNo;
				if ($ans) {
					foreach my $domain (@domains) {
						print "deleting domain: $domain->{'dom'}${nl}";
						print "$sudo $mkdir $homedir/domains/$domain->{'dom'}${nl}" if $debug;
						system "$sudo $mkdir $homedir/domains/$domain->{'dom'}";
						print "$sudo $chown -R $user $homedir${nl}" if $debug;
						system "$sudo $chown -R $user $homedir";
						&delete_domain($domain->{'dom'});
					};
				};
			};

			my @domains = &get_mail_domains_from_assign($assign, "uid", $uid);
			if ($domains[0] eq "" ) {
				print "User $user has no domains, shall I just delete them? ";
				my $ans = YesOrNo;
				if ($ans) {
					&delete_sys_user($user);
				};
			};
			return 0;
			#
			# FOO
			#
		};
		#
		# TO DO
		# This needs to check for alias domains as well. Must do that
		# with MySQL calls
		#
	} else {
		print "FAILED, invalid user: $user.${nl}";
		return 0;
	};
};


sub show_files_where_domain_exists {
	my ($domain) = @_;
	my @files = ( "$qmailpath/users/assign", "$qmailpath/control/*" );
	foreach my $file (@files) {
		system "grep $domain $file";
	};
};

sub show_settings {
	my $one = $ARGV[1]; my $two = $ARGV[2]; my $thr = $ARGV[3];
	my $quota_bin = FindTheBin("quota");

	if ( $secure_levels ) { check_permissions("3") };
	if ( $one eq "quota" ) {
		print $version;
		system "$sudo $quota_bin $two";
		print "${nl}${nl}"; 
		my @domain_list = get_users_domain_list( $two );
		foreach my $domain ( @domain_list ) {
			print "${nl}              *********  domain quota for $domain (in bytes) *********${nl}";
			system "$sudo $vuserinfo -q postmaster\@$domain";
		};
		print "${nl}";
	} elsif ( $one eq "userquota" ) {
		print $version;
		system "$sudo $vuserinfo -q $two";
		print "${nl}";
	} elsif ( $one eq "all" ) {
		print $version;
		system "$sudo $quota_bin $two";
		print "${nl}${nl}"; 
		my @domvals = get_main_domain( $two );
		print "           *********  main domain is $domvals[0]  *********${nl}";
		my $cmd = "$sudo $vdominfo $domvals[0]";
		system $cmd;
		my @domain_list = get_users_domain_list( $two );
		foreach my $domain ( @domain_list ) {
			if ($domain ne "" ) {
				print "${nl}              *********  info for $domain  *********${nl}";
				system "$sudo $vdominfo $domain";
				system "$sudo $vuserinfo postmaster\@$domain";
			};
		};
	} else {
		print $version;
		print "${nl}   Valid choices are: ${nl}${nl}";
		print "      quota     - Display quota for a user account and their domains (user)${nl}";
		print "      userquota - Display quotas for an email account (user\@domain.com)${nl}";
		print "      all       - Display all info for a user and their domains${nl}${nl}";
	};
};


sub get_main_domain {
	my ($user) = @_;
	my $passwd;
	my ($dom,$dir)=(getpwnam($user))[6,7]; 
	print "the homedir for $user is: $dir${nl}" if $debug;

	if ( $vauth eq "cdb" ) {
		open( PASS, "<$dir/domains/$dom/vpasswd" );
			foreach my $line (<PASS>) {
				#print $line;
				my @fields = split(":", $line);
				if ( $fields[0] eq "postmaster" ) {
					$passwd=$fields[1];
				};
			};
		close( PASS );
	} else {
		$passwd = `$vuserinfo -p postmaster\@$dom`;
	};
	print "postmaster password: $passwd${nl}" if $debug;
	return $dom, $passwd;
};


sub set_pass_to_main {
	my @vpasswd;
	#print "opening file $_[0]/domains/$_[1]/vpasswd.${nl}";
	open( PASS, "+<$_[0]/domains/$_[1]/vpasswd" );
		my $counter = 0;
		foreach my $line ( <PASS> ) {
			my @fields = split( ":", $line );
			if ( $fields[0] eq "postmaster" ) {
				#print "inserting $_[2] into the password field.${nl}";
				$fields[1] = $_[2];
				$vpasswd[$counter] = join(":", @fields);
			} else {
				$vpasswd[$counter] = $line;
			};
			#print $vpasswd[$counter];
			++$counter;
		};
	close( PASS );
	open( PASS, ">$_[0]/domains/$_[1]/vpasswd" );
		foreach my $line ( @vpasswd ) {
			print PASS $line;
		}; 
	close( PASS );
	#print @vpasswd;
};

sub does_domain_exist_in_qmail {
	my $grep = FindTheBin("grep");
	my $assign =`$grep "+${_[0]}" $qmailpath/users/assign`;
	my @assign_parts = split( /:/, $assign );
	print "${nl}${nl}  $assign  ${nl}${nl} $assign_parts[1] ${nl}${nl}" if $debug;
	if ( $assign_parts[1] eq "$_[0]" ) {
		return "1";
	} else {
		return "0";
	}; 
};

sub make_home_dir_tree {
	my @alpha = qw(a b c d e f g h i j k l m n o p q r s t u v w x y z);
	my @num = qw( 1 2 3 4 5 6 7 8 9 0 );
	my $mkdir = FindTheBin("mkdir"); $mkdir = "$mkdir -p";
	foreach my $iter (@alpha) {
		foreach my $iter2 (@alpha) {
			print "creating directory /usr/home/${iter}/${iter}${iter2}${nl}";
			system "$mkdir /usr/home/${iter}/${iter}${iter2}";
		};
		foreach my $iter2 ( @num ) {
			print "creating directory /usr/home/${iter}/${iter}${iter2}${nl}";
			system "$mkdir /usr/home/${iter}/${iter}${iter2}";
		};
	};
};

sub get_number {
	my ($min, $max) = @_;
	my $ans;
	do {
		print "($min-$max:) ";
		$ans = <STDIN>;
		chomp($ans);
	} until ( $ans >= $min && $ans <= $max );
	return $ans;
};

sub edit_qmailadmin_limits {
	my ( $target, $user ) = @_;
	print " Do, you want to edit domain limits for $user? ";
	my $answer = YesOrNo;
	if ( $answer ) {
		print "${nl}\t 0 = disabled and empty is unlimited${nl}${nl}";
		print "\t Please specify the maximum number of POP accounts: "; 
		my $maxpop = &get_number("0", "1000");
		print "\t Please specify the maximum number of aliases: "; 
		my $maxalias = &get_number("0", "1000");
		print "\t Please specify the maximum number of forwards: "; 
		my $maxforward = &get_number("0", "1000");
		print "\t Please specify the maximum number of mailing lists: "; 
		my $maxlist = &get_number("0", "100");
		print "\t Please specify the maximum number of autoresponders: "; 
		my $maxauto = &get_number("0", "1000");
		print "${nl}${nl}\tmaxpopaccounts\t\t$maxpop${nl}\tmaxaliases\t\t$maxalias${nl}";
		print "\tmaxforwards\t\t$maxforward${nl}\tmaxmailinglists\t\t$maxlist${nl}";
		print "\tmaxautoresponders\t$maxauto${nl}";
		print "${nl}${nl}   Your file looks like this, go ahead and install? : ";
		my $install = YesOrNo;
		if ( $install ) {
			my @domains = &get_users_domain_list( $user );
			foreach my $domain ( @domains ) {
				my $homedir = get_domains_homedir($domain);
				print "${nl}Installing file $homedir/.qmailadmin-limits...";
				open ( LIMITS, ">/tmp/.qmailadmin-limits" );
					print LIMITS "maxpopaccounts\t\t$maxpop${nl}maxaliases\t\t$maxalias${nl}";
					print LIMITS "maxforwards\t\t$maxforward${nl}maxmailinglists\t\t$maxlist${nl}";
					print LIMITS "maxautoresponders\t$maxauto${nl}";
				close LIMITS;
				system "$sudo $cp /tmp/.qmailadmin-limits $homedir${nl}";
				system "$sudo $chown $user:vchkpw $homedir/.qmailadmin-limits${nl}";
				print "done.${nl}";
			};
			unlink "/tmp/.qmailadmin-limits";
		}; 
	} else {
		print "${nl}. Ok then, see ya later.${nl}";
	};
};

sub get_domains_homedir {
	my ($domain) = @_;
	print "get_domains_homedir: searching for: $domain${nl}" if $debug;
	my @lines = `grep +${domain} $qmailpath/users/assign`;
	my $rows = @lines;
	if ( $rows > 1 ) {
		print "Oh crap, you've got duplicate entries for $domain. You need to fix that!${nl}";
		print @lines;
		return 0;
	} elsif ( $rows < 1 ) {
		print "Sorry, $domain doesn't exist${nl}";
		return 0;
	} else {
		my $domaindir = (split(/:/, $lines[0]))[4];
		print "domaindir is: $domaindir${nl}" if $debug;
		return $domaindir;
	};
};

sub get_users_homedir {
	my ($user) = @_;
	my $homedir = (getpwnam($user))[7];
	if ( -d $homedir ) {
		return $homedir;
	} else {
		warn("get_users_homedir: WARNING, $user's home missing ($homedir).${nl}");
		return 0;
	};
};

sub setupquota {
	my ($user, $quota) = @_;
	my $ssh      = FindTheBin("ssh");
	my $setquota = FindTheBin("setquota");
	if (!-e $setquota) { InstallPort("setquota", "sysutils"); };

	my $quotabump = $quota + 5;
	if ($fileservers[0] ne "") {
		foreach my $host (@fileservers) {
    		print "done.${nl}   Set the $host quota for $user to $quota megabytes...";
			my $cmd = "$ssh $host \"$sudo $setquota -u -f $quotafs -bh${quotabump}M -bs${quota}M $user\"";
			print "${nl}$cmd${nl}" if $debug;
			system "$cmd";
		};
	};
	print "done.${nl}";
};

sub reset_default_delivery {
	my $user    = getpwuid( $_[0]);
	my $homedir = get_users_homedir($user);
	
	my $domain = (getpwnam($user))[6];             # Fetch from gecos
	print "$domain${nl}" if $debug;
	my $defaultfile="$homedir/domains/$domain/.qmail-default";
	my $string = "| $vdelivermail '' bounce-no-mailbox";
	print "writing $string to $defaultfile${nl}" if $debug;
	open (FILE, "> $defaultfile") or die "Couldn't open $defaultfile for writing: $!${nl}";
		print FILE "$string${nl}";
	close FILE;
	print "The .qmail-default file for $domain has been updated.${nl}${nl}";
};

sub check_permissions {
	if ( $_[0] == "0" && $sl <= "1" ) {
		print "passed secure level 0 with $sl.${nl}${nl}" if $debug;
	} elsif ( $_[0] == "1" && $sl <= "1" ) {
		print "passed secure level 1 with $sl.${nl}${nl}" if $debug;
	} elsif ( $_[0] == "2" && $sl <= "2" ) {
		print "passed secure level 2 with $sl.${nl}${nl}" if $debug;
	} elsif ( $_[0] == "3" && $sl <= "3" ) {
		print "passed secure level 3 with $sl.${nl}${nl}" if $debug;
	} elsif ( $_[0] == "4" && $sl <= "4" ) {
		print "passed secure level 4 with $sl.${nl}${nl}" if $debug;
	} else {
		print "Sorry but you don't have permission!${nl}";
		exit;
	};
};

sub print_error {
	my ($error) = @_;
	print "${nl}${nl}\tI need you to pass me a command like this:${nl}${nl}";
	print "\t$error${nl}${nl}";
};

sub sudo_setup {
	my $sudobin = FindTheBin("sudo");
	if (! $sudobin) { InstallPort("sudo", "security"); };    
	$sudobin = FindTheBin("sudo");
	my $sudo = "";
	if ( $< ne "0" ) {
		$sudo = "$sudobin -p 'Password for %u@%h:'";
	};
	return $sudo;
};       

sub set_securelevel {
	my ($iam) = @_;
	if ( ! $secure_levels ) { return 0; };
	if ( $< ne 0 ) {
		if ( $iam eq "matt" || $iam eq "seaupdel" )    { return 0; }
		elsif ( $iam eq "support3" )                   { return 1; }
		elsif ( $iam eq "support2" )                   { return 2; }
		elsif ( $iam eq "support1" )                   { return 3; }
		elsif ( $iam eq "techsupport" )                { return 3; }
		elsif ( $iam eq "www"         )                { return 0; }
		else                                           { return 4; };
	} else {
		return 0;
	};
};

sub check_hostname {
	my ($adminhost) = @_;
	# Make sure we are running on the admin box
	#
	my $host = hostname();
	print "My hostname is: $host${nl}" if ($debug);
	if ($host ne $adminhost) { 
		print "${nl} WARNING! You're not running this on $adminhost!${nl}${nl}";
	};
};

sub exec_all {
	print $version;
	if ( $secure_levels ) { check_permissions("0") };
	my $ssh      = FindTheBin("ssh");
	if ( $ARGV[1] ne "" ) {
		print $version;
		print "executing $ARGV[1] on all systems...${nl}";
		foreach my $host ( @mailservers ) {
			system "$ssh $host $ARGV[0] $ARGV[1] $ARGV[2] $ARGV[3]";
		}
	} else {
		print "\tYou have you to give me a command to execute!${nl}";
	};
};

sub count_users {
	my $totalusers="0";

	if ( $vauth eq "cdb" ) {
		my $assign = "$qmailpath/users/assign";
		my @domainlist = &get_mail_domains_from_assign($assign);
		foreach my $file ( @domainlist ) {
			my $numusers = count_cdb_users( "$file->{'dir'}/vpasswd" );
			my $totalusers = $totalusers + $numusers;
			print "$file has $numusers\t" if $debug;
		};
		print "There are $totalusers total users on the system${nl}${nl}";
	} else {
		#
		# TO DO
		#
		print "don't support that auth method yet!${nl}";
	};
};

sub get_mail_domains_from_assign {
	my ($assign, $match, $value) = @_;
	my @domains;
	my @lines = ReadFile($assign);
	print "Parsing through the file $assign..." if $debug;;
	foreach my $line (@lines) {
		chomp $line;
		my @fields = split(":", $line);
		if ($fields[0] ne "" && $fields[0] ne ".") {
			my %domain = (
				stat => "$fields[0]",
				dom  => "$fields[1]",
				uid  => "$fields[2]",   
				gid  => "$fields[3]",
				dir  => "$fields[4]"   
			);
			if ( !$match) {
				push @domains, \%domain;
			} else {	
				if      ( $match eq "dom" && $value eq "$fields[1]" ) {
					push @domains, \%domain;
				} elsif ( $match eq "uid" && $value eq "$fields[2]" ) {
					push @domains, \%domain;
				} elsif ( $match eq "dir" && $value eq "$fields[4]" ) {
					push @domains, \%domain;
				};
			};
		};
	};
	print "done.${nl}${nl}." if $debug;;
	return @domains;
}

sub count_cdb_users {
	open ( USERLIST, $_[0] ) || warn "couldn't open $_[0]: $!${nl}";
		my @users = <USERLIST>;
	close (USERLIST);
	my $numusers = @users;
	print "There are $numusers in $_[0]${nl}" if $debug;
	return $numusers;
}

sub check {
	print $version;
	if ( $secure_levels ) { check_permissions("0") };
	if ( $ARGV[1] eq "duplicates" && $ARGV[2] ) {
		&check_duplicates();
	} elsif ( $ARGV[1] eq "domain-dir") {
		&check_domain_owners_home_dir;
	} elsif ( $ARGV[1] eq "count") {
		&count_users;
	} elsif ( $ARGV[1] eq "homedir-owners") {
		&check_ownership_of_all_homedirs;
	} elsif ( $ARGV[1] eq "qmail-default") {
		&check_qmail_default_files;
	} elsif ( $ARGV[1] eq "migrate" && $ARGV[2] ) {
		&migrate_mail_files($ARGV[2], $ARGV[3]);
	} elsif ( $ARGV[1] eq "rcpthosts") {
		&check_rcpthosts;
	} else {
		print "usage: $0 $ARGV[0] duplicates [uid] [name] [domain]${nl}";
		print "       $0 $ARGV[0] count${nl}";
		print "       $0 $ARGV[0] domain-dir${nl}";
		print "       $0 $ARGV[0] homedir-owners${nl}";
		print "       $0 $ARGV[0] qmail-default${nl}";
		print "       $0 $ARGV[0] rcpthosts${nl}";
		print "       $0 $ARGV[0] migrate <dest-serv> [letter] ${nl}";
	};
};

sub check_duplicates {
	my $sortf;
	my $full = "/tmp/full";
	my $sort = "/tmp/sort";
	my $uniq = "/tmp/uniq";

	if ( $ARGV[2] eq "uid" ) {
		print "\tListing all duplicate UIDs from /etc/passwd${nl}";
		$sortf = "2";
	} elsif ( $ARGV[2] eq "name" ) {
		print "\tListing all duplicate user names from /etc/passwd${nl}";
		$sortf = "0";
	} elsif ( $ARGV[2] eq "domain" ) {
		print "\tListing all duplicate main domains from /etc/passwd${nl}";
		$sortf = "6";
	} else {
		print "usage: $0 $1 [uid] [name]${nl}";
		exit 0;
	};

	if ( -e $full ) { system "$sudo $rm $full"; };

	open( FULL, ">$full" ) or die "couldn't open for write $full${nl}";
		while ( my @f = getpwent ) {
			print FULL "$f[$sortf]${nl}";
		};
	close( FULL );

	if ( -e $full ) {
		system "$sudo sort $full > $sort";
		system "$sudo $rm $full";
		system "$sudo sort -u $sort > $uniq";
		system "diff $sort $uniq";
		system "$sudo $rm $sort";
		system "$sudo $rm $uniq";
	} else {
		print "$full doesn't exist${nl}";
	};
};

sub check_domain_owners_home_dir { 
	my %pass; 
	my $minuid   = 1000;
	my $assign   = "$qmailpath/users/assign";
	my @lines    = &get_mail_domains_from_assign( $assign );
	my $c = @lines;

	print "Checking $c home directories...";
	foreach my $v (@lines) {
		my @f = split("/", $v->{'dir'} );
		my $home1 = "/$f[1]/$f[2]/$f[3]/$f[4]/$f[5]";
		if ( $f[1] eq "" ) { next; };
		# name, passwd, uid, gid, quota, comment, gcos, dir, shell = getpwuid
		my ($name, $uid, $dir ) = (getpwuid($v->{'uid'}))[0,2,7];

		if ( $uid eq getpwnam("vpopmail") ) {  
			next;
		} elsif ( $home1 ne $dir ) {
			if ( ! %pass->{$f[5]} && $name ) {
				print "\t qmuid: $v->{'uid'} \t qmdir: $v->{'dir'}\t qmdom: $v->{'dom'}${nl}";
				print "\t   uid: $uid \t pwdir: $dir${nl}";
				#print "$f[5]:*:$i:88::0:0:$v->{'dom'}:$home1:/sbin/nologin${nl}";
				#print "$chown -R $f[5] ~$f[5]${nl}";
				#print "edquota -p phark $f[5]${nl}";
				%pass= ( $f[5] => 1 );
				print "${nl}";
			};
			if ( !-e $v->{'dir'} ) {
				print "WARNING: $v->{'dir'} does not exist!${nl}";
			};
			$minuid++;
		};
	};
	print "done.${nl}${nl}";
};

sub check_rcpthosts {
	my $assign = "$qmailpath/users/assign";
	my @domains = &get_mail_domains_from_assign($assign);
	
	my $morercpthosts = "$qmailpath/control/morercpthosts";
	my @f1 = ReadFile("$qmailpath/control/rcpthosts");
	my @f2 = ReadFile($morercpthosts);
	my %rcpthosts;

	foreach my $f (@f1, @f2) {
		chomp $f;
		$rcpthosts{$f} = 1;
	};


	foreach my $v (@domains) {
		my $domain = $v->{'dom'};
		if ( ! $rcpthosts{$domain} ) {
			print "$domain${nl}";
		};
	};
	print "${nl}Any domains listed above should be added to the file ";
	print "$morercpthosts. Don't forget to do this afterwards:${nl}${nl}";
	print "\t$qmailpath/bin/qmail-newmrh${nl}";
	print "\tupdate mail${nl}${nl}";
};

sub check_ownership_of_all_homedirs {
	# name, passwd, uid, gid, quota, comment, gcos, dir, shell
	my $n;
	setpwent();
	while( my ($name, $uid, $dir) = (getpwent())[0,2,7] ) {
		if ( $uid < 100 ) { next; };
		if ( $name eq "nobody" ) { next; };

		if (!-e $dir) {
	 		print "WARNING: ${name}'s home dir: $dir, does not exist.${nl}";
			&get_users_domain_list($name);
			next;
		}

		my @dir_stat = stat($dir) or die "Couldn't stat $dir: $!${nl}";

		if ( $uid != $dir_stat[4] ) {
			print "warning: $name is $uid, but $dir is owned by $dir_stat[4].${nl}";
			print "Would you like me to fix it? ";
			my $answer = YesOrNo;
			if ($answer) {
				system("$sudo $chown -R $name $dir");
				print "Changed $dir to be owned by $name${nl}${nl}";
				next;
			} else {
				next;
			}
		}
	};
	endpwent();
}

sub check_qmail_default_files {
	my $updated = 0;
	my $skipped = 0;
	my $counter = 0;

	if ( $iam ne "root" ) {
		die "Sorry, this option must be run as root.${nl}";
	} else {
		print "\tThis goes through and finds every .qmail-default file${nl}";
		print "\ton your mail server and verifies it's accuracy. This${nl}";
		print "\tis particularly useful with older vpopmail installs${nl}";
		print "\twhere users could malform this files contents.${nl}";
		print "${nl}\tIt takes a while to run, be patient or Ctrl-C to cancel.${nl}";
	};

	&find(\&wanted, '/home');
	print "${nl}\t updated: $updated \t skipped: $skipped ${nl}";

	sub wanted {
		/^\.qmail-default$/ &&
		(my ($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_)) &&
		&check_default_file($File::Find::name);
	};

	sub check_default_file {
		my ($file) = @_;
		my @lines    = ReadFile($file);
		my $lines_c  = @lines;
	
		if ( $lines_c == 1 ) {
			chomp $lines[0];
			my $newline = &check_delivery($lines[0]);
			
			if ($newline) {
				print "oldline: $lines[0]${nl}";
				print "newline: $newline${nl}${nl}";
				&WriteFile($file, $newline);
				$updated++;
			} else {
				$skipped++;
			};

		} else {
			print "There's $lines_c lines in $file${nl}";
		};
		$counter++;
		if ($counter =~ /00$/ ) { 
			print "${nl}\t updated: $updated \t skipped: $skipped ${nl}";
		};
	};
};

sub check_delivery {
	my ($line) = @_;
	my ($pipe, $vdel, $qq, $def, $huh) = split(/ /, $line);

	if ($huh) { return 0; };

	if ($vdel eq "''" && $pipe =~ /^|\// ) {
		$def  = $qq;
		$qq   = $vdel;
		$vdel = $vdelivermail;
		$pipe = "|";
		$line = join(/ /, $pipe, $vdel, $qq, $def);
		return $line;
	};

	if ( $pipe eq /^|/ ) {
		$vdel = &check_vdelivermail_bin( $vdel );
		$def  = &check_default_delivery( $def );
		if ( $vdel && $def ) {
			$line = join(/ /, $pipe, $vdel, $qq, $def);
			return $line;
		} else {
			return 0;
		};
	} else {
		return 0;
	};

};

sub check_default_delivery {
	my ($current ) = @_;
	my $default = "bounce-no-mailbox";
	if ( $current eq $default ) {
		return $default;
	} elsif ( $current eq "delete" ) {
		return "delete";
	} elsif ( -d $current ) {
		return $current;
	} else {
		print "delivery unmodified: $current${nl}";
		return 0;
	};
};

sub check_vdelivermail_bin {
	my ($current) = @_;
	my $old = "/usr/home/vpopmail/bin/vdelivermail";

	if ( $current eq $old ) {
		return $vdelivermail;
	} else {
		return 0;
	};
};

sub migrate_mail_files {
	my ($serv, @letters) = @_;

	if ( $iam ne "root" ) {
		die "Sorry, this option must be run as root.${nl}";
	} else {
		print "Please be patient, this takes a while.${nl}";
	};

	LoadModule("Parallel::ForkManager", "p5-DBI", "databases" );

	my @alpha = qw( a b c d e f g h i j k l m n o p q r s t u v w x y z );
	my $rhost = $serv;
	my $rsync = FindTheBin("rsync");
	   $rsync = "$rsync -aW -e ssh --delete";

	my $pm    = new Parallel::ForkManager(4);

	if ( $letters[0] eq "" ) {
		&do_this_letter(@alpha);
	} else {
		&do_this_letter(@letters);
	};

	sub do_this_letter {
		my @nums  = qw( 0 1 2 3 4 5 6 7 8 9 );
		my @todo = @_;
		foreach my $l (@todo) {
			foreach my $d (@alpha, @nums) {
				$pm->start and next;
				my $cmd = "$rsync $home/$l/$l$d $rhost:$home/$l/";
				print "$cmd${nl}";
				system $cmd;
				$pm->finish;
			};
		};
	};
};

1;
__END__


=head1 NAME

        Maildomain - A program to manage large mail systems

=head1 SYNOPSIS

	Maildomain is a handy script used to manage a Matt Simerson style
	http://matt.simerson.net/computing/mail/toaster/ mail toaster. Maildomain
	alters a mail farm and updates each slave in the cluster. 

=head1 DESCRIPTION

	Maildomain is a handy script used to manage a Matt Simerson style
	http://matt.simerson.net/computing/mail/toaster/ mail toaster. Maildomain
	alters a mail farm and updates each slave in the cluster. 

=head2 Dependencies

	The vpopmail package from http://www.inter7.com/vpopmail
	A mechanism to distribute configuration files (rdist/rsync)
	A properly configured /etc/pw.conf file (man pw.conf)
	Properly configured and enabled file system quotas (man quota)
	Setquota (/usr/ports/sysutils/setquota)
	/var/qmail/control/.qmailadmin-limits file configured with 
		settings appropriate for your site

=head1 AUTHOR

        Matt Simerson <matt@cadillac.net>

=head1 BUGS

        None known. Report any to author.

=head1 TODO

        Don't export any of the symbols by default. Move all symbols
        to EXPORT_OK and explicitely pull in the required ones in 
        programs that need them.

=head1 SEE ALSO

        http://matt.simerson.net/computing/mail/toaster/

=head1 COPYRIGHT

        Copyright 2003, Matt Simerson. All Right Reserved.

=cut
