#!/bin/bash

# Made by @fernandomaroto.
# Modified by @manuel.

_echo2()    { echo "$@" >&2 ; }
_printf2()  { printf "$@" >&2 ; }
_echo2c()   { test "$show_fastest" = "yes" || _echo2 "$@" ; }
_printf2c() { test "$show_fastest" = "yes" || _printf2 "$@" ; }

_die() {
    _echo2 "Error: $1"
    _usage
    exit 1
}

_options() {
    local arg
    local tmp
    local serverlistfile

    for arg in "$@" ; do
        case "$arg" in
            [yY]* | -[yY]* | --[yY]*) yesno="yes" ;;
            [nN]* | -[nN]* | --[nN]*) yesno="no" ;;
            --servers=*)
                serverlistfile="${arg#*=}"
                readarray -t tmp <<< $(cat "$serverlistfile")
                servers_array+=("${tmp[@]}")
                ;;
            --servers-replace=*)
                serverlistfile="${arg#*=}"
                readarray -t tmp <<< $(cat "$serverlistfile")
                servers_array=("${tmp[@]}")
                ;;
            --show-fastest)
                yesno=no
                show_fastest=yes
                ;;
            --list-servers)
                yesno=no
                list_servers=yes
                ;;
            -h | --help)
                _usage
                exit 0
                ;;
            *)
                _die "unsupported parameter '$arg'."
                ;;
        esac
    done
}

_usage() {
    cat <<EOF >&2
Usage: $0 [options]
Options:
    --servers=FILE          FILE includes a list of (additional) keyservers, one for each line.
                            Note: empty lines or comments are not allowed.
    --servers-replace=FILE  Like above, but use only keyservers listed in FILE, and not the predefined ones.
    --show-fastest          Only show (to /dev/stdout) the fastest keyserver. Implies --no. Useful for scripts.
    --list-servers          Only list servers (to /dev/stdout) that would be used for ranking. Implies --no.
    --yes                   Allow refreshing pacman keys using the fastest keyserver.
    --no                    Do not refresh pacman keys.

Without any options, a list of predefined keyservers are ranked, and permission is asked for
refreshing pacman keys using the fastest keyserver.
EOF
}

_run() {
    local yesno="ask"        # --yes = refresh pacman keys, --no = don't refresh pacman keys, "ask" = ask what to do
    local show_fastest=no
    local list_servers=no
    local servers_array=(    # Feel free to suggest mirrors to be added or removed bellow

        # We want to use keyservers only with secured (hkps or https) connections!

        # Status at 2020-Aug-14:

        ############ These don't seem to work:
        ## "pgp.mit.edu"
        #  "keyring.debian.org"
        ## "subset.pool.sks-keyservers.net"
        #  "ipv6.pool.sks-keyservers.net"
        # hkps://keys.mailvelope.com
        ## hkps://hkps.pool.sks-keyservers.net
        # hkps://attester.flowcrypt.com

        ############ These do seem to work:
        hkps://keys.openpgp.org
        hkps://keyserver.ubuntu.com
        hkps://zimmermann.mayfirst.org
        # https://keyserver.ubuntu.com
        # https://zimmermann.mayfirst.org

        ############ These seem to work but only with hkp:
        # "hkp://ipv4.pool.sks-keyservers.net"
        # "hkp://pool.sks-keyservers.net"
        # "hkp://na.pool.sks-keyservers.net"
        # "hkp://eu.pool.sks-keyservers.net"
        # "hkp://oc.pool.sks-keyservers.net"
        # "hkp://p80.pool.sks-keyservers.net"
        # hkp://hkps.pool.sks-keyservers.net
    )
    local helper=/usr/bin/keyserver-rank-helper
    local server
    local cmdresult
    local timeresult
    local fastest
    local log=$(mktemp)

    _options "$@"

    if [ "$list_servers" = "yes" ] ; then
        for server in "${servers_array[@]}" ; do
            echo "$server"
        done
        return
    fi
    
    for server in "${servers_array[@]}"
    do
        _echo2c "Ranking $server ..."
        timeresult="$(/usr/bin/time -f %e $helper $server $log 2>&1 | tail -n 1)"
        echo "$timeresult" >> $log
    done
    _printf2c "\nResults:\n\n"
    test "$show_fastest" = "yes" || cat $log | sort -k 3 | column -t >&2
    fastest="$(cat $log | grep -v -w FAIL | sort -k 3 | head -n 1 | awk '{print $1}')"
    rm -f $log
    _printf2c "\nFastest keyserver is: $fastest\n\n"

    if [ "$show_fastest" = "yes" ] ; then
        echo "$fastest"
        return
    fi

    case "$yesno" in
        yes) ;;
        no)  return ;;
        ask)
            read -p "Refresh pacman keys using the fastest keyserver (y/N)? " >&2
            case "$REPLY" in
                "" | [nN]*) return ;;
            esac
            ;;
    esac
    sudo pacman-key --refresh-keys --keyserver "$fastest"
}

_run "$@"
