#!/bin/bash
#
# nopaste -- paste to pastebin.com
#
# Copyright 2005,2007,2009 Aron Griffis <agriffis n01se.net>
# Released under the GNU General Public License v2
#

nopaste_version=2.1
pastebin_url=${PASTEBIN_URL:-http://pastebin.com/pastebin.php}

main() {
    declare opt_nick=${PASTEBIN_USER:-${USER:-$(whoami)}}
    declare opt_language=text
    declare opt_diff=false
    declare opt_download=false
    declare opt_xcut=false
    declare opt_parent=
    declare expire=f # set by opt_expire()
    declare shortopts=( n:nick l:language x:xcut p:parent e:expire )
    declare -a parsed_opts parsed_params
    parse_cmdline "$@" || exit
    set -- "${parsed_params[@]}"

    declare -a urls

    if [[ $# -gt 0 ]]; then
        declare f u
        for f; do
            if [[ ! -r $f ]]; then
                echo "nopaste: can't read $f" >&2
                exit 1
            fi
            u=$(docurl --form-string "code2=$(<$f)")
            urls+=( "$u" )
            opt_parent=$(pid "$u")
        done
    else
        declare buf
        if $opt_xcut; then
            buf=$(get_x_clipboard) || exit 1
        else
            read -d '' buf
            [[ -n $buf ]] || exit 1
        fi
        urls=( "$(docurl --form-string "code2=$buf")" )
    fi

    put_x_clipboard <<<"${urls[*]}"
    printf "%s\n" "${urls[@]}"
}

docurl() {
    declare u
    u=$(curl --silent --show-error -o /dev/null -w "%{redirect_url}\n" \
        --form-string "poster=$opt_nick" --form-string "format=$opt_language" \
        --form-string "expiry=$expire" \
        ${opt_parent:+--form-string "parent_pid=$opt_parent"} \
        -F "paste=Send" -F "remember=0" "$@" "$pastebin_url") || exit 1
    if [[ -n $opt_parent ]] && $opt_diff; then
        u="$pastebin_url?diff=$(pid "$u")"
    elif $opt_download; then
        u="$pastebin_url?dl=$(pid "$u")"
    fi
    echo "$u"
}

pid() {
    echo "${1##*[/=]}"
}

get_x_clipboard() {
    if type -P xclip &>/dev/null; then
        xclip -o
    elif type -P xcut &>/dev/null; then
        xcut -p
    else
        echo "nopaste: xclip or xcut required for --xcut" >&2
        return 1
    fi
}

put_x_clipboard() {
    xclip 2>/dev/null || xcut 2>/dev/null
}

opt_expire:() {
    case $1 in
        d*) expire=d ;;     # day
        [fn]*) expire=f ;;  # forever/never
        *) expire=m ;;      # month
    esac
}

opt_private:() {
    pastebin_url=${pastebin_url%%://*}://$1.${pastebin_url#*://}
}

opt_help() { usage; exit; }
opt_version() { echo "nopaste $nopaste_version"; exit; }

usage() {
    cat <<'EOT'
usage: nopaste [options] [files]

    -e --expire WHEN    Set expiry day/month/forever, defaults to forever
    -l --language LANG  Set language, defaults to text
    -n --nick USER      Set nick (honors PASTEBIN_USER)
    -p --parent PID     Set parent paste id, for diffs
       --private STR    Use a private pastebin
    -x --xcut           Paste from X selection (using xclip or xcut)

    --diff       Return diff URL (with --parent or multiple)
    --download   Return download URL

    --help       Show this help
    --version    Show version info
EOT
}

#=============================================================================
# simple bash command-line processing
#
# (c) Copyright 2008 Aron Griffis <agriffis n01se.net>
# Released under the GNU GPL v2
#=============================================================================

parse_cmdline() {
    # extract long options from variable declarations
    declare getopt_long=$(set | \
        sed '/^opt_/!d; s/^opt_//; s/_/-/g;
            s/\(.*\)=false$/\1 no-\1/;
            s/\(.*\)=true$/\1 no-\1/;
            s/=.*/:/; s/()//;' | xargs | sed 's/ /,/g')

    # augment the shortopts array with takes-a-value colon;
    # for example f:file becomes f::file
    declare shortopts=( "${shortopts[@]}" )
    declare i x
    for ((i=0; i<${#shortopts[@]}; i++)); do
        x=${shortopts[i]}
        if [[ ",$getopt_long," == *,"${x#?:}":,* ]]; then
            shortopts[i]=${x/:/::}
        fi
    done
    declare getopt_short=$(IFS=''; echo "${shortopts[*]%:*}")

    declare args
    args=$(getopt -o "$getopt_short" \
        --long "$getopt_long" -n "$0" -- "$@") || return
    eval set -- "$args"

    declare opt var val
    parsed_opts=()
    while true; do
        [[ $1 == -- ]] && { shift; break; }

        # translate short options to long
        if [[ $1 == -? ]]; then
            opt=${1#-}
            for x in "${shortopts[@]}"; do
                if [[ $x == "$opt":* ]]; then
                    opt=${x##*:}
                    break
                fi
            done
        else
            opt=${1#--}
        fi

        # figure out $var and $val; shift positional params
        var=opt_${opt//-/_}
        case ",$getopt_long," in
            # make sure to handle opt_no_something (--no-something) 
            # which has a (silly) negation of --no-no-something
            *",no-$opt,"*)
                val=true
                parsed_opts=( "${parsed_opts[@]}" "$1" )
                shift ;;
            *",$opt,"*)
                if [[ $opt == no-* ]]; then
                    var=${var/no_/}
                    val=false
                else
                    val=true
                fi
                parsed_opts=( "${parsed_opts[@]}" "$1" )
                shift ;;
            *",$opt:,"*) 
                val=$2
                parsed_opts=( "${parsed_opts[@]}" "$1" "$2" )
                shift 2 ;;
            *)
                echo "error processing $1: not in getopt_long?" >&2
                return 1 ;;
        esac

        if [[ $(type -t "$var") == function ]]; then
            $var
        elif [[ $(type -t "$var:") == function ]]; then
            $var: "$val"
        elif is_array "$var"; then
            eval "$var=( \"\${$var[@]}\" $(printf %q "$val") )"
        elif is_var "$var"; then
            eval "$var=\$val"
        else
            echo "error processing $var: no func/array/var?" >&2
            return 1
        fi
    done

    parsed_params=( "$@" )
}

getopt() {
    declare cmd=${cmd:-${0##*/}}
    if [[ $(command getopt --help 2>&1) == *--longoptions* ]]; then
        command getopt "$@"
    elif [[ $OSTYPE == darwin* ]]; then
        if [[ ! -x /opt/local/bin/getopt ]]; then
            echo "Error: $cmd requires GNU getopt" >&2
            echo "Please install from http://getopt.darwinports.com/" >&2
            exit 1
        fi
        /opt/local/bin/getopt "$@"
    else
        echo "Error: $cmd requires GNU getopt" >&2
        exit 1
    fi
}

is_var() {
    declare -p "$1" &>/dev/null
}

is_array() {
    set -- $(declare -p "$1" 2>/dev/null)
    [[ $2 == -*a* ]]
}

main "$@"
