#!/bin/sh -f

alterator_api_version=1
po_domain="alterator-ca"

. alterator-sh-functions
. avahi-sh-functions
. shell-config
. shell-signal

cleanup_function()
{
	[ -z "$tmpdir" ] ||
		rm -rf -- "$tmpdir"
}
tmpdir="$(mktemp -dt "${0##*/}.XXXXXXXX")"
set_cleanup_handler cleanup_function

conffile="/etc/alterator-ca/dnparam.txt"
autoupdate_file="/etc/cron.d/alterator-ca"
update_cmd="ca-sko update"

export CA_VERBOSE=1

filter_localhost()
{
	[ -n "$1" -a "$1" != "localhost" ]
}

do_all_keys()
{
	local IFS=';'
	local cmd="$1"

	for i in $in_key_name; do
		ca-sko "$cmd" "$in_hostname" "$i"
	done
}

do_all_hosts()
{
	local IFS=';'
	local cmd="$1"
	local filter="${2:-:}"

	for i in $in_name; do
		"$filter" "$i" || continue
		ca-sko "$cmd" "$i"
	done
}

write_autoupdate()
{
	if ! test_bool "$in_autoupdate"; then
		rm -f "$autoupdate_file"
		return
	fi

    in_time="${in_time%:*}"
    local hour="${in_time%:*}"
    local min="${in_time#*:}"

	local tmpfile="$(mktemp "$autoupdate_file.XXXXXXXXXX")"

	printf '#autogenerated by alterator-ca\n' >"$tmpfile"
	printf 'SHELL=/bin/sh\n' >> "$tmpfile"
	printf 'PATH=/sbin:/usr/sbin:/bin:/usr/bin\n' >> "$tmpfile"
	printf 'CA_VERBOSE=1\n\n' >> "$tmpfile"
	printf '%s %s * * * root %s\n' "$min" "$hour" "$update_cmd" >> "$tmpfile"

	mv -f "$tmpfile" "$autoupdate_file"
}

read_autoupdate()
{
	if [ -s "$autoupdate_file" ]; then
		while read min hour monthday month weekday rest; do
			[ -n "$min" ] || continue
            [ -n "${min%%\#*}" ] || continue
			[ -n "${min##*=*}" ] || continue
			write_string_param time "$hour:$min:00"
			write_bool_param autoupdate true
			return
		done < "$autoupdate_file"
	fi
	write_string_param time "02:00:00"
	write_bool_param autoupdate false
}

on_message() {
	case "$in_action" in
		type)
			case "$in__objects" in
				root)
					write_type_item C iso-3166-alpha-2
					write_type_item O ca-cert-field
					;;
			esac
			;;
		list)
			case "$in__objects" in
				avail_hosts)
					trust-list | write_enum
					;;
				host)
					if [ -n "$in_hostname" ]; then
						ca-sko show "$in_hostname" |
							while IFS='	' read key issued expires subject __ __ __ status; do
								name="${key##*/}"
								name="${name%.cert}"
								status="${status#*:}"

								write_table_item \
									key_name "$name" \
									name "$name" \
									issued "$issued" \
									expires "$expires" \
									subject "$subject" \
									status "$status"
							done
					fi
					;;
				certs)
					write_table_item \
						name localhost \
						hostname "$(_ "Local certificates")"
					ca-sko hosts |
						while read host; do
							write_table_item \
								name "$host" \
								hostname "$host"
						done
					;;
			esac
			;;
		read)
			case "$in__objects" in
				download)
					file="$(ca-sko status | cut -d '	' -f 1)"

					if [ -z "$file" ]; then
						write_error "$(_ "CA not initialized")"
						return
					fi
					case "$in_file" in
						ca-root.pem)
							write_blob_param "file" "$file"
							;;
						ca-root.csr)
							write_blob_param "file" "${file%.pem}.csr"
							;;
						output.pem)
							if [ ! -s "$tmpdir/output.csr" ]; then
								write_error "$(_ "Missing sign request")"
								return
							fi
							ca-sko signfile "$tmpdir/output.csr" "$tmpdir/output.pem"
							if [ ! -s "$tmpdir/output.pem" ]; then
								write_error "$(_ "Unable to sign request")"
								return
							fi
							write_blob_param "file" "$tmpdir/output.pem"
							rm -f "$tmpdir/output.csr"
							;;
					esac
					;;
				host)
					case "$in_hostname" in
						localhost)
							write_string_param displayname "$(_ "Local")"
							;;
						*)
							write_string_param displayname "$in_hostname"
							;;
					esac
					write_string_param hostname "$in_hostname"
					;;
				certs)
					read_autoupdate
					if [ -s "$tmpdir/output.txt" ]; then
						write_bool_param can_has_sign true
						write_string_param sign_request "$(cat "$tmpdir/output.txt")"
					else
						write_bool_param can_has_sign false
					fi
					;;
				root)
					write_string_param C "$(shell_config_get "$conffile" "C")"
					write_string_param O "$(shell_config_get "$conffile" "O")"

					ret=0
					status="$(ca-sko status)"
					ret=$?

					[ $ret != 1 ] &&
						write_bool_param is_active true ||
						write_bool_param is_active false

					[ $ret != 1 ] || return

					startdate="$(printf '%s' "$status" | cut -d '	' -f 2)"
					enddate="$(printf '%s' "$status" | cut -d '	' -f 3)"
					subj="$(printf '%s' "$status" | cut -d '	' -f 4)"
					issuer="$(printf '%s' "$status" | cut -d '	' -f 5)"
					sha1fp="$(printf '%s' "$status" | cut -d '	' -f 6)"
					md5fp="$(printf '%s' "$status" | cut -d '	' -f 7)"
					status="$(printf '%s' "$status" | cut -d '	' -f 8)"
					status="${status#*:}"

					printf '%s/' "$subj" |
						while read -d/ line; do
							[ -n "$line" ] || continue
							name="${line%%=*}"
							value="${line#*=}"

							write_string_param "subject_$name" "$value"
						done

					printf '%s/' "$issuer" |
						while read -d/ line; do
							[ -n "$line" ] || continue
							name="${line%%=*}"
							value="${line#*=}"

							write_string_param "issuer_$name" "$value"
						done

					write_string_param startdate "$startdate"
					write_string_param enddate "$enddate"

					write_string_param sha1fp "$sha1fp"
					write_string_param md5fp "$md5fp"
					write_string_param status "$status"
					;;
			esac
			;;
		write)
			if [ -n "$in_new_host" -a -n "$in_new_name" ]; then
				ret=0
				status="$(ca-sko addhost "$in_new_name" 2>&1 >/dev/null)"
				ret=$?

				echo "$status" >&2
				[ $ret = 0 ] ||
					write_error "$status"
			elif [ -n "$in_del_host" -a -n "$in_name" ]; then
				do_all_hosts delhost filter_localhost
			elif [ -n "$in_update_host" -a -n "$in_name" ]; then
				do_all_hosts update
			elif [ -n "$in_import_host" -a -n "$in_name" ]; then
				do_all_hosts import
			elif [ -n "$in_sign_host" -a -n "$in_name" ]; then
				do_all_hosts sign
			elif [ -n "$in_export_host" -a -n "$in_name" ]; then
				do_all_hosts export
			elif [ -n "$in_sign_key" -a -n "$in_hostname" -a -n "$in_key_name" ]; then
				do_all_keys signkey
			elif [ -n "$in_apply_autoupdate" ]; then
				write_autoupdate
			#elif [ -n "" ]; then
			#	:
			fi
			;;
		create)
			if [ -z "$in_C" -a -z "$in_O" ]; then
				write_error "$(_ "Country and Organizaton must be defined")"
				return
			fi
			if [ -z "$in_O" ]; then
				write_error "$(_ "Organizaton must be defined")"
				return
			fi
			if [ -z "$in_C" ]; then
				write_error "$(_ "Country must be defined")"
				return
			fi
			if ca-sko status >/dev/null 2>&1; then
				if test_bool "$in_confirm"; then
					ca-sko drop
				else
					write_error "$(_ "CA already initialized")"
					return
				fi
			fi
			shell_config_set "$conffile" "C" "$in_C"
			shell_config_set "$conffile" "O" "$in_O"
			ret=0
			status="$(ca-sko init 2>&1 >/dev/null)"
			ret=$?
			if [ $ret = 0 ]; then
				file="$(ca-sko status | cut -d '	' -f 1)"
				if [ -d /srv/public -a -f "$file" ]; then
					cp -f -- "$file" /srv/public/ca-root.pem
					publish_service alterator-ca "$in_O Root CA (%h)" '_ca-root._tcp' 0 "path=/ca-root.pem"
				fi
			else
				write_error "$status"
			fi
			;;
		upload)
			mv -f "$in_request" "$tmpdir/output.csr"

			[ -s "$tmpdir/output.csr" ] &&
				openssl req -text -noout -in "$tmpdir/output.csr" -out "$tmpdir/output.txt"

			if [ ! -s "$tmpdir/output.txt" ]; then
				rm -f "$tmpdir/output.csr"
				rm -f "$tmpdir/output.txt"
				write_error "$(_ "Invalid sign request")"
			fi
			;;
	esac
}

message_loop
# vim:ts=4:
