#!/usr/bin/perl

$debug =1;
$exitcode=0;

$courier_alias="/etc/courier/aliases";
$courier_users="/etc/courier/userdb";
$make_aliases="/usr/local/sbin/makealiases";
$courier_domain="/etc/courier/hosteddomains";
$make_domains="/usr/local/sbin/makehosteddomains";
$userdb="/usr/local/sbin/userdb";
$userdbpw="/usr/local/sbin/userdbpw";
$makeuserdb="/usr/local/sbin/makeuserdb";
$maildirmake="/usr/local/bin/maildirmake";
$local_mail="/usr/local/mail";
$customer_dir="/usr/local/htdocs/customer";
$host_conf="/etc/httpd/hosting.conf";
$reload_apache="/etc/init.d/apache reload";
$reload_courier="/usr/local/sbin/courier restart";
$reload_named="/etc/init.d/named reload";
$default_domain="priceorg.com";
$base_ip="194.158.194.17";
$defaultquota=5242880;

local($action)=$ARGV[0];
if($action eq 'add') {
	my($basedomain)=$ARGV[4] ? $ARGV[4] : $default_domain;
	my($crypted)=&encrypt($ARGV[2]);
	print("Addig user $ARGV[1]...\n") if $debug;
	if(system("/usr/sbin/useradd -g www -s /bin/false -p $crypted -d $customer_dir/$ARGV[1] -m -c \'$ARGV[3]\' $ARGV[1]") != 0) { exit 1; }
	chmod 0750, "$customer_dir/$ARGV[1]";
	my($login,$pass,$uid,$gid)=getpwnam($ARGV[1]);
	print("Adding domain $ARGV[1].$basedomain...\n") if $debug;
	system("dnsconf --set $ARGV[1].$basedomain $base_ip");
	$code=system($reload_named);
	&check_status($code,$?,"named reload");
	$code=system("$userdb system/$login set uid=$uid gid=$gid shell=/bin/false gecos=\'$ARGV[3]\' home=$customer_dir/$ARGV[1] quota=$defaultquota");
	&check_status($code,$?,"userdb");
	&add_line("$courier_users/system","$uid=\t$login");
	&mailbox_pass($login,"system",$ARGV[2]);
	print("Adding virtual host...\n") if $debug;
	if(open(FHND,">>$host_conf")) {
	    print FHND qq|
<VirtualHost $base_ip>
	ServerName $ARGV[1].$basedomain
	User $ARGV[1]
	DocumentRoot "$customer_dir/$ARGV[1]/htdocs"
</VirtualHost>
|;
	    close FHND;
	    print("Reloading apache...\n") if $debug;
	    $code=system($reload_apache);
	    &check_status($code,$?,"apache reload");
	} else { exit 2; }
	&new_mailbox($ARGV[1],$basedomain,$ARGV[2]);
} elsif($action eq 'setpass') {
	print("Changing pass for user $ARGV[1]...\n") if $debug;
	my($crypted)=&encrypt($ARGV[2]);
	if(system("/usr/sbin/usermod -p $crypted $ARGV[1]") != 0) { exit 1; }
} elsif($action eq 'newdomain') {
	print("Adding domain $ARGV[2], for user $ARGV[1]...\n") if $debug;
	system("dnsconf --newdomain $ARGV[2]");
	system("dnsconf --setns $ARGV[2] ns.domain.com");
	system("dnsconf --setmx $ARGV[2] mail.domain.com");
	system("dnsconf --set $ARGV[2] $base_ip");
	system("dnsconf --set www.$ARGV[2] $base_ip");
	$code=system($reload_named);
	&check_status($code,$?,"named reload");
	&add_line($host_conf,"\tServerAlias $ARGV[2]\n\tServerAlias www.$ARGV[2]","$customer_dir/$ARGV[1]/htdocs",1);
	$code=system($reload_apache);
	&check_status($code,$?,"apache reload");
	&add_line("$courier_alias/domains","\@$ARGV[2]: $ARGV[1]");
	$code=system($make_aliases);
	&check_status($code,$?,"makealiases");
	&add_line($courier_domain,"$basedomain");
} elsif($action eq 'newhost') {
	print("Adding domain $ARGV[3].$ARGV[2]...\n") if $debug;
	system("dnsconf --set $ARGV[3].$ARGV[2] $base_ip");
	$code=system($reload_named);
	&check_status($code,$?,"named reload");
	&add_line($host_conf,"\tServerAlias $ARGV[3].$ARGV[2]","/usr/local/htdocs/customer/$ARGV[1]/htdocs",1);
	$code=system($reload_apache);
	&check_status($code,$?,"apache reload");
} elsif($action eq 'virt_mail') {
	&remove_line("$courier_alias/domains","^\@$ARGV[1]");
	$code=system($make_aliases);
	&check_status($code,$?,"makealiases");
	mkdir("$local_mail/$ARGV[1]",0700);
	chown 105, 100, "$local_mail/$ARGV[1]";
	system("/bin/touch $courier_users/$ARGV[1]");
	&new_mailbox("postmaster",$ARGV[1],$ARGV[2]);
} elsif($action eq 'add_mbox') {
	&new_mailbox($ARGV[1],$ARGV[2],$ARGV[3],$ARGV[4]);
} elsif($action eq 'mbox_pass') {
	$domain="system";
	if(index($ARGV[1],"\@") > 0) {
		($userid,$domain)=split(/\@/,$ARGV[1]);
	}
	&mailbox_pass($ARGV[1],$domain,$ARGV[2]);
} elsif($action eq 'delete_mbox') {
	print("Deleting mail account $ARGV[1]\@$ARGV[2]\n") if $debug;
	$code=system("$userdb $ARGV[2]/$ARGV[1]\@$ARGV[2] del");
	&check_status($code,$?,"userdb");
	$code=system("/bin/rm -rf $local_mail/$ARGV[2]/$ARGV[1]");
	&check_status($code,$?,"rm $ARGV[1]");
	$code=system($makeuserdb);
	&check_status($code,$?,"makeuserdb");
	$code=system($reload_courier);
	&check_status($code,$?,"courier reload");
} elsif($action eq 'alias_mail') {
	print "Mail for domain $ARGV[1] is addressed to user $ARGV[2]\n" if $debug;
	&add_line("$courier_alias/domains","\@$ARGV[1]: $ARGV[2]");
	$code=system($make_aliases);
	&check_status($code,$?,"makealiases");
	&del_maildomain($ARGV[1]);
} elsif($action eq 'deldomain') {
	print("Domain $ARGV[1] is being removed...\n") if $debug;
	system("dnsconf --deldomain $ARGV[1]");
	$code=system($reload_named);
	&check_status($code,$?,"named reload");
	&remove_line($host_conf,"$ARGV[1]");
	$code=system($reload_apache);
	&check_status($code,$?,"apache reload");
	&remove_line("$courier_alias/domains","^\@$ARGV[1]");
	$code=system($make_aliases);
	&check_status($code,$?,"makealiases");
	&del_maildomain($ARGV[1]);
} elsif($action eq 'delete') {
	print("User $ARGV[1] is being removed...\n") if $debug;
	$code=system("userconf --deluser $ARGV[1] --deldata");
	&check_status($code,$?,"deluser");
	if(!&remove_section("$host_conf","VirtualHost",$ARGV[1],"user")) {
		$code=system($reload_apache);
		&check_status($code,$?,"apache reload");
	}
	if( $ARGV[2] ) {
		system("dnsconf --unset $ARGV[1].$ARGV[2]");
		$code=system($reload_named);
		&check_status($code,$?,"named reload");
		$code=system("$userdb $ARGV[2]/$ARGV[1]\@$ARGV[2] del");
		&check_status($code,$?,"userdb");
		$code=system($reload_named);
		&check_status($code,$?,"named reload");
		$code=system("/bin/rm -rf $local_mail/$ARGV[2]/$ARGV[1]");
		&check_status($code,$?,"rm $ARGV[1]");
		$code=system($makeuserdb);
		&check_status($code,$?,"makeuserdb");
		$code=system($reload_courier);
		&check_status($code,$?,"courier reload");
	}
	$code=system("$userdb system/$ARGV[1] del");
	&check_status($code,$?,"userdb");
	&remove_line("$courier_users/system","=\\s$ARGV[1]");
	$code=system($makeuserdb);
	&check_status($code,$?,"makeuserdb");
} else {
print qq|
 This script should be called with following arguments:
 add system account   	     - add username password comment [base-domain]
 change password             - setpass username password
 add domain for user         - newdomain username new-domain
 add 3rd level domain        - newhost username domain new-host
 delete 2nd level domain     - deldomain domain
 delete system account       - delete username
 create mail domain          - virt_mail domain postmaster-password [postmaster-quota]
 redirect all mail for domain- alias_mail domain user 
 add mailbox                 - add_mbox mailbox domain password [quota]
 delete mailbox              - delete_mbox mailbox domain
 change password for mail    - mbox_pass user@domain password
|;
}
exit $exitcode;

