#!/bin/sh

# This file is subject to the terms and conditions of the GNU General Public
# License version 2.

# Copyright (C) Hewlett-Packard (Paul Bame) paul_bame@hp.com

MIMETYPES=/etc/apache/mime.types
[ -r $MIMETYPES ] || MIMETYPES=/etc/apache-ssl/mime.types

export CVSROOT=/var/cvs
if [ -r /etc/cvs-cron.conf ]
then
    . /etc/cvs-cron.conf
    CVSROOT=$REPOS
fi

# add ?debug=true to the end of your URL for debugging mode
debugt=false
case "$QUERY_STRING" in
    *debug=true*)
	debug=true
	echo 'content-type: text/plain'
	echo
	exec 2>&1
	env | sort
#	set -x
	;;
esac

parse_pathinfo()
{
    CMPATH=${PATH_INFO}
    # The last set of brackets determines the version requested
    case $PATH_INFO in
	?*,?*,?*) # path,rev,rev
	    CGI_r2=${CMPATH##*,}
	    CMPATH=${CMPATH%,*}
	    CGI_r1=${CMPATH##*,}
	    CMPATH=${CMPATH%,*}
	    ;;
	*\[*\]*)
	    CMVERSION=${PATH_INFO##*\[}
	    CMVERSION=${CMVERSION%%\]*}
	    ;;
	*) CMVERSION= ;;
    esac

    # CMPATH could include other [...] pairs - strip them out
    while true
    do
	$debug && set -x
	: CMPATH = $CMPATH
	case $CMPATH in
	    *\[*\]*) true ;;
	    *) break;
	esac
	left=${CMPATH%%\[*}
	CMVERSION=${CMPATH#*\[}
	CMVERSION=${CMVERSION%%\]*}
	right=${CMPATH#*\]}
	CMPATH=$left$right
    done

    [ "$CMPATH" = "$CMVERSION" ] && CMVERSION=
    CMSPEC="${CMVERSION:+ -r$CMVERSION}"
}

parse_query_string()
{
    typeset qs namevalue name value
    qs="${QUERY_STRING:-}"
    namevalue=
    while [ "$qs" != "$namevalue" ]
    do
        namevalue=${qs%%&*}
        name=${namevalue%%=*}
        [ "$name" != "$namevalue" ] && value=${namevalue#$name=}
        eval CGI_"$name"=\'"$value"\'
        qs=${qs#$namevalue&}
    done
}

header()
{
    echo 'content-type: text/html'
    echo
    echo "<title>$1</title>"
    echo -n '<p align=right><font size=-1><i>'
    echo '<a href="http://ftp.parisc-linux.org/cgi-bin/cvslite/build-tools/cvslite?log=y">cvslite</a> 1.7, A quick hack by <a href=mailto:bame@puffin.external.hp.com>Paul Bame</a></i></font></p>'
    echo "<h1 align=center>$1</h1>"
}

gettype()
{
    typeset -l EXT extensions
    typeset FILE type

    # extract basename first
    EXT=${1##*/}
    # Now extension
    case "$EXT" in
        *.*) EXT=${EXT##*.} ;;
        *) EXT=
    esac

    if [ -z "$EXT" ] 
    then
        echo text/plain
        return
    fi

    # read the mimetypes file
    if [ ! -r $MIMETYPES ]
    then
        # Can't read types file - return
        $debug && echo "Warning: Can't read mime types file: $MIMETYPES" >&2
        echo text/plain
        return
    fi

    while read type extensions
    do
	for n in $extension
	do
	    if [ $n = $EXT ]
	    then
	        echo $type
		return 0
	    fi
	done
    done <$MIMETYPES

    # didn't find it
    $debug && echo "Can't find type $EXT in mime types file: $MIMETYPES" >&2
    echo text/plain
}

# From the name, figure out whether we'll claim it is HTML or
# plain text.  This works most of the time for code with basic
# non-Microsloth text and html documentation.  Note the file may
# not actually exist.
contenttype()
{
    typeset ct=text/plain

    case $1 in
	# Accelerate these
	*.[hH][Tt][Mm]|*.[hH][Tt][Mm][lL]|*.[sS][hH][Tt][Mm][lL])
	     ct=text/html
	     ;;
	*.x) # Willy's web site stuff
	     ct=text/html
	     ;;
	# Override these common programming lang files
	*.[cChHs]|*.[Cc][Xx][Xx]|*.sh)
	     ct=text/plain
	     ;;
	*.*) # Use web server mime.types
	     ct=$(gettype $1)
	     ;;
	*)   			# files with no extension call text/plain
	     ct=text/plain
	     ;;
    esac

    echo "content-type: $ct"
}

