#!/bin/sh
# pb: create a Paste.me paste from a file or stdin.
#
#   pb file.js                    # paste a file
#   cat log.txt | pb -e 1d -b     # from stdin, expires in a day, burn after read
#   pb -s python -t "My script" -p s3cret script.py
#   pb update                     # replace this script with the latest version
#
# Install:  curl -fsSL https://paste.msar.me/pb.sh -o /usr/local/bin/pb && chmod +x /usr/local/bin/pb
# No install (stdin stays free for the paste):
#   sh -c "$(curl -fsSL https://paste.msar.me/pb.sh)" pb -e 1d file.txt
#   cat log.txt | sh -c "$(curl -fsSL https://paste.msar.me/pb.sh)" pb -b
#
# Prints the paste URL on stdout and the delete token on stderr.
# Set PASTE_URL to your instance (default https://paste.msar.me).

set -eu

usage() {
    cat >&2 <<USAGE
pb: share a file or piped text on Paste.me

usage: pb [options] [file]
       command | pb [options]
       pb update            download the latest pb from the server

options:
  -t title     title shown on the paste
  -s syntax    highlighting: text, js, python, go, bash, json, ... (default text)
  -e expiry    never, 1h, 1d, 1w, 1m or 1y (default never)
  -b           burn after reading (deleted after the first view)
  -p password  encrypt the paste with a password
  -h           show this help

examples:
  pb -s go main.go
  cat build.log | pb -e 1d -t "CI log"
  pb -b -p s3cret secrets.txt
  pb ./update                 (paste a file that is literally named "update")

server: ${PASTE_URL:-https://paste.msar.me} (set PASTE_URL to change)
USAGE
    exit "${1:-2}"
}

base=${PASTE_URL:-https://paste.msar.me}

# Replace the installed script with the latest copy from the server.
self_update() {
    case $0 in
        */*) self=$0 ;;
        *) self=$(command -v "$0" 2>/dev/null || true) ;;
    esac
    if [ -z "$self" ] || [ ! -f "$self" ]; then
        echo "pb: not running from an installed file, nothing to update." >&2
        echo "    install: curl -fsSL $base/pb.sh -o /usr/local/bin/pb && chmod +x /usr/local/bin/pb" >&2
        exit 1
    fi

    dir=$(dirname "$self")
    if [ ! -w "$dir" ] || [ ! -w "$self" ]; then
        echo "pb: no write access to $self (try: sudo pb update)" >&2
        exit 1
    fi

    # Download next to the target so the final mv is an atomic rename; the
    # shell running this copy keeps reading the old file safely.
    tmp=$(mktemp "$dir/.pb.XXXXXX")
    trap 'rm -f "$tmp"' EXIT
    if ! curl -fsSL "$base/pb.sh" -o "$tmp"; then
        echo "pb: download from $base/pb.sh failed" >&2
        exit 1
    fi
    if [ "$(head -c 9 "$tmp")" != "#!/bin/sh" ] || ! sh -n "$tmp" 2>/dev/null; then
        echo "pb: $base/pb.sh doesn't look like pb, keeping the current version" >&2
        exit 1
    fi

    if cmp -s "$tmp" "$self"; then
        echo "pb is already up to date ($self)"
        exit 0
    fi

    chmod 755 "$tmp"
    mv "$tmp" "$self"
    trap - EXIT
    echo "pb updated from $base/pb.sh ($self)"
    exit 0
}

if [ "${1:-}" = "update" ]; then
    self_update
fi

title="" syntax="" expires="" burn="" password=""

while getopts "t:s:e:p:bh" opt; do
    case $opt in
        t) title=$OPTARG ;;
        s) syntax=$OPTARG ;;
        e) expires=$OPTARG ;;
        b) burn=1 ;;
        p) password=$OPTARG ;;
        h) usage 0 ;;
        *) usage ;;
    esac
done
shift $((OPTIND - 1))
[ $# -le 1 ] || usage

# No file and nothing piped in: show help instead of waiting on the keyboard.
if [ $# -eq 0 ] && [ -t 0 ]; then
    usage 0
fi

file=${1:--}
if [ "$file" != "-" ] && [ ! -r "$file" ]; then
    echo "pb: cannot read $file" >&2
    exit 1
fi

headers=$(mktemp)
trap 'rm -f "$headers"' EXIT

# Multipart form: content=<file reads the file (or stdin) as a text field,
# and --form-string keeps values starting with @ or < literal.
set -- -sS -D "$headers" -F "content=<$file"
[ -n "$title" ] && set -- "$@" --form-string "title=$title"
[ -n "$syntax" ] && set -- "$@" --form-string "syntax=$syntax"
[ -n "$expires" ] && set -- "$@" --form-string "expires=$expires"
[ -n "$burn" ] && set -- "$@" --form-string "burn=1"
[ -n "$password" ] && set -- "$@" -H "X-Paste-Password: $password"

body=$(curl "$@" "$base/api/pastes")
status=$(grep '^HTTP/' "$headers" | tail -n 1 | cut -d' ' -f2)

if [ "${status:-0}" -ge 300 ]; then
    echo "pb: $body" >&2
    exit 1
fi

echo "$body"
token=$(grep -i '^x-delete-token:' "$headers" | cut -d' ' -f2 | tr -d '\r')
[ -n "$token" ] && echo "delete: curl -X DELETE -H 'X-Delete-Token: $token' $base/api/pastes/${body##*/}" >&2
exit 0