sub new_mailbox {
	local($userid,$domain,$passwd,$initquota)=@_;
	my($newquota)=$initquota ? $initquota : $defaultquota;
	printf("Adding mail account $userid\@$domain...\n") if $debug;
	mkdir("$local_mail/$domain/$userid",0700);
	$code=system("$maildirmake $local_mail/$domain/$userid/Maildir");
	&check_status($code,$?,"maildirmake");
	$code=system("/bin/chown -R webmail.users $local_mail/$domain/$userid");
	&check_status($code,$?,"chown");
	$code=system("$userdb $domain/$userid\@$domain set uid=105 gid=100 shell=/bin/false gecos=$userid home=$local_mail/$domain/$userid quota=$newquota");
	&check_status($code,$?,"userdb");
	&mailbox_pass("$userid\@$domain",$domain,$passwd);
}

sub mailbox_pass {
	local($mailbox,$domain,$passwd)=@_;
	print("Changing pass for mailbox $mailbox...\n") if $debug;
	$code=system("$userdb $domain/$mailbox set clearpw=$passwd");
	&check_status($code,$?,"userdb");
	$code=system("/bin/echo '$passwd' | $userdbpw -md5 | $userdb $domain/$mailbox set systempw");
	&check_status($code,$?,"userdbpw");
	$code=system("/bin/echo '$passwd' | $userdbpw -hmac-md5 | $userdb $domain/$mailbox set hmac-md5pw");
	&check_status($code,$?,"userdbpw-md5");
	$code=system("/bin/echo 'passwd' | $userdbpw -hmac-sha1 | $userdb $domain/$mailbox set hmac-sha1pw");
	&check_status($code,$?,"userdbpw-sha1");
	$code=system($makeuserdb);
	&check_status($code,$?,"makeuserdb");
	$code=system($reload_courier);
	&check_status($code,$?,"courier reload");
}

