#!/bin/sh

# Author:     darren chamberlain <dlc@sevenroot.org>
# Co-Author:  Paul Bournival <paulb-ns@cajun.nu>
# Co-Author:  Mikhail Novosyolov <mikhailnov@dumalogiya.ru>
#

# bashlib is used by sourcing it at the beginning of scripts that
# needs its functionality (by using the . or source commands).

PATH=/bin:/usr/bin

#
# Set version number
# Must be an integer because bash cannot compare float numbers
#
VERSION="2"

# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
# Initialization stuff begins here. These things run immediately, and
# do the parameter/cookie parsing.
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

# Global debug flag. Set to 0 to disable debugging throughout the lib
DEBUG=0

# capture stdin for POST methods. POST requests don't always come in
# with a newline attached, so we use cat to grab stdin and append a newline.
# This is a wonderful hack, and thanks to paulb.
STDIN=$(/bin/cat)
if [ -n "${STDIN}" ]; then
  QUERY_STRING="${STDIN}&${QUERY_STRING}"
fi

# Handle GET and POST requests... (the QUERY_STRING will be set)
if [ -n "${QUERY_STRING}" ]; then 
  # name=value params, separated by either '&' or ';'
  if echo ${QUERY_STRING} | grep '=' >/dev/null ; then
    for Q in $(echo ${QUERY_STRING} | /usr/bin/tr ";&" "\012") ; do
      #
      # Clear our local variables
      #
      unset name
      unset value
      unset tmpvalue
  
      #
      # get the name of the key, and decode it
      #
      name=${Q%%=*}
      name=$(echo ${name} | \
             /usr/bin/sed -e 's/%\(\)/\\\x/g' | \
             /usr/bin/tr "+" " ")
      name=$(echo ${name} | \
             /usr/bin/tr -d ".-")
      name=$(printf ${name} | /usr/bin/tr -d '$`')
  
      #
      # get the value and decode it. This is tricky... printf chokes on
      # hex values in the form \xNN when there is another hex-ish value
      # (i.e., a-fA-F) immediately after the first two. My (horrible)
      # solution is to put a space aftet the \xNN, give the value to
      # printf, and then remove it.
      #
      tmpvalue=${Q#*=}
      tmpvalue=$(echo ${tmpvalue} | \
                 /usr/bin/sed -e 's/%\(..\)/\\\x\1 /g')
      #echo "Intermediate \$value: ${tmpvalue}" 1>&2
  
      #
      # Iterate through tmpvalue and printf each string, and append it to
      # value
      #
      for i in ${tmpvalue}; do
          g=$(printf ${i})
          value="${value}${g}"
      done
      #value=$(echo ${value})
  
      eval "export FORM_${name}='${value}'"
    done
  else # keywords: foo.cgi?a+b+c
    Q=$(echo ${QUERY_STRING} | tr '+' ' ')
    eval "export KEYWORDS='${Q}'"
  fi
fi

#
# this section works identically to the query string parsing code,
# with the (obvious) exception that variables are stuck into the
# environment with the prefix COOKIE_ rather than FORM_. This is to
# help distinguish them from the other variables that get set
# automatically.
#
if [ -n "${HTTP_COOKIE}" ]; then 
  for Q in ${HTTP_COOKIE}; do
    #
    # Clear our local variables
    #
    name=
    value=
    tmpvalue=

    #
    # Strip trailing ; off the value
    #
    Q=${Q%;}

    #
    # get the name of the key, and decode it
    #
    name=${Q%%=*}
    name=$(echo ${name} | \
           /usr/bin/sed -e 's/%\(\)/\\\x/g' | \
           /usr/bin/tr "+" " ")
    name=$(echo ${name} | \
           /usr/bin/tr -d ".-")
    name=$(printf ${name})

    # Decode the cookie value. See the parameter section above for
    # an explanation of what this is doing.
    tmpvalue=${Q#*=}
    tmpvalue=$(echo ${tmpvalue} | \
               /usr/bin/sed -e 's/%\(..\)/\\\x\1 /g')
    #echo "Intermediate \$value: ${tmpvalue}" 1>&2

    #
    # Iterate through tmpvalue and printf each string, and append it to
    # value
    #
    for i in ${tmpvalue}; do
        g=$(printf ${i})
        value="${value}${g}"
    done
    #value=$(echo ${value})

    #
    # Export COOKIE_${name} into the environment
    #
    #echo "exporting COOKIE_${name}=${value}" 1>&2
    eval "export COOKIE_${name}='${value}'"
  done
fi

# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
# functions and all that groovy stuff
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#
# Shameless plug, advertises verion.
version() {
  echo "bashlib, version ${VERSION}"
}

version_html() {
  echo -n "<a href=\"http://sevenroot.org/dlc/2000/12/bashlib\">bashlib</a>,"
  echo "version ${VERSION}"
}

#
# Parameter function.
# * When called with no arguments, returns a list of parameters that
#   were passed in.
# * When called with one argument, returns the value of that parameter
#   (if any)
# * When called with more than one argument, assumes that the first is a
#   paramter name and the rest are values to be assigned to a paramter of
#   that name.
#
param() {
  local name
  local value
  if [ $# -eq 1 ]; then
    name=$1
    name=$(echo ${name} | /usr/bin/sed -e 's/FORM_//')
    value=$(/usr/bin/env | /bin/grep "^FORM_${name}=" | /usr/bin/sed -e 's/FORM_//' | /usr/bin/cut -d= -f2-)
  elif [ $# -gt 1 ]; then
    name=$1
    shift
    eval "export 'FORM_${name}=$*'"
  else
    value=$(/usr/bin/env | /bin/grep '^FORM_' | /usr/bin/sed -e 's/FORM_//' | /usr/bin/cut -d= -f1)
  fi
  # "+" is URL-encoded as "%2B", web server replaces spaces with "+", replace back,
  # otherwise safe_param() just removes the "+" sign and looses the space.
  echo "${value}" | /usr/bin/sed -e 's/+/ /'
  unset name
  unset value
}

# shell invocation and X-site scripting prevention
safe_param() {
	param $* | /usr/bin/tr -d '$`<>"%;)(&+'"'"
}

# cookie function. Same explanation as param
cookie() {
  local name
  local value
  if [ $# -eq 1 ]; then
    name=$1
    name=$(echo ${name} | /usr/bin/sed -e 's/COOKIE_//')
    value=$(/usr/bin/env | /bin/grep "^COOKIE_${name}" | /usr/bin/sed -e 's/COOKIE_//' | /usr/bin/cut -d= -f2-)
  elif [ $# -gt 1 ]; then
    name=$1
    shift
    eval "export 'COOKIE_${name}=$*'"
  else
    value=$(/usr/bin/env | /bin/grep '^COOKIE_' | /usr/bin/sed -e 's/COOKIE_//' | /usr/bin/cut -d= -f1)
  fi
  echo ${value}
  unset name
  unset value
}

# keywords returns a list of keywords. This is only set when the script is
# called with an ISINDEX form (these are pretty rare nowadays).
keywords() {
  echo ${KEYWORDS}
}

set_cookie() {
  local name=$1
  shift
  local value=$*
  bashlib_cookies="${bashlib_cookies}; ${name}=${value}"

  bashlib_cookies=${bashlib_cookies#;}

  cookie $name $value
}

#
# send_redirect takes a URI and redirects the browser to that uri, exiting
# the script along the way.
#
send_redirect() {
  local uri
  if [ $# -eq 1 ]; then
    uri=$1
  else
    uri="http://${SERVER_NAME}/${SCRIPT_NAME}"
  fi
  echo "Location: ${uri}"
  echo ""
}

