#!/bin/sh

# Alpine Setup Box
# Copyright (C) 2015 Alan Lacerda
# See LICENSE file for license details 

# Static definition
##
### DO NOT TOUCH THIS VARIABLE
CONFIG_DIR=/etc/setup-box
JSON_DIR=/etc/setup-box/json
VERSION=v$pkgver

# Variable definition
##
### This variable is populated by the search_file() function
json_files=""
### After all research, what will we finally install
final_packs=""
final_serv=""
### File that contains all desktop-related groups
desktop_json="$JSON_DIR/desktop.json"
show_error="0"
create_user="0"
### End of Variables definition
##
#

usage () {
   cat <<__EOF__
$(basename $0) $VERSION - Setup a variety Environments

Usage: $(basename $0) option [args]

Options:
 -b Basic Alpine Linux Setup
 -d Select a desktop environment:
    mate
    openbox
    xfce
 -u create a user with the choosen username
    If -d was set but -u was not, a default user will be created
 -g group (see -G)
 -s subgroup (see -S)
 -h Show this help
 -G List all avaliable groups
 -S List all avaliable subgroups
 -v Show any error - just in case
 -V Show $(basename $0) version

EXAMPLES:
 Installing MATE Desktop for Jane with Internet applications and Pentest tools:
    ~# $(basename $0) -d mate -u jane -s desktop_extras.internet -g pentest
 
 Installing a basic environment with Gparted:
    ~# $(basename $0) -d openbox -s systools.disk

__EOF__
   exit 1
}

# Installing all dependencies for setup-box.
check_deps() {
	if [ "$(id -u)" != "0" ]; then
		cat <<__EOF__
***********************************
**** WARNING: You are not root ****
***********************************
$(basename $0) must be executed as root
		
__EOF__
		logger -i -t $(basename $0) -p 4 "User $(whoami) tried to execute $(basename $0)"
		exit 1
	fi
}

