#!/bin/bash
# Note that even sh-emulation mode of bash won't do here because
#  of "builtin < subshell" redirection - it has to be full-fledged /bin/bash

## Init
skip=
recurse=
decrypt=
encrypt=
files=( )

errors=( )

## Process $0 (ccat, ccdecrypt, ccencrypt)
name="$(basename "$0")"
case "$name" in
	ccencrypt) encrypt=true ;;
	ccdecrypt) decrypt=true ;;
	ccat) decrypt=cat ;;
esac
unset name

## Process command line like ccrypt woud've done
for arg in "$@"; do
	case "$arg" in
		-k) skip=true ;;
		-K) skip=true ;;
		-r) recurse=true ;;
		-d) decrypt=true ;;
		-c) decrypt=cat ;;
		-e) encrypt=true ;;
		*)
			if [[ $skip ]]; then
				skip=
				continue
			fi
			files=( "${files[@]}" "$arg" ) ;;
	esac
done
unset skip

## Recursive expansion
if [[ $recurse ]]; then
	recurse=( )
	name=( )
	[[ $decrypt ]] && name=( '-name' '*.cpt' )
	[[ $encrypt ]] && name=( '!' '-name' '*.cpt' )
	while read -u3 name
	do recurse=( "${recurse[@]}" "$name" )
	done 3< <(find "${files[@]}" -type f "${name[@]}")
	files=( "${recurse[@]}" )
	unset recurse name
fi

## Actual per-file operation loop
for file in "${files[@]}"; do
	# Some assumptions about file name and existance
	[[ ! -f "$file" && $decrypt ]] && file="${file}.cpt"
	if [[ ! -f "$file" ]]; then
		errors=( "${errors[@]}" "File does not exists: $file" )
		continue
	fi

	# Try to auto-determine applicable operation
	if [[ -z $encrypt && -z $decrypt ]]; then
		[[ -z $encrypt && "${file##*.}" = cpt ]] && decrypt=true
		[[ -z $decrypt ]] && encrypt=true
	fi
	# ...and perform a sanity check
	if [[ $encrypt && $decrypt ]] || [[ ! $encrypt && ! $decrypt ]]; then
		errors=( "${errors[@]}" 'One of encrypt or decrypt should be specified' )
		break
	fi

	# Perform the requested op
	if [[ $encrypt ]]

	then # encryption
		dst="${file}.cpt"
		if [[ -e "$dst" ]]; then
			errors=( "${errors[@]}" "Destination path exists: $dst" )
			continue
		fi
		if ! gpg --batch -q -e -r "$EMAIL" <"$file" >"$dst"; then
			rm -f "$dst"
			errors=( "${errors[@]}" "GnuPG failure on file encryption: $file (for: $EMAIL)" )
			continue
		fi
		shred -u "$file"

	else # decryption
		if [[ $decrypt != cat && "$file" = "${file%.cpt}" ]]
		then # special case: explicitly specified file exists, but doesn't have ".cpt"
			tmp="$(mktemp "${file}.tmp.XXXXX")"
			if ! gpg --batch -q -d "$file" >"$tmp"; then
				rm -f "$tmp"
				errors=( "${errors[@]}" "GnuPG failure on file decryption: $file" )
				continue
			fi
			mv "$tmp" "$file"
		else # normal file.cpt -> file operation or ccat
			if [[ $decrypt = cat ]]
			then
				dst=
				gpg --batch -q -d "$file"
			else
				dst="${file%.cpt}"
				if [[ -e "$dst" ]]; then
					errors=( "${errors[@]}" "Destination path exists: $dst" )
					continue
				fi
				gpg --batch -q -d "$file" >"$dst"
			fi
			if [[ $? -gt 0 ]]; then
				[[ "$dst" ]] && rm -f "$dst"
				errors=( "${errors[@]}" "GnuPG failure on file decryption: $file" )
				continue
			fi
			[[ "$dst" ]] && rm -f "$file"

		fi
	fi
done

## Report errors, if any
for error in "${errors[@]}"; do echo >&2 "ERROR: $error"; done
exit ${#errors[@]}
