#!/bin/sh
# A simple titan upload utility as a POSIX shell script.
#
# This script is dedicated to the public domain according to the terms of CC0:
# https://creativecommons.org/publicdomain/zero/1.0/
#
# History:
# May 23: Original script
# Sep 24: Support edit parameter

usage () {
    echo "Usage: $(basename "$0") [-c CERT_FILE] [-k KEY_FILE] [-t TOKEN] [-m MIMETYPE] URI [FILE]"
}

args=$(getopt hc:k:m:t: "$@")
if [ $? -ne 0 ]; then
    usage
    exit 2
fi
set -- $args
while [ $# -gt 0 ]; do
    case "$1" in
        -h) usage; echo;
            echo "Upload FILE to titan uri URI."
            echo "If FILE is omitted, create/edit file in \$EDITOR then upload."
            echo "If FILE is -, it will be read from standard input."
            echo
            echo "If -m is not used, the mimetype will be:"
            echo "* text/gemini if FILE ends in .gmi or if FILE was omitted or was -;"
            echo "* determined using the 'file' command otherwise."
            echo
            echo "Paths to a client certificate and its private key may optionally be provided,"
            echo "using either environment variables CLIENT_CERT and CLIENT_KEY,"
            echo "or the -c and -k options (which take priority over variables)."
            exit 0;;
        -c) cert="$2"; shift;;
        -k) key="$2"; shift;;
        -t) token="$2"; shift;;
        -m) mimetype="$2"; shift;;
        --) shift; break;;
    esac
    shift
done

if [ $# -lt 1 ] || [ $# -gt 2 ]; then
    usage
    exit 2
fi

cert="${cert:-$CLIENT_CERT}"
key="${key:-$CLIENT_KEY}"

if { [ -n "$cert" ] || [ -n "$key" ] ;} && { [ -z "$cert" ] || [ -z "$key" ] ;}; then
    echo "Both certificate and key are required if either is given."
    exit 2
fi

uri="$1"
file="$2"

args="$(printf "%s" "$uri" | sed -En 's/^(titan:\/\/)?([^\/:]+)(:([0-9]+))?\/(.*)$/\2:\4 \5/p')"
set -- $args
if [ $# -ne 1 ] && [ $# -ne 2 ]; then
    echo "Failed to parse URI: $uri"
    exit 1
fi
host="${1%:*}"
port="${1#*:}"
port="${port:-1965}"
path="$2"

connect () {
    if [ -n "$cert" ]; then 
        openssl s_client -cert "$cert" -key "$key" -quiet -connect "$host:$port"
    else
        openssl s_client -quiet -connect "$host:$port"
    fi 2>/dev/null
}

edit=
realpath="$(printf "%s" "$path" | sed -En 's/;edit$//p')"
if [ -n "$realpath" ]; then
    edit=1
    path="$realpath"
fi

tmpfile=

if [ -z "$file" ]; then 
    file="$(mktemp)" || { echo "Failed to make temp file" && exit 1; }
    tmpfile="$file"
    if [ -n "$edit" ]; then
        strip20 () {
            read header
            case "$header" in
                20*) cat;;
                *) echo "Unexpected response: $header";;
            esac
        }
        (printf "%s\r\n" "titan://$host:$port/$path;edit") | connect | strip20 > "$file"
    fi
    $EDITOR "$file"
    if ! [ -s "$file" ] && [ -z "$edit" ]; then
        echo "Empty file. Aborting."
        exit 0
    fi
    mimetype=${mimetype:-text/gemini}
fi

if [ "$file" = - ]; then
    file="$(mktemp)" || { echo "Failed to make temp file" && exit 1; }
    tmpfile="$file"
    cat>"$file"
    mimetype=${mimetype:-text/gemini}
fi

[ -r "$file" ] || { echo "Can't open $file for reading." && exit 1; }
[ -d "$file" ] && { echo "$file is a directory." && exit 1; }

if [ -z "$mimetype" ]; then
    if [ "${file%%.gmi}" != "$file" ]; then
        mimetype=text/gemini
    else
        mimetype="$(file -b --mime-type "$file")"
    fi
fi

size="$(wc -c < "$file")"

(printf "%s\r\n" "titan://$host:$port/$path;${token:+token=$token;}mime=$mimetype;size=$size"; cat "$file") | connect

[ -n "$tmpfile" ] && rm "$tmpfile"