sub require_mysql
{
return if ($require_mysql++);
$mysql::use_global_login = 1;
&foreign_require("mysql", "mysql-lib.pl");
%mconfig = &foreign_config("mysql");
$password_func = $mysql::password_func || "password";
}

# setup_mysql(&domain, [no-db])
# Create a new MySQL database, user and permissions
sub setup_mysql
{
local $tmpl = &get_template($_[0]->{'template'});
&require_mysql();

# Create the user
$_[0]->{'mysql_user'} = &mysql_user($_[0]);
local $user = $_[0]->{'mysql_user'};
local @hosts = &get_mysql_hosts($_[0]);
local $wild = &substitute_template($tmpl->{'mysql_wild'}, $_[0]);
if (!$_[0]->{'parent'}) {
	&$first_print($text{'setup_mysqluser'});
	my $pass = &mysql_pass($_[0]);
	local $h;
	foreach $h (@hosts) {
		&mysql::execute_sql_logged($mysql::master_db, "insert into user (host, user, password) values ('$h', '$user', $password_func('$pass'))");
		if ($wild && $wild ne $_[0]->{'db'}) {
			&mysql::execute_sql_logged($mysql::master_db, "insert into db (host, db, user, select_priv, insert_priv, update_priv, delete_priv, create_priv, drop_priv, grant_priv, references_priv, index_priv, alter_priv) values ('$h', '$wild', '$user', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y')");
			}
		}
	&$second_print($text{'setup_done'});
	}
&mysql::execute_sql_logged($mysql::master_db, 'flush privileges');

# Create the initial DB
if (!$_[1]) {
	&create_mysql_database($_[0], $_[0]->{'db'});
	}
}

# delete_mysql(&domain)
# Delete a mysql database, the domain's mysql user and all permissions for both
sub delete_mysql
{
# First remove the databases
&require_mysql();
if ($_[0]->{'db_mysql'}) {
	&delete_mysql_database($_[0], split(/\s+/, $_[0]->{'db_mysql'}));
	}

# Then remove the user
local $user = &mysql_user($_[0]);
local $tmpl = &get_template($_[0]->{'template'});
local $wild = &substitute_template($tmpl->{'mysql_wild'}, $_[0]);
if (!$_[0]->{'parent'}) {
	# Delete the user and any database permissions
	&$first_print($text{'delete_mysqluser'});
	&mysql::execute_sql_logged($mysql::master_db, "delete from user where user = '$user'");
	&mysql::execute_sql_logged($mysql::master_db, "delete from db where user = '$user'");
	&$second_print($text{'setup_done'});
	}
if ($wild && $wild ne $_[0]->{'db'}) {
	# Remove any wildcard entry for the user
	&mysql::execute_sql_logged($mysql::master_db, "delete from db where db = '$wild'");
	}
&mysql::execute_sql_logged($mysql::master_db, 'flush privileges');
}

# modify_mysql(&domain, &olddomain)
# Changes the mysql user's password if needed
sub modify_mysql
{
&require_mysql();
local $olduser = &mysql_user($_[1]);
local $user = &mysql_user($_[0], 1);
$_[0]->{'mysql_user'} = $user;
my $oldpass = &mysql_pass($_[1]);
my $pass = &mysql_pass($_[0]);
if ($pass ne $oldpass && !$_[0]->{'parent'} && !$config{'mysql_nopass'}) {
	# Change MySQL password
	&$first_print($text{'save_mysqlpass'});
	if (&mysql_user_exists($_[0])) {
		&mysql::execute_sql_logged($mysql::master_db, "update user set password = $password_func('$pass') where user = '$olduser'");
		&mysql::execute_sql_logged($master_db, 'flush privileges');
		&$second_print($text{'setup_done'});
		return 1;
		}
	else {
		&$second_print($text{'save_nomysql'});
		}
	}
if ($_[0]->{'user'} ne $_[1]->{'user'} && !$_[0]->{'parent'}) {
	# Rename MySQL user
	&$first_print($text{'save_mysqluser'});
	if (&mysql_user_exists($_[1])) {
		&mysql::execute_sql_logged($mysql::master_db, "update user set user = '$user' where user = '$olduser'");
		&mysql::execute_sql_logged($mysql::master_db, "update db set user = '$user' where user = '$olduser'");
		&mysql::execute_sql_logged($master_db, 'flush privileges');
		&$second_print($text{'setup_done'});
		return 1;
		}
	else {
		&$second_print($text{'save_nomysql'});
		}
	}
return 0;
}

