#!/bin/bash

options=()  # the buffer array for the parameters
eoo=0       # end of options reached
output=0    # do we try to write to file
target=''   # where do we try to write to
special_filenames=0 # --enable-special-filenames was given
localgpg=0 #use local gpg (for ex --gen-rand etc.)
origargs=( "$@" )

set_output () {
    if (( output )); then
        echo 'Output file already set'>&2
        exit 1
    fi
    output=1 target=$1
}

check_charset () {
    if ! [[ "$1" =~ ^[uU][tT][fF]-?8$ ]]; then
        printf 'Unsupported character set %q\n' "$1"
        exit 1
    fi
}

while (( $# )); do
    if ! ((eoo)); then
        case "$1" in
            #when those arguments are present will not use the keyring, and so they can be executed with local gpg
            # can be used in combination with sign
            #-c)
            #    localgpg=1
            #    break
            #;;
            --gen-rand|--gen-prime|--enarmor|--dearmor|--print-md|--help|-h)
                localgpg=1
                break
                ;;
            --no-default-keyring)
                # this is not possible with split gpg right?
                localgpg=1
                break
                ;;
            --import)
                # ignore all the options and only collect file name(s) - if any
                shift
                exec qubes-gpg-import-key "$@"
                ;;
            # Keyserver options makes no sense for offline GPG VM, so it is
            # rejected by qubes-gpg-client and qubes-gpg-server. But since
            # it is forced by Torbirdy extension, simply ignore the option.
            --keyserver-options=*)
                shift
                ;;
            # --quiet is safe and is accepted by the current server, but
            # old versions rejected it.  Use -q instead, which is
            # accepted in all versions.
            --quiet)
                options+=(-q)
                shift
                ;;
            --keyserver-options)
                if [[ "$#" -lt 2 ]]; then
                    printf 'Missing argument to %s\n' "$1" >&2
                    exit 1
                fi
                shift 2
                ;;
            # Using dirmngr in an offline GPG VM makes no sense, however
            # qubes-gpg-client does not recognize the command line option
            # --disable-dirmngr so to avoid an error message we ignore
            # this option.
            --disable-dirmngr)
                shift
                ;;
            # --photo-viewer shouldn't be passed to the backend as it allow
            # arbitrary command execution
            --photo-viewer=*)
                shift
                ;;
            --photo-viewer)
                if [[ "$#" -lt 2 ]]; then
                    printf 'Missing argument to %s\n' "$1" >&2
                    exit 1
                fi
                shift 2
                ;;
            # --command-fd is used by reprepro, and looks safe.
            # However, it turns out that GnuPG trusts the data it
            # receives on this FD, so the backend has to reject it.
            --command-fd=*)
                shift
                ;;
            --command-fd)
                if [[ "$#" -lt 2 ]]; then
                    printf 'Missing argument to %s\n' "$1" >&2
                    exit 1
                fi
                shift 2
                ;;
            # Used by Mailpile, see https://github.com/QubesOS/qubes-issues/issues/3485
            --expert|--pinentry-mode=*|--passphrase-fd=*|--no-use-agent)
                shift
                ;;
            --pinentry-mode|--passphrase-fd)
                if [[ "$#" -lt 2 ]]; then
                    printf 'Missing argument to %s\n' "$1" >&2
                    exit 1
                fi
                shift 2
                ;;
            # ignore tty/display related options - those are meaningless in another VM
            --ttyname=*|--display=*|--ttytype=*|--lc-messages=*|--lc-ctype=*|--no-tty|--xauthority=*)
                shift
                ;;
            --ttyname|--ttytype|--display|--lc-messages|--lc-ctype|--xauthority)
                if [[ "$#" -lt 2 ]]; then
                    printf 'Missing argument to %s\n' "$1" >&2
                    exit 1
                fi
                shift 2
                ;;
            --enable-special-filenames)
                special_filenames=1
                shift
                ;;
            # Deprecated legacy options
            --disable-mdc|\
            --force-mdc|\
            --force-v3-sigs|\
            --force-v4-certs|\
            --no-sk-comments|\
            --use-agent)
                shift
                ;;
            # Ignored options
            --yes)
                shift
                ;;
            --detach|--detach-sig)
                options+=( --detach-sign )
                shift
                ;;
            --output)
                if [[ "$#" -lt 2 ]]; then
                    printf 'Missing argument to %s\n' "$1" >&2
                    exit 1
                fi
                set_output "$2"
                shift 2
                ;;
            --output=*)
                set_output "${1:9}"
                shift
                ;;
            --status-fd|\
            --logger-fd|\
            --attribute-fd)
                if [[ "$#" -lt 2 ]]; then
                    printf 'Missing argument to %s\n' "$1" >&2
                    exit 1
                elif [[ "$2" =~ ^(0x)?0*1$ ]]; then
                    # don't use stdout for status fd, since it might be later
                    # redirected to a file with --output
                    exec {fd_for_stdout}>&1
                    options+=( "$1" "$fd_for_stdout" )
                else
                    options+=( "$1" "$2" )
                fi
                shift 2
                ;;    
            --status-fd=*|\
            --logger-fd=*|\
            --attribute-fd=*)
                if [[ $1 =~ ^([^=]*=)(0x)?0*1$ ]]; then
                    # don't use stdout for status fd, since it might be later
                    # redirected to a file with --output
                    exec {fd_for_stdout}>&1
                    options+=( "${BASH_REMATCH[1]}$fd_for_stdout" )
                else
                    options+=( "$1" )
                fi
                shift
                ;;
            --log-file=*)
                # rejected by split-gpg to not allow a write to arbitrary file
                # on the backend side; emulate using --logger-fd
                exec {fd_for_logfile}>"${1:11}"
                options+=( "--logger-fd" "$fd_for_logfile" )
                shift
                ;;
            --log-file)
                if [[ "$#" -lt 2 ]]; then
                    printf 'Missing argument to %s\n' "$1" >&2
                    exit 1
                fi
                # rejected by split-gpg to not allow a write to arbitrary file
                # on the backend side; emulate using --logger-fd
                exec {fd_for_logfile}>"$2"
                options+=( "--logger-fd" "$fd_for_logfile" )
                shift 2
                ;;
            --display-charset=*)
                check_charset "${1:18}"
                shift
                ;;
            --charset=*)
                check_charset "${1:10}"
                shift
                ;;
            --charset|--display-charset)
                if [[ "$#" -lt 2 ]]; then
                    printf 'Missing argument to %s\n' "$1" >&2
                    exit 1
                fi
                check_charset "$2"
                shift 2
                ;;
            # alias '--sign-with' to '-u' (short for '--local-user')
            # https://github.com/QubesOS/qubes-issues/issues/3325#issuecomment-1039877769
            --sign-with=*)
                options+=("-u" "${1:12}")
                shift
                ;;
            --sign-with)
                if (( $# >= 2 )); then
                    options+=("-u" "$2")
                    shift 2
                else # let qubes-gpg-client error out
                    options+=("$1")
                    shift
                fi
                ;;
            --auto-key-locate)
                # Generally not safe to use, but allow using with the default
                # value (and ignore the option in such case as it's no-op)
                # See https://github.com/QubesOS/qubes-issues/issues/8287
                if [ "$2" = "local,wkd" ]; then
                    shift 2
                else
                    printf 'Unsupported --auto-key-locate %s (only local,wkd value is allowed)\n' "$2" >&2
                    exit 1
                fi
                ;;
            --cert-digest-algo|\
            --cert-notation|\
            --cipher-algo|\
            --command-fd|\
            --comment|\
            --compress-algo|\
            --default-recipient|\
            --digest-algo|\
            --disable-cipher-algo|\
            --disable-pubkey-algo|\
            --encrypt-to|\
            --hidden-encrypt-to|\
            --hidden-recipient|\
            --list-options|\
            --local-user|\
            --keyid-format|\
            --max-output|\
            --personal-cipher-preferences|\
            --personal-compress-preferences|\
            --personal-digest-preferences|\
            --recipient|\
            --s2k-cipher-algo|\
            --s2k-count|\
            --s2k-digest-algo|\
            --s2k-mode|\
            --sender|\
            --sig-notation|\
            --set-filename|\
            --set-notation|\
            --trust-model|\
            --trusted-key|\
            --try-secret-key|\
            --verify-options)
                if (( $# >= 2 )); then
                    options+=("$1" "$2")
                    shift 2
                else # let qubes-gpg-client error out
                    options+=("$1")
                    shift
                fi
                ;;
            -[!-]*)
                if [[ "$1" =~ ^-[bacdekKnqst]*[NrRu]$ ]] && (( $# >= 2 )); then
                    options+=("$1" "$2")
                    shift 2
                elif [[ "$1" =~ ^(-[bacdekKnqst]*)o(.*)$ ]]; then
                    if (( ${#BASH_REMATCH[1]} > 1 )); then
                        options+=("${BASH_REMATCH[1]}")
                    fi
                    if (( ${#BASH_REMATCH[2]} > 0 )); then
                        set_output "${BASH_REMATCH[2]}"
                        shift
                    elif (( $# >= 2 )); then
                        set_output "$2"
                        shift 2
                    else
                        printf 'Missing argument to -o\n' >&2
                        exit 1
                    fi
                else # if $# is too small, let qubes-gpg-client error out
                    options+=("$1")
                    shift
                fi
                ;;
            --)
                eoo=1
                options+=("$1")
                shift
                ;;
            *)
                options+=("$1")
                shift
                ;;
        esac
    else
        if ((special_filenames)) && [[ "$1" = "-&"* ]]; then
            options+=("/proc/self/fd/${1#-&}")
        else
            options+=("$1")
        fi
        shift
    fi
done

if [[ "$localgpg" -eq 1 ]]
then
    exec /usr/bin/gpg "${origargs[@]}"
    exit $?
fi

. /etc/profile.d/qubes-gpg.sh

if ((output)); then
    if [[ "$target" != '-' ]]; then exec > "$target"; fi
    exec qubes-gpg-client -o- "${options[@]}"
else
    exec qubes-gpg-client "${options[@]}"
fi
