#!/bin/sh

# ClonePanel - Manages duplicate accounts on two or more webservers,
# including snapshot backups, monitoring and failover dns.
# Copyright (C)2006 Chris Cheers, Internet Lynx.
# Contact chris[at]clonepanel[dot]com.
# Internet Lynx, PO Box 7117, Mannering Park, NSW 2259, Australia

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

Version=0.33
# database -h for built-in documentation

set -u
# Be strict about variable declaration

unset PATH
#avoid use of $PATH - limit script to system commands we choose

PROGRAM_DIR=$(/bin/echo $0 |/bin/sed -e "s/\/[a-zA-Z0-9_]*$//")
# Extract the working directory from command line
# NB - if your system doesn't have echo and sed in these locations
# then this line will need to be changed in all shell scripts

# Standard include files:
. $PROGRAM_DIR/includes

# Built-in documentation:
function showdocs {
	$CAT <<-EODOC
		Add / remove database from list to sync for an account in clonepanel system.
		Inputs may be given as command line parameters or interactively.
		Usage:
		1. List databases already defined:
		./database -u myaccount
		2. Add / delete a database (enter data at prompts):
		./database add|del
		3. Add / delete a database (data on command line):
		./database -d myaccount_mydb [ -u myaccount -l myaccount_login -p secret -t tablenames ] add|del
		Command line options: 
		-h		Print these instructions and exit
		-d myaccount_dbname	Database name
		-u myaccount	CPanel username of the account
		-l myaccount_login	Database login for this database
		-p secret	Password for this login
		-t table1,table2	Optional list of tables to sync
		-H localhost	Optional hostname for database (not required on CPanel)
		-f		Force overwrite add or multiple delete
		
		Important Note: While CPanel allows you to use the main account username and password
		to access any database storing this information in plain text is a VERY BAD IDEA!
		So don't be lazy, create a new user for each database and give only that
		information (the db login and password) to this program.

EODOC
	exit $DOC_REQUEST
}


# Get db filename(s) based on user input database name
function get_db_file {
	n_matches=0
	matches=`$FIND $database_dir -maxdepth 1 -type f`
	if [ ! "$matches" ]; then
		return
	fi
# Start with all database records for this username
	if [ ! "$database" ]; then
		n_matches=`$ECHO $matches |$WC -w`
		return
	fi
# Without a given db name, just return full list
	dbs=$matches
	matches=''
	n_matches=0
# If a database name is given then match this also - reset match list
	for db in $dbs
	do
		matched=`$GREP -l "db_name='$database'" $db`
		if [ "$matched" ]; then
			matches="$matched $matches"
			n_matches=$($EXPR $n_matches + 1 )
		fi
	done
# Anything now matches database name
	if [ ! "$matches" ]; then
		return
	fi
	if [ ! "$login" ]; then
		return
	fi
# Return if no matches or nothing more to test
	dbs=$matches
	matches=''
	n_matches=0
# If a login name is given then must match this also - reset match list
	for db in $dbs
	do
		matched=`$GREP -l "db_user='$login'" $db`
		if [ "$matched" ]; then
			matches="$matched $matches"
			n_matches=$($EXPR $n_matches + 1 )
		fi
	done
# Anything now matches database and login names
	if [ ! "$matches" ]; then
		return
	fi
	if [ ! "$tables" ]; then
		return
	fi
# Return if no matches or nothing more to test
	dbs=$matches
	matches=''
	n_matches=0
# If a tables list is given then must match this also - reset match list
	for db in $dbs
	do
		matched=`$GREP -l "db_table='$tables'" $db`
		if [ "$matched" ]; then
			matches="$matched $matches"
			n_matches=$($EXPR $n_matches + 1 )
		fi
	done
}

function create_db_file {
	cecho -c $info "Creating $database_dir/$dbfile"
	$CAT >$database_dir/$dbfile << ENDDATA
db_name='$database'
db_user='$login'
db_password='$password'
db_table='$tables'
db_host='$dbhost'
ENDDATA
}

function create_db_dir {
	cecho -c $info "Creating directory $database_dir"
	$MKDIR $database_dir
	checkerror $? $E_FAILED_OPENING_DB_LIST
	if [ ! -d $database_dir ]; then
		cecho -c $error "Failed to create / open directory $database_dir"
		exit $E_FAILED_OPENING_DB_LIST
	fi
}

function run_sync_setup {
# After making changes to database setup, recommend syncing these to remote hosts
	cecho -c $warning "Changes made must be synchronised with remote host(s)"
	cecho -n -c $prompt "Run sync program now? (y/n):"
	read response
	if [ "$response" == "y" ]; then
		$PROGRAM_DIR/sync_remote -u $user
	fi
}

# Initialise own input variables:
command=list
user=''
database=''
login=''
password=''
tables=''
dbhost=''
force='n'

# Start real script

