#!/bin/sh

# Copyright 2015-2023 Rivoreo

# 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.


base64_to_c_array() {
	base64 -d | hexdump -v -e '1/1 "0x%02x,"'
}

rsa_private_key_to_c_array() {
	enabled=
	while read -r line; do case "$line" in
		"-----BEGIN RSA PRIVATE KEY-----")
			enabled=1
			;;
		"-----END RSA PRIVATE KEY-----")
			exit
			;;
		*)
			[ -n "$enabled" ] && printf %s\\n "$line"
			;;
	esac done | base64_to_c_array
}

[ -z "$CC" ] && CC=cc
[ -z "$CFLAGS" ] && CFLAGS="-Wall -O1"

if [ $# != 5 ]; then
	printf 'Usage: %s <server-address> <server-port> <server-public-key> <privileged-user-name> <client-name>\n' "$0" 1>&2
	exit 255
fi

client_name="$5"
client_program_name="client.$client_name"
if [ -h "$client_program_name" ] || [ -e "$client_program_name" ]; then
	printf '%s exists\n' "$client_program_name" 1>&2
	exit 1
fi

set -e
id_dir="`mktemp -d`"
trap 'rm -rf "$id_dir"' EXIT
server_name="$1"
server_port="$2"
ssh-keygen -t rsa -b 4096 -N "" -m PEM -f "$id_dir/id_rsa"
public_key="`printf %s \"$3\" | base64_to_c_array`"
public_key="${public_key%,}"
private_key="`rsa_private_key_to_c_array < \"$id_dir/id_rsa\"`"
private_key="${private_key%,}"
privileged_user_name="$4"
$CC $CFLAGS -c base64.c syncrw.c
compile_and_link_sfc() {
	$CC $CFLAGS $LDFLAGS \
		-D "SSHOUT_SERVER_NAME=\"$server_name\"" \
		-D "SSHOUT_SERVER_PORT=$server_port" \
		-D "SSHOUT_SERVER_PUBLIC_KEY=$public_key" \
		-D "SSHOUT_CLIENT_PRIVATE_KEY=$private_key" \
		-D "PRIVILEGED_USER_NAME=\"$privileged_user_name\"" \
		"$@" -x none base64.o syncrw.o -o "$client_program_name"
}
if [ -n "$STRING_TRANSLITERATION" ]; then
	cut=
	i=1
	while [ $i -lt ${#STRING_TRANSLITERATION} ]; do
		cut="$cut?"
		i=$((i+1))
	done
	sep="${STRING_TRANSLITERATION%$cut}"
	if [ ${#sep} != 1 ]; then
		echo "Shell piao" 1>&2
		exit 1
	fi
	if [ "${STRING_TRANSLITERATION#$cut}" != "$sep" ]; then
		echo "Invalid STRING_TRANSLITERATION" 1>&2
		exit 1
	fi
	originals="${STRING_TRANSLITERATION#?}"
	originals="${originals%$sep*$sep}"
	indexes="${STRING_TRANSLITERATION%?}"
	indexes="${indexes#$sep*$sep}"
	if [ -z "$originals" ] || [ -z "$indexes" ] || [ "$originals" = "$STRING_TRANSLITERATION" ] || [ "$indexes" = "$STRING_TRANSLITERATION" ] || [ ${#originals} != ${#indexes} ]; then
		echo "Invalid STRING_TRANSLITERATION" 1>&2
		exit 1
	fi
	{
		echo "static const char *decode_string(const char *s) {"
		echo "	static char map[] = {"
		cut=
		i=1
		while [ $i -lt ${#indexes} ]; do
			cut="$cut?"
			i=$((i+1))
		done
		while [ -n "$indexes" ]; do
			printf "		['%c'] = '%c',\\n" "${indexes%$cut}" "${originals%$cut}"
			indexes="${indexes#?}"
			originals="${originals#?}"
			cut="${cut#?}"
		done
		printf %s\\n \
"		[0] = 1
	};
	static char buffer[4096];
	int i;
	if(*map == 1) {
		*map = 0;
		for(i = 1; i < sizeof map; i++) if(!map[i]) map[i] = i;
	}
	const unsigned char *up = (const unsigned char *)s;
	i = 0;
	do {
		unsigned char c = up[i];
		buffer[i] = c < sizeof map ? map[c] : c;
	} while(up[i++]);
	return buffer;
}
"
		sed -E "s/DECODE_STRING\\((\"[][ 	!#$%&'()*,./a-zA-Z0-9:;<=>?@^_\`{}|~+-]+\")\\)/decode_string\\(\\
\\1\\
\\)/g" sfc.c | sed -E "/^\".+\"\$/y$STRING_TRANSLITERATION"
	} | compile_and_link_sfc -x c -
else
	compile_and_link_sfc -D "DECODE_STRING(S)=(S)" sfc.c
fi
set -f
set -- `cat "$id_dir/id_rsa.pub"`
printf 'sshoutcfg adduser -a %s %s\n' "$2" "$client_name"