# disable_mysql(&domain)
# Modifies the mysql user for this domain so that he cannot login
sub disable_mysql
{
&$first_print($text{'disable_mysqluser'});
if ($_[0]->{'parent'}) {
	&$second_print($text{'save_nomysqlpar'});
	}
else {
	&require_mysql();
	local $user = &mysql_user($_[0]);
	if ($oldpass = &mysql_user_exists($_[0])) {
		&mysql::execute_sql_logged($mysql::master_db, "update user set password = '*LK*' where user = '$user'");
		&mysql::execute_sql_logged($master_db, 'flush privileges');
		$_[0]->{'disabled_oldmysql'} = $oldpass;
		&$second_print($text{'setup_done'});
		}
	else {
		&$second_print($text{'save_nomysql'});
		}
	}
}

# enable_mysql(&domain)
# Puts back the original password for the mysql user so that he can login again
sub enable_mysql
{
&$first_print($text{'enable_mysql'});
if ($_[0]->{'parent'}) {
	&$second_print($text{'save_nomysqlpar'});
	}
else {
	&require_mysql();
	local $user = &mysql_user($_[0]);
	if (&mysql_user_exists($_[0])) {
		if ($_[0]->{'disabled_oldmysql'}) {
			&mysql::execute_sql_logged($mysql::master_db, "update user set password = '$_[0]->{'disabled_oldmysql'}' where user = '$user'");
			delete($_[0]->{'disabled_oldmysql'});
			}
		else {
			local $pass = &mysql_pass($_[0]);
			&mysql::execute_sql_logged($mysql::master_db, "update user set password = $password_func('$pass') where user = '$user'");
			}
		&mysql::execute_sql($master_db, 'flush privileges');
		&$second_print($text{'setup_done'});
		}
	else {
		&$second_print($text{'save_nomysql'});
		}
	}
}

# mysql_user_exists(&domain)
# Returns his password if a mysql user exists for the domain's user, or undef
sub mysql_user_exists
{
&require_mysql();
local $user = &mysql_user($_[0]);
local $u = &mysql::execute_sql($mysql::master_db, "select password from user where user = '$user'");
return @{$u->{'data'}} ? $u->{'data'}->[0]->[0] : undef;
}

# check_mysql_clash(&domain, [field])
# Returns 1 if some MySQL database already exists
sub check_mysql_clash
{
if (!$_[1] || $_[1] eq 'db') {
	&require_mysql();
	local @dblist = &mysql::list_databases();
	return 1 if (&indexof($_[0]->{'db'}, @dblist) >= 0);
	}
if (!$_[0]->{'parent'} && (!$_[1] || $_[1] eq 'user')) {
	&require_mysql();
	return 1 if (&mysql_user_exists($_[0]));
	}
return 0;
}

# backup_mysql(&domain, file)
# Dumps this domain's mysql database to a backup file
sub backup_mysql
{
&require_mysql();

# Find all domain's databases
local $tmpl = &get_template($_[0]->{'template'});
local $wild = &substitute_template($tmpl->{'mysql_wild'}, $_[0]);
local @alldbs = &mysql::list_databases();
local @dbs;
if ($wild) {
	$wild =~ s/\%/\.\*/g;
	$wild =~ s/_/\./g;
	@dbs = grep { /^$wild$/i } @alldbs;
	}
push(@dbs, split(/\s+/, $_[0]->{'db_mysql'}));
@dbs = &unique(@dbs);

# Back them all up
local $db;
foreach $db (@dbs) {
	&$first_print(&text('backup_mysqldump', $db));
	local $dbfile = $_[1]."_".$db;
	local $cmd = "$mysql::config{'mysqldump'} $mysql::authstr --add-drop-table".
		     (&mysql::supports_quoting() ? " --quote-names" : "").
		     " ".quotemeta($db)." 2>&1 >".quotemeta($dbfile);
	local $out = `$cmd`;
	if ($? || $out) {
		&$second_print(&text('backup_mysqldumpfailed', "<pre>$out</pre>"));
		return 0;
		}
	else {
		&$second_print($text{'setup_done'});
		}
	}
return 1;
}

