#!/bin/bash

# Copyright (C) 2009 Andy Spencer
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

HOME=/var/vhosts/paste.frsag.net
# Remove url codings from stdin
function get_modeline {
        modeline=$(
                echo "$QUERY_STRING" |
                sed -e 's/%\([0-9A-F][0-9A-F]\)/\\\\\x\1/g; s/[,&]/ /g' |
                xargs echo -e
        )
        echo "vim: $modeline"
}

# Extract an uploaded file from standard input
#   $2 is the name of the input to extract
function cut_file {
        bnd="${CONTENT_TYPE/*boundary\=/}"
        awk -v "want=$1" -v "bnd=$bnd" '
                BEGIN { RS="\r\n" }

                # reset based on boundaries
                $0 == "--"bnd""     { st=1; next; }
                $0 == "--"bnd"--"   { st=0; next; }
                $0 == "--"bnd"--\r" { st=0; next; }

                # search for wanted file
                st == 1 && $0 ~  "^Content-Disposition:.* name=\""want"\"" { st=2; next; }
                st == 1 && $0 == "" { st=9; next; }

                # wait for newline, then start printing
                st == 2 && $0 == "" { st=3; next; }
                st == 3             { print $0    }
        ' | head -c $((128*1024)) # Limit size to 128K
}

# Print out a generic header
function header {
        echo "Content-Type: $1; charset=UTF-8"
        echo
}

# List previous pastes
function do_cmd {
case "$1" in
head)
        header text/plain
        for i in $(ls -t db/*); do
                basename $i
                basename $i | sed 's/./-/g'
                sed '1,/^$/d; /^\s*$/d' $i | sed -n '1,5s/\(.\{0,60\}\).*/\1/p'
                echo
        done
        ;;
ls)
        header text/html
        echo "<a href='/'>Back</a><br/>"
        echo "<ul>"
        ls -t db | xargs -n1 -I {} echo "<li><a href=\"http://paste.frsag.net/{}?\">{}</a></li>"
        echo "</ul>"
        ;;
esac
}

# Format a file for viewing
function do_print {
        if [ -f "./$1" ]; then
                input="$1"
        elif [ -f "db/$1" ]; then
                input="db/$1"
                trim='1,/^$/d' # sed command to remove cruft
        else
                echo "Status: 404 Not Found"
                header text/plain
                echo "File '$1' not found"
                return
        fi


        if [[ "$REQUEST_URI" == *'?'* ]]; then
                # Create a temp file with the provided modeline
                output="$(mktemp)"
                tmp="$(mktemp)"
                sed "1a$(get_modeline)" "$input" > "$tmp"

                # - I have some plugins in ~/.vim
                # - Run ex in screen to trick it into thinking that it
                #   has a real terminal, note that we also have to set
                #   term=xterm-256color in vimrc
                screen -D -m ex -nXZ -i NONE -u vimrc \
                        '+sil! set fde= fdt= fex= inde= inex= key= pa= pexpr=' \
                        '+sil! set iconstring= ruf= stl= tal=' \
                        "+sil! set titlestring=$1\ -\ paste.frsag.net" \
                        '+sil! set noml'     \
                        '+sil! 2d|'$trim     \
                        '+sil! %s/\r//g' \
                        '+sil! TOhtml'       \
                        "+sav! $output" \
                        '+qall!'        \
                        "$tmp"

                header text/html
                cat "$output"
                rm "$tmp" "$output"
        else
                header text/plain
                sed "$trim" "$input"
        fi
}


# Upload handler
function do_upload {
        body=$(cat -)
        spam=$(echo -n "$body" | cut_file "ignoreme")
        text=$(echo -n "$body" | cut_file "(text|x)")
        if [ ! -z "$spam" ]; then
                header text/plain
                echo "Spam check.."
                exit
        fi
        if [ -z "$text" ]; then
                header text/plain
                echo "No text pasted"
                exit
        fi
        output="$(mktemp db/XXXXX)"
        uri="$url$(basename "$output")${QUERY_STRING:+"?"}"

        # Format, spam check, and save message
        (
                get_modeline
                echo "Date: $(date -R)"
                echo "From: $REMOTE_ADDR"
                echo
                echo "$text"
        ) | spamc -E > "$output"

        # Test for spam
        if [ "$?" -ne 0 ]; then
                # Report spam
                header text/plain
                echo "Your post has been marked as spam!"
                echo "Spam test results are as folllows.. "
                echo
                cat "$output"
                mv  "$output" spam
        else
                # Redirect user
                echo "Status: 302 Found"
                echo "Location: $uri"
                header text/plain
                echo "$uri"
        fi
}

# Default index page
function do_help {
filetypes=$(
        ls /usr/share/vim/vim*/syntax/ $HOME/.vim/syntax/ |
        sed -n '/^\(syntax\|manual\|synload\|2html\|colortest\|hitest\).vim$/d; s/.vim$//p' |
        sort | uniq
)
uploads=$(ls -t db | head -n 10)

header text/html
cat - <<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
        <head>
                <title>paste.frsag.net - Vim based pastebin</title>
                <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
                <meta name="description" content="vpaste: Vim based pastebin" />
                <meta name="keywords" content="vpaste,paste,pastebin,vim" />
                <style type="text/css">
                        * { margin:0; padding:0; }
                        body { margin:1em; }
                        h4 { margin:1em 0 0 0; }
                        blockquote,dd,dl,p,pre,ul { margin:0 0 0 2em; }
                        dt { font-weight:bold; padding:0.5em 0 0 0; }
                        blockquote { width:50em; font-size:small; }
                        span { font-family:monospace; }
                </style>
        </head>
        <body>
                <form id="form" method="post" action="?" enctype="multipart/form-data">
                <div style="margin:0 0 1.5em 0;">
                <input style="display:none" type="text" name="ignoreme" value="">
                <textarea name="text" cols="80" rows="25" style="width:100%; height:20em;"></textarea>
                <select onchange="document.getElementById('form').action =
                        document.location + '?ft=' + this.value;">
                <option value="" selected="selected" disabled="disabled">Filetype</option>
                <option value="">None</option>
                $(for ft in $filetypes; do
                        echo "<option>$ft</option>"
                done)
                </select>
                <input type="submit" value="Paste" />
                </div>
                </form>
                <h4>LATEST UPLOADS</h4>
                <ul>$(for upload in ${uploads[@]}; do
                        echo "<li><a href='$upload?'>$upload</a></li>"
                done)
                </ul>
                <hr style="margin-top: 10px;"/>
                <p style="border: 1px; text-align: right;">
                        <a href="vpaste">tool for paste</a> |
                        <a href="ls">list all</a> |
                        <a href="head">sample all</a> |
                        Thanks to <a href="http://vpaste.net/">Andy Spencer - vpaste.net</a>
                </p>
        </body>
</html>
EOF
}

# Main
url="http://$HTTP_HOST${REQUEST_URI/\?*}"
pathinfo="${REQUEST_URI/*\/}"
pathinfo="${pathinfo/\?*}"
echo "$REMOTE_ADDR - `date -R` - $REQUEST_METHOD $url $pathinfo" >>access.log

if [ "$pathinfo" = ls ]; then
        do_cmd ls
elif [ "$pathinfo" = head ]; then
        do_cmd head
#elif [ "$pathinfo" = greg ]; then
#       header text/plain
#       env
#       set
elif [ "$pathinfo" ]; then
        do_print "$pathinfo"
elif [ "$CONTENT_TYPE" ]; then
        do_upload
else
        do_help
fi