#!/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"
Source