# restore_mysql(&domain, file)
# Restores this domain's mysql database from a backup file, and re-creates
# the mysql user.
sub restore_mysql
{
&$first_print($text{'restore_mysqldrop'});
	{
	local $first_print = \&null_print;	# supress messages
	local $second_print = \&null_print;
	&require_mysql();

	# First clear out all current databases and the MySQL login
	&delete_mysql($_[0]);

	# Now re-set up the login only
	&setup_mysql($_[0], 1);
	}
&$second_print($text{'setup_done'});

# Work out which databases are in backup
local ($dbfile, @dbs);
push(@dbs, [ $_[0]->{'db'}, $_[1] ]) if (-s $_[1]);
foreach $dbfile (glob("$_[1]_*")) {
	if (-r $dbfile) {
		$dbfile =~ /\Q$_[1]\E_(.*)$/;
		push(@dbs, [ $1, $dbfile ]);
		}
	}

# Finally, import the data
local $db;
foreach $db (@dbs) {
	&create_mysql_database($_[0], $db->[0]);
	&$first_print(&text('restore_mysqlload', $db->[0]));
	local $cmd = "$mysql::config{'mysql'} $mysql::authstr -t ".quotemeta($db->[0])." <".quotemeta($db->[1])." 2>&1";
	local $out = &backquote_logged($cmd);
	if ($? || $out) {
		&$second_print(&text('restore_mysqlloadfailed', "<pre>$out</pre>"));
		return 0;
		}
	else {
		&$second_print($text{'setup_done'});
		}
	}
return 1;
}

# mysql_user(&domain, [always-new])
sub mysql_user
{
return $_[0]->{'mysql_user'} if (defined($_[0]->{'mysql_user'}) && !$_[1]);
return length($_[0]->{'user'}) > 16 ?
	  substr($_[0]->{'user'}, 0, 16) : $_[0]->{'user'};
}

# mysql_pass(&domain)
sub mysql_pass
{
return defined($_[0]->{'mysql_pass'}) ? $_[0]->{'mysql_pass'} : $_[0]->{'pass'};
}

# mysql_size(&domain, dbname)
# Returns the size and number of tables in a database
sub mysql_size
{
&require_mysql();
local $size;
if (-d $mysql::config{'mysql_data'}) {
	$size = &disk_usage_kb("$mysql::config{'mysql_data'}/$_[1]")*1024;
	}
local @tables = &mysql::list_tables($_[1], 1);
return ($size, scalar(@tables));
}

# check_mysql_database_clash(&domain, dbname)
# Check if some MySQL database already exists
sub check_mysql_database_clash
{
&require_mysql();
local @dblist = &mysql::list_databases();
return 1 if (&indexof($_[1], @dblist) >= 0);
}

# create_mysql_database(&domain, dbname)
# Add one database to this domain, and grants access to it to the user
sub create_mysql_database
{
# Create the database
&$first_print(&text('setup_mysqldb', $_[1]));
local @dbs = split(/\s+/, $_[0]->{'db_mysql'});
&mysql::execute_sql_logged($mysql::master_db, "create database $_[1]");
push(@dbs, $_[1]);
$_[0]->{'db_mysql'} = join(" ", @dbs);

# Add db entries for the user for each host
local $tmpl = &get_template($_[0]->{'template'});
local $h;
local @hosts = &get_mysql_hosts($_[0]);
local $user = &mysql_user($_[0]);
foreach $h (@hosts) {
	&mysql::execute_sql_logged($mysql::master_db, "insert into db (host, db, user, select_priv, insert_priv, update_priv, delete_priv, create_priv, drop_priv, grant_priv, references_priv, index_priv, alter_priv) values ('$h', '$_[1]', '$user', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y')");
	}
&mysql::execute_sql_logged($mysql::master_db, 'flush privileges');
&$second_print($text{'setup_done'});
}

# delete_mysql_database(&domain, dbname, ...)
# Remove one or more MySQL database from this domain
sub delete_mysql_database
{
&require_mysql();
local @dblist = &mysql::list_databases();
&$first_print(&text('delete_mysqldb', join(", ", @_[1..$#_])));
local @dbs = split(/\s+/, $_[0]->{'db_mysql'});
foreach $db (@_[1..$#_]) {
	if (&indexof($db, @dblist) >= 0) {
		# Drop the DB
		&mysql::execute_sql_logged($mysql::master_db, "drop database $db");

		# Remove any db permissions for it
		&mysql::execute_sql_logged($mysql::master_db, "delete from db where db = '$db'");
		}
	@dbs = grep { $_ ne $db } @dbs;
	}
$_[0]->{'db_mysql'} = join(" ", @dbs);
&mysql::execute_sql_logged($mysql::master_db, 'flush privileges');
&$second_print($text{'setup_done'});
}

# get_mysql_hosts(&domain)
# Returns the allowed MySQL hosts for some domain
sub get_mysql_hosts
{
local $tmpl = &get_template($_[0]->{'template'});
local @hosts = $tmpl->{'mysql_hosts'} eq "none" ? ( ) :
	split(/\s+/, &substitute_template($tmpl->{'mysql_hosts'}, $_[0]));
@hosts = ( 'localhost' ) if (!@hosts);
return @hosts;
}

1;