# Check for help request and input variables in the command line options:
while getopts ":hu:d:l:p:t:H:f:" opt
do
	case $opt in
		h)	showdocs
			;;
		u)	user=$OPTARG
			;;
		d)	database=$OPTARG
			;;
		l)	login=$OPTARG
			;;
		p)	password=$OPTARG
			;;
		t)	tables=$OPTARG
			;;
		H)	dbhost=$OPTARG
			;;
		f)	force='y'
			;;
		*)	$ECHO "Unknown option. Use -h for instructions"; exit $E_UNKNOWN_OPT
			;;
	esac
done
shift $(($OPTIND - 1))

OPTIND=1
# reset getopts for next time

if [ $# -gt 0 ]; then
        command=$1
fi

if [ ! $user ]; then
	cecho -n -c $prompt "Enter CPanel account username: "
	read user
	if [ ! $user ]; then
		cecho -c $error "Account username must be specified"
		exit $E_BLANK_INPUTS
	fi
fi

config -u $user
# User-specific config options

if [ ! -d $USER_DIR ]; then
	cecho -c $error "Error: No account with that username."
	exit $E_NO_ACCOUNT
fi

database_dir=$USER_DIR/$DATABASE_DIRNAME
if [ ! -d "$database_dir" ] ; then
	create_db_dir
fi

case $command in
	list)
		cecho -c $ok "Databases listed for $user:"

		get_db_file
		if [ $n_matches -gt 0 ]; then
			for dbfilename in $matches
			do
				cecho -c $info "Database $dbfilename:"
				$CAT $dbfilename
			done
			cecho -c $ok "$n_matches database(s) listed"
		else
			cecho -c $warning "No matching databases"
		fi
		;;
	add)
		if [ ! $database ]; then
			cecho -n -c $prompt "Enter full database name: "
			read database
			if [ ! $database ]; then
				cecho -c $error "Database name must be specified"
				exit $E_BLANK_INPUTS
			fi
		fi
		defuser=$($ECHO "$database" |$CUT -d_ -f1) ;
# Derive an expected username from the part of the database name up to the first underscore	
		if [ "$user" != "$defuser" ]; then
			cecho -c $warning "Warning - Account $user not matched to database owner $defuser"
		fi
		if [ ! $login ]; then
			cecho -n -c $prompt "Enter database username [$database]: "
			read login
			if [ ! $login ]; then
				login="$database"
			fi
		fi
		if [ ! $password ]; then
			cecho -n -c $prompt "Enter database password: "
			read password
			if [ ! $password ]; then
				cecho -c $error "Password must be specified"
				exit $E_BLANK_INPUTS
			fi
		fi
		if [ ! "$tables" ]; then
			cecho -n -c $prompt "Enter database tables (default blank): "
			read tables
		fi
		if [ ! "$dbhost" ]; then
			cecho -n -c $prompt "Enter database hostname (default blank): "
			read dbhost
		fi

		get_db_file
		case $n_matches in
			1)
				if [ $force != 'y' ]; then
					cecho -n -c $prompt "One matching database exists - replace it (y/n)?: "
					read force
				fi
				;;
			0)
				;;
			*)
				if [ $force != 'y' ]; then
					cecho -n -c $prompt "$n_matches matching databases exist - delete all (y/n)?: "
					read force
				fi
				;;
		esac
		if [ $n_matches -gt 0 ]; then
			if [ $force == 'y' ]; then
				for match in $matches
				do
					$RM $match
					checkerror $? $E_FAILED_DELETE_DB
				done
			else 
				cecho -c $error "Aborted"
				exit $USER_ABORT
			fi
		fi
		
		highest=`$FIND $database_dir -maxdepth 1 -type f -printf "%f\n" | $SORT -n | $TAIL -n 1`
# highest numeric existing entry
		if [ ! "$highest" ]; then
			highest=0
		fi

		dbfile=$($EXPR $highest + 1 )
#			We could just use the database name but this allows
#			for multiple entries (eg different tables in same db)
		create_db_file
		run_sync_setup
		cecho -c $ok "Add database done!"
		;;
	del)
		if [ ! $database ]; then
			cecho -n -c $prompt "Enter full database name: "
			read database
			if [ ! $database ]; then
				cecho -c $error "Database name must be specified"
				exit $E_BLANK_INPUTS
			fi
		fi

		get_db_file
		case $n_matches in
			0)
				cecho -c $error "No matching databases - nothing to delete"
				exit $E_DB_NOT_FOUND
				;;												
			1)
				$RM $matches
				checkerror $? $E_FAILED_DELETE_DB
				;;
			*)
				if [ $force != 'y' ]; then
					cecho -n -c $prompt "$n_matches databases match your input - delete all (y/n)?: "
					read force
				fi
				if [ $force == 'y' ]; then
					for match in $matches
					do
						$RM $match
						checkerror $? $E_FAILED_DELETE_DB
					done
				else 
					cecho -c $error "Aborted"
					exit $USER_ABORT
				fi
				;;
		esac
		run_sync_setup
		cecho -c $ok "Delete database done!"
		;;	
	*)	cecho -c $error "Unknown option. Use -h for instructions"; exit $E_UNKNOWN_OPT
		;;
esac
















