#!/usr/local/bin/bash
#
# Copyright (C) 2006 SIPfoundry Inc.
# Licensed by SIPfoundry under the LGPL license.
#
# Copyright (C) 2006 Pingtel Corp.
# Licensed to SIPfoundry under a Contributor Agreement.


Action=RUN
Status=1
Args=""
Today=`date`

resolverArgs=""

# Declare script variables in a manner that unit test
# (or end user I suppose) can override
: ${SslDir:=@SIPX_CONFDIR@/ssl}
: ${AuthoritiesDir:=$SslDir/authorities}
: ${ConfigDefs:=@SIPX_CONFDIR@/config.defs}
: ${Configpp:=@bindir@/configpp}
: ${ConfigFiles:=@SIPX_CONFDIR@/authproxy-config @SIPX_CONFDIR@/proxy-config}
: ${PidFile:=@SIPX_RUNDIR@/sipxconfig.pid}
: ${LibDir:=@SIPX_LIBDIR@}
: ${Psql:=psql}
: ${ServiceDir:=/etc/init.d}
: ${SubstituteUser:=su}
: ${Chown:=chown}
: ${LogDir:=@SIPX_LOGDIR@}
: ${TmpDir:=@SIPX_TMPDIR@}
: ${RunningUser:=@SIPXPBXUSER@}
: ${PgUser:=pgsql}
: ${PgSchema:=@SIPX_CONFDIR@/cdr/schema.sql}
: ${DbVersion:=2}
: ${DbPatchDir:=@SIPX_CONFDIR@/cdr}
: ${DbPatchLog:=@SIPX_LOGDIR@/sipcdrpatch.log}

Database=SIPXCDR
Today=`date`

# This function determines the correct service name for Postgres.
postgresService() {
    # If the user has already specified $Service, do not modify it.
    if test -n "$POSTGRES_SERVICE"
    then
        echo -e "$POSTGRES_SERVICE"
    fi
    
    if [ -f /etc/init.d/rhdb ]
    then
	    # Red Hat Enterprise uses the name rhdb.
        echo -e rhdb
    fi
    
    # Most other distributions use the name postgresql.
    echo -e postgresql
}

# Search/replace variables used in config.defs into config files
runConfigpp() {
    
    # If the "config.defs" file exists and the <name>.in file exists for a
    # configuration file, then run the config preprocessor to generate the
    # fully resolved configuration file.
    if [ -f "$ConfigDefs" ]
    then
      for i in $ConfigFiles ; do
        if [ -f "${i}.in" ]
          then
            ${Configpp} --defs "${ConfigDefs}" --in "${i}.in" --out "$i"
          fi
      done
    fi
}

# How to add a database patch:
#
# Add a file containing SQL statements in the sipXproxy/etc/database directory.
# Be sure to add the file to the sql_schemas list in Makefile.am and to the %files
# section in sipxproxy.spec.in
#
# Define an upgrade path - put the file name (without extension .sql) in one or 
# more of the upgrade lists below. If we currently have database version 3 then
# add the file to UpgradePatches1 (upgrading a version 1 database) and UpgradePatches2
# (upgrading a version 2 database).

UpgradePatches1="refer_uri"

# Apply database patches
databasePatch() {
    versionString=`${Psql} -U ${PgUser} -d ${Database} -c "select max(version) from version_history"`
    version=`echo $versionString | cut -d ' ' -f 3`
    case ${version} in
        1)
            UpgradePatches=$UpgradePatches1
            ;;
            
        *)
            UpgradePatches="view_cdrs"
            ;;
    esac
    if [ -f ${DbPatchLog} ]; then
        echo "${Today}" >> ${DbPatchLog}
    else
        echo "${Today}" > ${DbPatchLog}
    fi       
    echo "Patch list: ${UpgradePatches}" >> ${DbPatchLog}
    if [ -n "${UpgradePatches}" ]; then
        for patch in $UpgradePatches; do
            if [ -f ${DbPatchDir}/${patch}.sql ]; then
                # Apply patch only if not found in the patch list
                if ! ${Psql} -U ${PgUser} -d ${Database} -c "select name from patch where name = '${patch}'" | grep ${patch} >>${DbPatchLog} 2>&1; then
                   echo "Applying patch ${DbPatchDir}/${patch}.sql" >> ${DbPatchLog}
                   ${Psql} --quiet -U ${PgUser} -d ${Database} -f ${DbPatchDir}/${patch}.sql >>${DbPatchLog} 2>&1
                   ${Psql} --quiet -U ${PgUser} -d ${Database} -c "insert into patch values ('${patch}')" 
                fi
            else
                echo "Error: Database patch file ${patch}.sql not found."
            fi
        done
   fi
}