# We need to exclude $desktop_json from the list. This is due to the fact that
# desktop environment cannot be installed without "base". In order to install
# a desktop environment the user must use -d option
search_files() {
	for i in $(ls $JSON_DIR/*.json); do
		if [ "$i" != "$desktop_json" ]; then
			t="$t "$i
		fi
	done
	json_files=$t
}

# Function to define in what json files perform the search for the
# group to be installed
## Called by -s option
search_sub_group() {
	for f in $json_files; do
		if [ "${1%.*}" != "desktop" ]; then
			if [ $( < $f jq ".${1%.*} | length") ]; then
				for j in $@; do
					core=$(echo $j | cut -d. -f1)
					sub=$(echo $j | cut -d. -f2)

					packages=$( < $f jq ".$core[] \
						| select(.$sub)" \
						| egrep -Ev '\{|:|]|}' \
						| sed 's/\"//g' \
						| sed 's/,//g')

					services=$( < $f jq ".$core[].$sub[].services[]" \
						| egrep -Ev '\{|:|]|}' \
						| sed 's/\"//g' \
						| sed 's/,//g')

					final_pack="$final_pack "$packages
					final_serv="$final_serv "$services
				done
			fi
		fi
	done
}

# Selecting a whole meta-group to be installed
## Called by -g option
search_meta_group() {
	for i in $json_files; do
		if [ $( < $i jq ".$1 | length") ]; then
			packages=$( < $i jq ".$1[]" \
				| egrep -Ev '\{|:|]|}' \
				| sed 's/\"//g' \
				| sed 's/,//g')

			services=$( <  $i jq ".$1[][]" \
				| jq '.[] \
				| select(.services)' \
				| sed 's/\"//g')

			final_pack="$final_pack "$packages
			final_serv="$final_serv "$services
		fi
	done
}

## Called by -d option
search_desktop() {
	if [ $( < $desktop_json jq -e ".desktop[] | select(.$1) | length")  ]; then
		# first of all lets force some packages to be installed
		for i in "base" "drivers"; do
			packages=$( < $desktop_json jq ".desktop[] \
				| select(.$i)" \
				| egrep -Ev '\{|:|]|}' \
				| sed 's/\"//g' \
				| sed 's/,//g')

			services=$( < $desktop_json jq ".desktop[].$i[].services[]" \
				| sed 's/\"//g')

			final_pack="$final_pack "$packages
			final_serv="$final_serv "$services
		done

		# Now lets pick up the packages that we were requested to install
		packages=$( < $desktop_json jq ".desktop[] \
			| select(.$1)" \
			| egrep -Ev '\{|:|]|}' \
			| sed 's/\"//g' \
			| sed 's/,//g')

		services=$( < $desktop_json jq ".desktop[].$1[].services[]" \
			| sed 's/\"//g')
		 
		final_pack="$final_pack "$packages
		final_serv="$final_serv "$services
	fi
	
	if [ "$1" == "openbox" ]; then
		mkdir -p ~/.config/openbox
cat >~/.config/openbox/menu.xml<<EOF
<?xml version="1.0" encoding="UTF-8"?>

<openbox_menu xmlns="http://openbox.org/3.4/menu">
<menu id="root-menu" label="Openbox 3">
  <separator label="Applications" />
  <item label="GParted">
    <action name="Execute">
      <command>gparted</command>
    </action>
  </item>
  <item label="Terminal">
    <action name="Execute">
      <command>st</command>
    </action>
  </item>
  <separator />
  <item label="Log Out">
    <action name="Exit">
      <prompt>yes</prompt>
    </action>
  </item>
</menu>
</openbox_menu>
EOF

# create xinitrc
cat >~/.xinitrc <<EOF
exec openbox-session
EOF

	fi
	
	# psmouse module
	modprobe psmouse
	grep -q -w psmouse /etc/modules \
		|| echo "psmouse" >> /etc/modules
	grep -q -w fbcon /etc/modules \
		|| echo "fbcon" >> /etc/modules
}

# Called by -G option
list_meta_groups() {
   cat <<__EOF__
$(basename $0) $VERSION

Avaliables groups are:
__EOF__
 
	for i in $(echo $json_files | sed 's/.json//g' | tr ' ' \\n ); do
		basename $i
	done
	exit 1
}

# Called by -S option
list_sub_groups() {
   cat <<__EOF__
$(basename $0) $VERSION

Avaliables subgroups are:
__EOF__

	for file in $json_files; do
		for i in $(echo $file | sed 's/.json//g' | tr ' ' \\n ); do
			echo $(basename $i):
			for sg in $( < $file jq '.[][]' \
				| grep : \
				| tr '"' ' ' \
				| egrep -v "services|packages" \
				| tr ':' ' ' \
				| tr '[' ' ' \
				| sed 's/ //g'); do
				echo -e "\t$sg"
			done
		done
	done
	exit 1
}

# Function to remove duplicated packages from the list of packages
# to be installed - just a clean up
optimize_pack() {
	final_pack=$(echo ${1} \
		| tr ' ' \\n \
		| sort -u \
		| tr \\n ' ')
}

# Function to remove duplicated services from the list of services
optimize_serv() {
   final_serv=$(echo ${1} \
		| tr ' ' \\n \
		| sort -u \
		| tr \\n ' ')
}

# Function to execute the rc-update add against each services that were installed
add_services() {
	for i in $@; do 
		if [ "$i" == "udev" ]; then
			rc-update add $i
			rc-update add $i-postmount
			add_to_sysinit "$i $i-postmount"
		elif [ "$i" == "dbus" ]; then
			rc-update add $i
			add_to_sysinit "$i"
		elif [ "$i" == "xrdp" ]; then
			rc-update add $i
			rc-update add $i-sesman
		elif [ "$i" == "zabbix" ]; then
			rc-update add $i-server
		else
			rc-update add $i
		fi
	done
}

add_to_sysinit() {
	for i in $@; do
		rc-update add $i sysinit
        done
}

start_services() {
        for i in $@; do
                if [ "$i" == "udev" ]; then
			rc-service $i start
                        rc-service $i-postmount start
		elif [ "$i" == "zabbix" ]; then
			rc-service $i-server start
		else
			rc-service $i start
                fi
        done
}

setup_zabbix() {
	php_conf="/etc/php/php.ini"
	zabbix_conf="/etc/zabbix/zabbix_server.conf"
	# first lets enable lighttpd fastcgi module
	sed -i '/mod_fastcgi.conf/s/#//g' /etc/lighttpd/lighttpd.conf

	# next, let us setup postgresql
	/etc/init.d/postgresql setup

	start_services "postgresql"

	echo -n -e "Choose a password for zabbix's database user:\033[1;31m "
	read zabbix_pass
	echo -e "\033[0m"

	# executing database commands:
	psql -U postgres <<EOF
\x
create user zabbix with password '$zabbix_pass';
create database zabbix owner zabbix;
EOF

	for i in schema.sql images.sql data.sql; do
		< /usr/share/zabbix/database/postgresql/$i psql -U zabbix zabbix
	done

	rm /var/www/localhost/htdocs -R
	ln -s /usr/share/webapps/zabbix /var/www/localhost/htdocs

	cat << EOF >> $php_conf
max_execution_time = 600
expose_php = off
post_max_size = 32M
upload_max_filesize = 16M
max_input_time = 600
memory_limit = 256M
always_populate_raw_post_data = -1
EOF

	# setting user and password to access the database
	sed -e "s/#*DBName.*/DBName\=zabbix/g" -i $zabbix_conf
	sed -e "s/#*DBUser.*/DBUser\=zabbix/g" -i $zabbix_conf
	sed -e "s/#*DBPassword.*/DBPassword\=$zabbix_pass/g" -i $zabbix_conf

	# fixing permission
	chown -R lighttpd /usr/share/webapps/zabbix/conf

}

##
# Main function starts here
main () {
	# If there is no arguments... let's show how to use this application
        if [ $# -lt 1 ]; then
                usage
        fi

	# If -v was not given, lets redirect any error to the limbo
	if [ "$show_error" == "0" ]; then
		exec 2&> /dev/null
	fi
	
	# Checking some premisses and installing dependencies
	check_deps
	
	# Harvesting for all valid JSON files
	# Getting ready to be used...
	search_files
	
	# If there is any argument... let's work
	while getopts "bd:s:g:u:hGSvV" opt ; do
		case $opt in
			b)
				setup_alpine="1";;
			d) 
				create_user="1"
				search_desktop "$OPTARG";;
			s) 
				if [ "$OPTARG" == "networking.zabbix_monitor" ]; then
					zabbix_config="1"
				fi
				search_sub_group "$OPTARG";;
			g) 
				search_meta_group "$OPTARG";;
			G) 
				list_meta_groups;;
			S) 
				list_sub_groups;;
			u)
				new_user="$OPTARG";;
			v) 
				show_error="1";;
			V) 
				echo $(basename $0) $VERSION
				exit 1;;
			h) 
				usage;;
			*) 
				usage;;
		esac
	done
	shift `expr $OPTIND - 1`

	if [ "$setup_alpine" == "1"  ]; then
		/sbin/setup-alpine
	fi
	
	# Packages to be installed (including services)
	optimize_pack "$final_pack"
	apk add $final_pack -i

	# Services to be added to startup (just services)
	if [ "$?" == "0"  ]; then
		optimize_serv "$final_serv"
		add_services $final_serv
	
		if [ "$create_user" == "1" ]; then
			if [ "x$new_user" == "x" ]; then
				new_user="alpine"
			fi
			echo -e "\033[1;33m****************************************************"
			echo -e "We've created a new user for you: $new_user"
			echo -e "****************************************************"
			adduser -h /home/$new_user -g "Alpine Linux User" $new_user
			while [ $? -eq 1 ]; do
				echo -e "\033[0;31mPasswords mismatch. Try again"
				passwd $new_user
			done
			for grp in audio video cdrom usb; do
				adduser $new_user $grp
			done
			echo -e "\033[0m"
		fi

		# start of setup environments - after install the packages
		# 	but before start their services
	
		if [ "$zabbix_config" == "1"  ]; then
			setup_zabbix
			start_services zabbix
			final_msg="\033[1;33mKeep note of the following information:\nDATABASE:\n"
			final_msg=$final_msg"\tDatabase name: zabbix\n\tDatabase user: zabbix\n\tDatabase password: $zabbix_pass\nHTTP:\n"
			final_msg=$final_msg"\tZabbix User: Admin\n\tZabbix Pass: zabbix\nNow browse to: http://<my_ip>/setup.php"
		fi

		# end of setup environments

		start_services $final_serv

		echo -e "$final_msg"
		echo -e "\033[0m"
	else
		exit $?
	fi
}

main $@