fancylog()
{
    typeset b
    b=${1##*/}
    rlog $1 |
        awk -v basename="$b" '
	    (st == 0 && $1 == "head:") {
		$2 = "<a href=\"./" basename "\"><b>" $2 "</b></a>"
		print
		next
	    }
	    (st == 0 && $1 == "----------------------------" && NF == 1) {
	        st = 1;
		next
	    }
	    (st == 1 && $1 == "----------------------------" && NF == 1) {
	        next
	    }
	    (st == 1 && $1 == "revision") {
		link = "<a href=\"./[" $2 "]" basename "\"><b>" $2 "</b></a>"
		if (oldrev != "") {
		    printf("<a href=\"%s,%s,%s\">Differences %s -&gt; %s</a>\n", \
		    basename, $2, oldrev, $2, oldrev)
		}
		printf("<hr noshade size=1>%s ", link);
		oldrev = $2
		next
	    }
	    (st == 1 && $1 == "date:") {
		print
		next
	    }
	    (st == 1) {
	        # print "<i>" $0 "</i>"
	        print 
		next
	    }
	    (st == 0 && NF == 2 && $1 == "symbolic" && $2 == "names:") {
	        print; st = 2; next
	    }
	    (st == 2 && NF == 2) {
	        n = $1
		sub(":", "", n)
		link = "<a href=\"./[" n "]" basename "\"><b>" $2 "</b></a>"
		print "\t" $1, link
		next
	    }
	    {st = 0; next}
	'
}

get_revs()
{
    HEAD=
    HEAD_1=
    TAGS=
    NUMERIC=
    eval $(rlog $1 |
        awk '
	    (st == 0 && $1 == "----------------------------" && NF == 1) {
	        st = 1; next
	    }
	    (st == 0 && $1 == "head:") {
	        print "HEAD=" $2
		next
	    }
	    (st == 1) {
		if (numeric++ == 1)
		    print "HEAD_1=" $2
	        if ($1 == "revision")
		    print "NUMERIC=\"$NUMERIC " $2 "\""
		st = 0; next
	    }
	    (st == 0 && NF == 2 && $1 == "symbolic" && $2 == "names:") {
	        st = 2; next
	    }
	    (st == 2 && NF == 2) {
	        n = $1
		sub(":", "", n)
		print "TAGS=\"$TAGS " n "\""
		next
	    }
	    {st = 0; next}
	')
}

diff_form()
{
    get_revs "$CVSPATH"

    [ X"$CGI_r1" = X-1 -o X"$CGI_r1" = X ] && CGI_r1=$HEAD_1
    [ X"$CGI_r2" = XHEAD -o X"$CGI_r2" = X ] && CGI_r2=$HEAD

    echo "<form>"
    echo "<select name=r1>"
    for n in $TAGS $NUMERIC
    do
	if [ "$CGI_r1" = "$n" ]
	then
	    echo "<option value=$n selected>$n"
	else
	    echo "<option value=$n>$n"
	fi
    done
    echo "</select>"
    echo "<select name=r2>"
    for n in $TAGS $NUMERIC
    do
	if [ "$CGI_r2" = "$n" ]
	then
	    echo "<option value=$n selected>$n"
	else
	    echo "<option value=$n>$n"
	fi
    done
    echo "</select>"
    echo "<input type=submit value=Diff></form>"
}

parse_pathinfo

# Path to the CVS file or directory, minus the trailing ,v if any
CVSPATH=$CVSROOT$CMPATH

# What's this URL?
MYURL=http://${SERVER_NAME}
[ ! -z "$SERVER_PORT" -a "$SERVER_PORT" != 80 ] &&
	MYURL="$MYURL:$SERVER_PORT"

# This is poor for Location headers if QUERY_STRING
# WARNING REQUEST_URI is Apache specific
MYURL="$MYURL$REQUEST_URI"


# Does the URL refer to a CVS file?
if [ -f "$CVSPATH,v" ]
then
    parse_query_string

    if [ -n "$CGI_r1" -a -n "$CGI_r2" ]
    then
	header "cvs diff -r$CGI_r1 -r$CGI_r2 $PATH_INFO"
	diff_form
	echo "<pre>"
	rcsdiff -r"$CGI_r1" -r"$CGI_r2" -u -10 "$CVSPATH" |
		sed -e 's,&,\&amp;,g' -e 's,<,\&lt;,g' \
			-e 's,>,\&gt;,g' \
			-e '/^-/s:.*:<font color=red>&</font>:' \
			-e '/^+/s:.*:<font color=blue>&</font>:' \
			-e '/^@@/s:.*:<hr noshade size=1><b>&</b>:'
	echo "</pre>"
        exit
    fi

    if [ "$CGI_log" = y ]
    then
	header "cvs log $PATH_INFO"
	diff_form
	echo "<pre>"
	rlog "$CVSPATH" |
	    sed -e 's,&,\&amp;,g' -e 's,<,\&lt;,g' \
			-e 's,>,\&gt;,g' |
	    fancylog "$CVSPATH"
	echo "</pre>"
	exit
    fi

    contenttype "$CMPATH"
    echo
    if co -p$CMSPEC "$CVSPATH" 2>/tmp/xx$$
    then
	exit 0
    else
	echo "<pre>"
	cat /tmp/xx$$
	echo "</pre>"
    fi
    rm -f /tmp/xx$$
fi

# Does the URL refer to an unversioned file hanging out in the CVS archive?
if [ -f "$CVSPATH" ]
then
    contenttype "$CVSPATH"
    echo
    cat "$CVSPATH"
    exit
fi

printname()
{
    n="$1"
    typeset crap='<tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt>'
    case "$n" in
	*,v)
	    nn=${n%,v}
	    echo -n "<br><tt>"
	    echo -n "<a href='./$nn?log=y'>L</a>&nbsp;"
	    echo -n "<a href='./$nn?r1=-1&r2=HEAD'>D</a>&nbsp;<tt>"
	    echo "<a href='./$nn'>$nn</a>"
	    ;;
	*)
	    # this is slower than looking for ,v unfortunately
	    if [ -d "$n" ]
	    then
		echo "<br>$crap<a href='./$n/'><b>$n/</b></a>"
	    else
		echo "<br>$crap<a href='./$n'>$n</a>"
	    fi
    esac
}

dir()
{
    # show CVS directory
    header "cvslite: $PATH_INFO"
    echo '(select <b><u>L</u></b> to see a cvs log, <b><u>D</u></b> to see differences)'
    cd "$CVSPATH"
    set -- .. *

    [ "$1" = "*" ] && return

    # Some semi-intelligent logic for laying out directory listings
    let ncols="($# + 9) / 10"
    [ $ncols -gt 4 ] && ncols=4
    col=0
    let nrows="($# + ($ncols - 1)) / $ncols"
    echo "<table border=0 width=100%><tr>"
    while [ $col -lt $ncols ]
    do
	echo "<td valign=top>"
	i=0
	while [ $i -lt $nrows ]
	do
	    [ $# = 0 ] && break
	    printname "$1"; shift 1
	    let i=$i+1
	done
	let col=$col+1
    done
    echo "</table>"
}

# does the URL refer to a directory?
if [ -d $CVSPATH ]
then
    # Need those trailing slashes
    case "$PATH_INFO" in
	*/) dir; exit ;;
	*) echo "Location: $MYURL/"; echo; exit ;;
    esac
fi

# I'm clueless.  Here's a similarly clueless error message.
echo "content-type: text/plain"
echo
echo "huh?"