# Setup database
databaseCommand() {

    runConfigpp

    databaseCheck Silent
    
    case ${1} in
       create)
         createdb --quiet -U ${PgUser} --encoding=UNICODE ${Database}
         ${Psql} --quiet -U ${PgUser} -d ${Database} -f ${PgSchema}
       ;;
       
       drop)
         dropdb --quiet -U ${PgUser} ${Database}
       ;;
   esac
}

runningUserCheck() {
  CurrentUser=`id -un`
  if [ "$CurrentUser" != "$RunningUser" ]; then
    echo "Only user @sipxpbx.user@ can run this command." 1>&2
    return 1
  fi
  return 0
}

# Check if call resolver is configured for HA
HAcheck() {
   # Quietly check if we're setup for HA - we have to do database tests differently
   resolveConfig=`cat @SIPX_CONFDIR@/callresolver-config.in | grep SIP_CALLRESOLVER_CSE_HOSTS`
   host_list=`expr match "$resolveConfig" '.*CSE_HOSTS\s*:\s*\(.*\)'`
   
   ha_with_localhost=0   

   if [ -z "$host_list" ]; then
      # Normal setup
      return 1
   else
      if expr match "$host_list" '.*localhost.*' >/dev/null; then
         # HA setup with localhost
         ha_with_localhost=1 
      else
         # HA setup without localhost
         ha_with_localhost=0
      fi
      return 0
   fi
}

# Return false if postgres is 
#  1. not running 
#  2. running but not setup to communicate w/java or ${Psql} command
#  3. Database is not created
databaseCheck() {
   if ! ${Psql} -l -U pgsql | grep "${Database}" >/dev/null 2>&1
   then
      procs=`ps -C postmaster`
      if ! expr match "$procs" '.*postmaster.*' >/dev/null; then
         if [ "$1" != "Silent" ]; then
            echo "  failed"
            echo
            echo "  Error: PostgreSQL is not running."
            echo
         fi
      else
         # Check postgres configuration
         Service=postgresql
         if test -z $PGDATA; then
	    PGDATA=/usr/local/pgsql/data
         fi          
         # Check for conf file
         if [ -f $PGDATA/pg_hba.conf ]; then
            if ! grep '^local *all *all *trust.*' $PGDATA/pg_hba.conf >/dev/null; then
               if [ "$1" != "Silent" ]; then            
                  echo
                  echo "  Error: $PGDATA/pg_hba.conf is not set up for local connections."
                  echo "         Run the sipxcallresolver.sh script with the --setup"
                  echo "         parameter:"
                  echo "                     sipxcallresolver.sh --setup"
                  echo
               fi  
            else
               #  Check if psql command works at all
               if ${Psql} -l -U pgsql >/dev/null 2>&1; then
                  if [ "$1" != "Silent" ]; then               
                     echo
                     echo "  Error: The SIPXCDR database does not exist. Run the sipxcallresolver.sh"
                     echo "         script with the --setup parameter:"
                     echo "                     sipxcallresolver.sh --setup"
                     echo                  
                  fi
               else
                  echo 
                  echo "  Unknown database error."
                  echo
               fi
            fi
         fi
      fi
      return 1
   else
      return 0
   fi
}

