#!/usr/bin/env sh
#
# send-patch: "The Telodendria Patch Sender"
#
# This is a simple script for posting patch files to
# a single room(generally the Telodendria patch room.)

. "$(pwd)/tools/lib/common.sh"

# Path to the patch to send.
PATCHFILE="$1"

# Tries to decompose the name and the HS from an MXID using
# sed.
UR_NAME="$(echo "$MXID" | sed "s/\@\(.*\)\:\(.*\)/\1/")"
HS_NAME="$(echo "$MXID" | sed "s/\@\(.*\)\:\(.*\)/\2/")"

# Prompts the user for a password, while disabling echo-ing.
readpwd() {
    printf "$1"
    stty -echo -ctlecho
    read -r "$2"
    echo
    stty echo ctlecho
}

# Makes an HTTP request, setting the RETURN variable for the
# actual reply from the server and the ERROR_CODE variable
# for a HTTP error code.
request() {
    RETURN=$(http -i "$@" 2>/dev/null)
    ERROR_CODE=$(echo "$RETURN" | head -n1 | awk '{print $2}')
    RETURN=$(echo "$RETURN" | sed '1,/^[[:space:]]*$/d')
}

# Prompts user to login and gives out an access token to use
# in the ACCESS_TOKEN variable
matrix_login() {
    # Check authentication methods
    echo "Checking authentication methods..."
    request "$HS_BASE/_matrix/client/v3/login"
    AUTH_METHODS=$RETURN
    if [ $ERROR_CODE -ne 200 ]; then
        echo "Homeserver does not support login."
        exit 1
    fi
    if ! echo "$AUTH_METHODS" | grep "m.login.password" >/dev/null; then
        echo "Homeserver does not support password authentication."
        exit 1
    fi
    # Homeserver does support password authentication, so request
    # them one.
    if [ -z "$MXPW" ]; then
        readpwd "Enter your Matrix password: " MXPW
    fi
    # Tries to login using the "Telodendria Patch Script" device
    # name
    JSON=$(
        printf '{'
        printf '  "identifier": {'
        printf '    "type": "m.id.user",'
        printf '    "user": %s' "$(json -e $UR_NAME)"
        printf '  },'
        printf '  "initial_device_display_name": "Telodendria Patch Script",'
        printf '  "type": "m.login.password",'
        printf '  "password": %s' "$(json -e "$MXPW")"
        printf '}'
    )
    request -X POST -d "$JSON" $HS_BASE/_matrix/client/v3/login
    LOGIN="$RETURN"
    if [ $ERROR_CODE -ne 200 ]; then
        echo "Login failed."
        echo "$RETURN"
        exit 1
    fi
    ACCESS_TOKEN=$(echo "$LOGIN" | json -s "access_token->@decode")
}

# Logs out of Matrix using the ACFESS_TOKEN environment variable
matrix_logout() {
    if [ -z "$ACCESS_TOKEN" ]; then
        echo "No access token"
        exit 1
    fi
    request -X POST -H "Authorization: Bearer $ACCESS_TOKEN" "$HS_BASE/_matrix/client/v3/logout"
    LOGOUT=$RETURN
    if [ $ERROR_CODE -ne 200 ]; then
        echo "Logout failed."
        echo "$RETURN"
        exit 1
    fi
    echo "Logged out."
}

send_patch() {
    if [ -z "$ACCESS_TOKEN" ]; then
        matrix_login
        DO_LOGOUT=1
    fi
    # We are sucessfully logged in as our user, now let's
    # try to upload and post our patch
    echo "$PATCHFILE"
    request -X POST \
        -H "Content-Type: text/x-patch" \
        -H "Authorization: Bearer $ACCESS_TOKEN" \
        -d "@$PATCHFILE" \
        "$HS_BASE/_matrix/media/v3/upload"
    MXCID=$RETURN
    if [ $ERROR_CODE -ne 200 ]; then
        echo "Upload failed."
        echo "$RETURN"
        matrix_logout
        exit 1
    fi
    MXCID=$(echo "$MXCID" | json -s "content_uri->@decode")
    echo "MXC ID: $MXCID"
    JSON=$(
        base=$(basename "$PATCHFILE")
        printf '{'
        printf '  "body": %s,' "$(json -e $base)"
        printf '  "filename": %s,' "$(json -e $base)"
        printf '  "info": {'
        printf '    "mimetype": "text/x-patch",'
        printf '    "size": %d' $(wc -c "$PATCHFILE" | awk '{print $1}')
        printf '  },'
        printf '  "msgtype": "m.file",'
        printf '  "url": %s' "$(json -e $MXCID)"
        printf '}'
    )
    http -X PUT -d "$JSON" -H "Authorization: Bearer $ACCESS_TOKEN" \
        "$HS_BASE/_matrix/client/v3/rooms/$PATCHES_ROOM/send/m.room.message/$(date +%s)" \
        2>/dev/null >/dev/null && echo "Patch sent."

    # Log out if we generated an access token
    if [ "$DO_LOGOUT" -eq "1" ]; then
        matrix_logout
    fi
}

# Check if the patch file is valid.
if [ "$(basename "$PATCHFILE" .patch)" = "$PATCHFILE" ] || [ ! -f "$PATCHFILE" ]; then
    echo "Format: $0 file.patch"
    exit 1
fi
echo "Sending file '$PATCHFILE'"
echo "Checking homeserver's real address using .well-known..."
request "https://$HS_NAME/.well-known/matrix/client"
case "$ERROR_CODE" in
    "200")
        WELL_KNOWN=$RETURN
        if [ -z "$WELL_KNOWN" ]; then
            echo "well-known test returned 200 but no correct input was given."
            exit 1
        fi
        # well-known entry is correct, we can now store our base endpoint
        HS_BASE=$(printf "$WELL_KNOWN" | json -s "m.homeserver->base_url->@decode") && send_patch
        ;;
    *)
        echo "$ERROR_CODE"

        echo "well-known test failed."
        printf "Please enter your homeserver base URL: "
        read -r HS_BASE
        echo
        send_patch
        ;;
esac