#!/bin/sh # ginger — a very small client for gingerfresh.org # # ginger WORD download paste WORD (prints message, saves file) # ginger -u FILE [--keep] [-m] upload FILE # # Upload is temp-only by default (served once, no permanent copy) — the opposite # of the website's default. --keep tells the server to also stash a permanent copy. # -m / --message prompts you for a one-line note to attach. BASE="https://gingerfresh.org" usage() { cat >&2 <<'EOF' usage: ginger WORD download a paste (prints message, saves any file) ginger -u FILE [--keep] [-m] upload a file default: temp-only (one download, nothing kept) --keep : also keep a permanent copy server-side -m : prompt for a message to attach EOF exit 1 } mode=download keep=0 want_msg=0 arg="" # --- argument parsing: flags in any order, last bare word wins as FILE/WORD --- while [ $# -gt 0 ]; do case "$1" in -u|--upload) mode=upload ;; --keep) keep=1 ;; -m|--message) want_msg=1 ;; -h|--help) usage ;; -*) echo "unknown option: $1" >&2; usage ;; *) arg="$1" ;; # the FILE (upload) or the WORD (download) esac shift done [ -n "$arg" ] || usage # helper: pull filename="..." out of a saved header dump (CRLF-tolerant) header_filename() { tr -d '\r' < "$1" \ | grep -i '^content-disposition:' \ | sed -n 's/.*filename="\([^"]*\)".*/\1/p' } # ============================== UPLOAD ============================== if [ "$mode" = upload ]; then [ -f "$arg" ] || { echo "no such file: $arg" >&2; exit 1; } # always serve=on, otherwise the server never hands us a word to return. # nokeep=on unless --keep, so the default is "burn it after one read". set -- -sS -F "file=@$arg" -F "serve=on" [ "$keep" -eq 1 ] || set -- "$@" -F "nokeep=on" if [ "$want_msg" -eq 1 ]; then printf 'message: ' >&2 # prompt on stderr so stdout stays just-the-word IFS= read -r msg set -- "$@" -F "message=$msg" fi # the reply is received.html; the only /WORD link in it is the slug # (the "new paste" link is bare href="/", no word, so it can't match). word=$(curl "$@" "$BASE/upload" \ | grep -oE 'href="/[A-Za-z0-9]+"' \ | head -n1 \ | sed 's#href="/##; s#"##') if [ -n "$word" ]; then echo "$word" # the word and nothing else — pipe away else echo "upload failed (no word in response)" >&2 exit 1 fi exit 0 fi # ============================= DOWNLOAD ============================ word="$arg" # one scratch dir per run, under /tmp ($TMPDIR). We never delete anything — # the OS owns /tmp and clears it in its own time. Files land here, not cwd. work=$(mktemp -d) hdr="$work/headers" body="$work/body" # ONE GET. This serves *and* shreds the endpoint, so we keep whatever comes back. curl -sS -D "$hdr" -o "$body" "$BASE/$word" # A filename in the headers means /WORD itself *was* the file (file-only paste). fname=$(header_filename "$hdr") if [ -n "$fname" ]; then cp "$body" "$fname" # copy out of /tmp into cwd; original stays put echo "saved: $fname" exit 0 fi # Otherwise it's the HTML message page. Lift the text out of
# (may span many lines), then unescape the three entities the server emits. awk ' /