# Check if there are multiple proxy processes running at the same time.
# This can be a scenario for logging failures.
proxyCheck() {
   ok=0
   echo -n "Checking for running sipproxy..."
   procs=`ps -C sipproxy`
   if expr match "$procs" '.*sipproxy.*' >/dev/null; then
      # At least one sipproxy is running, check for another one
      if expr match "$procs" '.*sipproxy.*sipproxy.*' >/dev/null; then
         echo " failed"
         echo
         echo "  Found at least two sipproxy processes. This is a potential"
         echo "  cause of CSE logging failures!"
         echo
         ps -C sipproxy
         echo
         ok=1
      else
         echo " ok"
      fi
   else
      echo " not running (ok)"   
   fi

   echo -n "Checking for running sipauthproxy..."
   procs=`ps -C sipauthproxy`
   if expr match "$procs" '.*sipauthproxy.*' >/dev/null; then
      # At least one sipauthproxy is running, check for another one
      if expr match "$procs" '.*sipauthproxy.*sipauthproxy.*' >/dev/null; then
         echo "failed"
         echo
         echo "  Found at least two sipauthproxy processes. This is a potential"
         echo "  cause of CSE logging failures! "
         echo
         ps -C sipauthproxy
         echo
         ok=1
      else
         echo " ok"
      fi
   else
      echo " not running (ok)"
   fi
   return $ok
}

configCheck() {
   Status=1
   db_check=1
   
   if ! proxyCheck; then
     Status=0
   fi
 
   if [ $db_check = 1 ]; then
     echo "Checking database..."
     if ! databaseCheck; then
        Status=0
     else
        if databaseVersionCheck; then
           echo "  ok"
        fi
     fi
   else
      echo "Machine is configured for HA without a database on localhost - skip database check"
   fi

   echo "Checking configuration..."   
   proxyConfig=`cat @SIPX_CONFDIR@/proxy-config.in | grep SIP_PROXY_CALL_STATE_DB`
   if ! expr match "$proxyConfig" '.*:\s*[eE][nN][aA][bB][lL][eE]\s*$' >/dev/null; then
      echo
      echo "  Error: proxy is not configured to log call state events to a database."
      echo "         Add the line"
      echo 
      echo "             SIP_PROXY_CALL_STATE_DB : ENABLE"
      echo
      echo "         to @SIPX_CONFDIR@/proxy-config.in"
      echo
      Status=0
   else
      echo "  proxy configured for logging"
   fi
   authConfig=`cat @SIPX_CONFDIR@/authproxy-config.in | grep SIP_AUTHPROXY_CALL_STATE_DB`
   if ! expr match "$authConfig" '.*:\s*[eE][nN][aA][bB][lL][eE]\s*$' >/dev/null; then
      echo
      echo "  Error: authproxy is not configured to log call state events to a database."
      echo "         Add the line"
      echo 
      echo "             SIP_AUTHPROXY_CALL_STATE_DB : ENABLE"
      echo
      echo "         to @SIPX_CONFDIR@/authproxy-config.in"
      echo
      Status=0
   else
      echo "  authproxy configured for logging"
   fi
   
   # Don't check configuration of call resolver for distributed machines
   if [ ${Action} = CONFIGTEST ]; then
      resolveOk=1
      resolveConfig=`cat @SIPX_CONFDIR@/callresolver-config.in | grep SIP_CALLRESOLVER_DAILY_RUN`
      if ! expr match "$resolveConfig" '.*:\s*[eE][nN][aA][bB][lL][eE]\s*$' >/dev/null; then
         echo
         echo "  Warning: call resolver is not configured for daily runs. This"
         echo "           will prevent the call resolver from automatically"
         echo "           resolving calls and purging old database records"
         echo "           on a regular basis. Add the line"
         echo              
         echo "              SIP_CALLRESOLVER_DAILY_RUN : ENABLE"
         echo
         echo "           to @SIPX_CONFDIR@/callresolver-config.in"
         echo 
         resolveOk=0
         Status=0
      fi

      resolveConfig=`cat @SIPX_CONFDIR@/callresolver-config.in | grep SIP_CALLRESOLVER_PURGE`
      if ! expr match "$resolveConfig" '.*:\s*[eE][nN][aA][bB][lL][eE]\s*$' >/dev/null; then
         echo
         echo "  Warning: call resolver is not configured for purging old records."
         echo "           This will prevent the call resolver from automatically"
         echo "           purging old database records on a regular basis. Add"
         echo "           the line"
         echo              
         echo "              SIP_CALLRESOLVER_PURGE  : ENABLE"
         echo
         echo "           to @SIPX_CONFDIR@/callresolver-config.in"
         echo
         resolveOk=0
         Status=0
      fi
      
      # In HA setup test for the CA field entry
      if HAcheck; then
         resolveConfig=`cat @SIPX_CONFDIR@/callresolver-config.in | grep SIP_CALLRESOLVER_CSE_CA`
         if [ -z resolvConfig ]; then
            echo
            echo " Error: In a HA setup the SIP_CALLRESOLVER_CSE_CA parameter must"
            echo "        be set. Add the line"
            echo              
            echo "              SIP_CALLRESOLVER_CSE_CA  : <name of CA file>"
            echo
            echo "           to @SIPX_CONFDIR@/callresolver-config.in"
            resolveOk=0
            Status=0
         else
            cfile=`expr match "$resolveConfig" '.*:\s*\(.*\)\s*$'`
            if [ ! -f @SIPX_CONFDIR@/ssl/authorities/${cfile} ]; then 
               echo
               echo "Error: The value for SIP_CALLRESOLVER_CSE_CA is:"
               echo "              ${cfile}"
               echo
               echo "        A file of that name does not exist in"
               echo "        @SIPX_CONFDIR@/ssl/authorities"
               echo
               resolveOk=0
               Status=0      
            fi
         fi
      fi
   
      if [ $resolveOk = 1 ]; then
         echo "  call resolver configuration ok"
      fi   
   
      echo -n "Checking for @GEM_LIB_DIR@/sipxcallresolver-1.0.0/main.rb..."
      if [ -f @GEM_LIB_DIR@/sipxcallresolver-1.0.0/main.rb ]; then
         echo " ok"
      else
         echo
         echo "  Error: @GEM_LIB_DIR@/sipxcallresolver-1.0.0/main.rb not found."
         echo
         Status=0
      fi   
   fi
}