sub del_maildomain {
    local($domain_name)=@_;
	if( -f "$courier_users/$domain_name" ) {
		unlink "$courier_users/$domain_name";
		$code=system($makeuserdb);
		&check_status($code,$?,"makeuserdb");
	}
	$code=system($reload_courier);
	&check_status($code,$?,"courier reload");
	if ( -d "$local_mail/$domain_name" ) {
		$code=system("/bin/rm -r $local_mail/$domain_name");
		&check_status($code,$?,"rmdir $domain_name");
	}
}

sub remove_line {
    local($fname,$str)=@_;
    local(@lines,@lines2);
    if(open(FHND,$fname)) {
		@lines=<FHND>;
		close(FHND);
		@lines2 = grep(!/$str/, @lines);
		if(open(FHND,">$fname")) {
	    	print FHND @lines2;
	    	close(FHND);
		} else { return 2; }
    } else { return 1; }
    return 0;
}

sub remove_section {
    local($fname,$s_name,$description,$descr_type)=@_;
    local(@lines,$i,$firstline,$lastline,$match);
    $i=$match=$firstline=$lastline=0;
    if(open(FHND,$fname)) {
		@lines=<FHND>;
		close(FHND);
		for($i=0;$i<=$#lines;$i++) {
			if($lines[$i] =~ /<($s_name)\s+([^>]+)>/io && !$match) {
				$firstline=$i;
				if(!$match && !$descr_type && ($2 eq $description)) {
					$match=1;
				}
			} elsif($lines[$i] =~ /<\/$s_name>/io && $lastline<$firstline) {
				$lastline=$i;
			} elsif(!$match && $descr_type && $lines[$i] =~ /\s*$descr_type\s+([^\s]+)/io) {
				$match=1 if ($1 eq $description);
			}
		}
		if(open(FHND,">$fname")) {
			for($i=0;$i<=$#lines;$i++) {
				if($match && $i>=$firstline && $i<=$lastline) { next; }
				print FHND $lines[$i] unless length($lines[$i]) < 2;
			}
			close(FHND);
		} else { return 2; }
    } else { return 1; }
    return 0;
}

sub add_line {
    local($fname,$str,$match,$offset)=@_;
    local(@lines,$i,$k);
    if(open(FHND,$fname)) {
	    @lines=<FHND>;
	    close(FHND);
    	if(open(FHND,">$fname")) {
    	    for($i=0;$i<=$#lines;$i++) {
    		$k=($i>=abs($offset))?$i-$offset:0;
    		if(length($match) && index($lines[$k],$match) != -1) {
    			print FHND "$str\n";
    		}
    		print FHND $lines[$i];
    	    }
    	    print FHND "$str\n" unless length($match);
		close(FHND);
		return 0;
    	} else { return 2; }
    } else { return 1; }
}

sub encrypt {
    local($password)=@_;
    local($encrypted);
	my @salt_chars = ('A' .. 'Z', 0 .. 9, 'a' .. 'z', '.', '/');
	my $salt = join '', @salt_chars[rand 64, rand 64];
	$encrypted = crypt($password, $salt);
    return $encrypted;
}

sub check_status {
    local($sys_return,$retval,$cmd)=@_;
    if($sys_return != 0) {
	my($exit_value) = $retval >> 8;
	my($signal_num) = $retval & 127;
	print "Call of \'$cmd\' failed. Return code $exit_value, signal $signal_num.\n";
	$exitcode=$exit_value unless $exitcode > $exit_value;
	return($exit_value);
    } else {
	return(0);
    }
}