# Check the database version.  If it is wrong, then exit, because it's dangerous to
# run call resolver on top of the wrong database version.
databaseVersionCheck() {
   dbver=`${Psql} -c "select max(vh.version) from version_history vh;" ${Database} pgsql | sed -n 's/^\s*\([0-9][0-9]*\)\s*$/\1/p'`
   if [ "$dbver" = "" ]
   then
      echo "  Error: could not get the database version."
	   return 1
    fi
    if [ "$dbver" != $DbVersion ]
    then
       if [ "$dbver" == 0 ]
       then
          echo
          echo "  Error: bad ${Database} database version. This database was"
          echo "  created by a prerelease version of sipxcallresolver. You should"
          echo "  drop and recreate the database via"
          echo "       \"sipxcallresolver.sh --database drop create\"."
          echo
       else
          echo 
          echo "  Error: bad ${Database} database version.  Expected version $DbVersion,"
          echo "  got version $dbver. This database was created or modified by a different"
          echo "  version of sipxcallresolver."
          echo
        fi
        return 1
    fi
    return 0
}

# Called after installation or upgrade by distro's package infrastructure
# but can be called manually and is harmless if called multiple times.
onSetup() {
   if ! databaseCheck Silent
   then
       @bindir@/pgpatch.sh
       databaseCommand create
   fi
   databasePatch
   
   # Make a call resolver entry in the crontab file
   if [ -f @SIPX_SYSCONFDIR@/crontab ]; then
      if ! grep sipxcallresolver @SIPX_SYSCONFDIR@/crontab >/dev/null; then 
         echo "05 01 * * * root @bindir@/sipxcallresolver.sh --daily" >> @SIPX_SYSCONFDIR@/crontab
      fi
   else
      echo "05 01 * * * root @bindir@/sipxcallresolver.sh --daily" > @SIPX_SYSCONFDIR@/crontab   
   fi   
}

onUninstall()
{
   # Remove crontab entry for sipxcallresolver if there is one
   if [ -f @SIPX_SYSCONFDIR@/crontab ]; then
      if grep sipxcallresolver @SIPX_SYSCONFDIR@/crontab >/dev/null; then 
         sed -e 's/^.*sipxcallresolver.*$//' @SIPX_SYSCONFDIR@/crontab > @SIPX_SYSCONFDIR@/crontab.tmp
         mv @SIPX_SYSCONFDIR@/crontab.tmp @SIPX_SYSCONFDIR@/crontab
      fi
   fi
}

# Start CDR call resolver
onStartup() { 
    # Check database version - don't run if it's wrong
    if ! databaseVersionCheck; then
       exit 1
    fi
    databasePatch    
    ruby @GEM_LIB_DIR@/sipxcallresolver-1.0.0/main.rb ${resolverArgs}
}

# simple diagnostics
configtest() {
   configCheck

   # Print out a success message if everything is OK, to give the user some feedback.
   # If there is an error then the test will yield an error message.
   if [ $Status = 1 ]
   then
      echo "The config test succeeded."
      echo
   else
      echo "The config test found problems."
      echo
   fi
}

CONFIG_DEFS="@SIPX_CONFDIR@/config.defs"

CONFIG_FILES="\
  @SIPX_CONFDIR@/callresolver-config
  "
# If the "config.defs" file exists and the <name>.in file exists for a
# configuration file, then run the config preprocessor to generate the
# fully resolved configuration file.
if [ -f "$CONFIG_DEFS" ]
then
  for i in $CONFIG_FILES ; do
    if [ -f "${i}.in" ]
    then
       @bindir@/configpp --defs "${CONFIG_DEFS}" --in "${i}.in" --out "$i"
    fi
  done
fi

user=`whoami`
if [ "${user}" != "root" ]; then
   echo "Error: Must be root to run sipxcallresolver.sh script."
   exit 1
fi

while [ $# -ne 0 ]
do
    case ${1} in
        -c|--configtest)
            Action=CONFIGTEST
            ;;
            
        -s|--setup)
            Action=SETUP
            ;;
            
        -u|--uninstall)
            Action=UNINSTALL
            ;;

        -d|--database)
            Action=DATABASE
            shift
            Args="${@}"
            break 2
            ;;    

        --patch)
            Action=PATCH
            ;;
            
        --distrib-configtest)
            Action=DISTRIBTEST
            ;;

        --nop)
            Action=NOP
            ;;

        -h|--help)
            Action=HELP
            ;;
            
        *)
            if [ "${1}" = --start ]; then
              resolverArgs="${resolverArgs} ${1} "
            elif [ "${1}" = --end ]; then
              resolverArgs="${resolverArgs} ${1} "
            elif [ "${1}" = --redo ]; then
              resolverArgs="${resolverArgs} ${1} "
            elif [ "${1}" = --daily ]; then
              resolverArgs="${resolverArgs} ${1} "
            else
              resolverArgs="${resolverArgs} \"${1}\" "
            fi
            ;;
    esac           

    shift # always consume 1
done

if [ ${Action} = CONFIGTEST ]
then
    configtest
    exit $Status
elif [ ${Action} = DISTRIBTEST ]
then
    configtest
    exit $Status
elif [ ${Action} = DATABASE ] 
then
    databaseCommand $Args
elif [ ${Action} = RUN ] 
then
   if [ "${user}" != "root" ]; then
      echo "Error: Must be root to run call resolver"
      exit 1
   fi
   onStartup
elif [ ${Action} = SETUP ]
then
    onSetup
elif [ ${Action} = UNINSTALL ]
then
    onUninstall
elif [ ${Action} = PATCH ]
then
    databasePatch
elif [ ${Action} = HELP ]
then

cat <<USAGE
Usage: sipxcdr.sh [-d|--database commands ...]
                  [-c|--configtest]
                  [-s|--setup]
                  [-h|--help]
                     
Set up CDR database and processing for sipXpbx.

Options include:

  none                 Starts CDR call resolver

  --database commands  Runs an operation on the database. Database commands 
                       are detailed below 

  --configtest         Run diagnostics

  --setup              Initialize postgresql for communicating with sipxconfig
                       and create initial database. Will most likely need 
                       root permissions.
                       
  --uninstall          Uninstall sipxcallresolver changes and settings.

Common Database commands include:

   drop                Drops ${Database} database

   create              Create new ${Database} database

   -p                  Full list all available commands

Notable environment variables:

    POSTGRES_SERVICE   a guess is made to determine the name for the
                       Postgres service.
                       If the guess is incorrect, then set this to the name of
                       the script in /etc/init.d that starts/stops
                       the Postgres database.  The possibilities that
                       we are aware of are "postgresql" and "rhdb".

USAGE

fi


syntax highlighted by Code2HTML, v. 0.9.1