#!/bin/bash
#
# Ver. @FULL_VERSION@
#
# Boomaga provides a virtual printer for CUPS.
# This can be used for print preview or for print booklets.
#


CUPS_BACKEND_OK=0
CUPS_BACKEND_FAILED=1

# Have debug info in /var/log/cups/error_log:
#set -x

DBUS_MACINE_ID_DIR='@DBUS_MACINE_ID_DIR@'
SYSTEM_NAME='@CMAKE_SYSTEM_NAME@'

PREF_ENV_PROGS="kdeinit4 firefox chromium-browser razor-session gnome-session lxsession Xfce4-session"


#*******************************************
#
#*******************************************
function debug
{
    echo "DEBUG: [Boomaga] $1" >&2
}


#*******************************************
#
#*******************************************
function info
{
    echo "INFO: [Boomaga] $1" >&2
}


#*******************************************
#
#*******************************************
function error
{
    echo "ERROR: [Boomaga] $1" >&2
    exit $CUPS_BACKEND_FAILED
}


#*******************************************
#
#*******************************************
function createJobFileDir
{
  if [ -d "${jobFileDir}" ];
  then
    return
  fi

  if [ -e "${jobFileDir}" ];
  then
    error "File '${jobFileDir}' exists, and int isn't directory.";
  fi

  if [ ! -"d ${jobFileDir}" ];
  then
    mkdir "${jobFileDir}"
  fi
}


#*******************************************
#
#*******************************************
function copyInputFile
{
  cat - > "$1"

  read line<$1

  case $line in
    %!PS-Adobe*)
      mv "$1" "$1.ps"
      ps2pdf "$1.ps" "$1"
      rm "$1.ps"
      ;;
  esac
}


#*******************************************
#
#*******************************************
function getActiveSessionDisplay_consolekit
{
  which ck-list-sessions 2>/dev/null >/dev/null || return 2

  oldIfs=$IFS
  IFS=$(echo -en "\n")
  while read line; do
    IFS="$oldIfs='"
    read key value <<< $line;

    case $key in
      Session*)
        if [ "$sesUid" = "$uid" -a "$sesActive" = "TRUE" -a "$sesDisplay" != "" ];
        then
          xDisplay=$sesDisplay
          IFS=${oldIfs}
          return 0
        fi

        unset sesUid
        unset sesActive
        unset sesADisplay
        ;;

      unix-user)
        sesUid=$value
        ;;

      active)
        sesActive=$value
        ;;

      x11-display)
        sesDisplay=$value
        ;;
    esac
  done  <<< $(ck-list-sessions; echo "SessionEnd:");

  IFS=${oldIfs}
  return 1
}


#*******************************************
#
#*******************************************
function getActiveSessionDisplay_systemd
{
  which loginctl 2>/dev/null >/dev/null || return 2

  local sessions=$(loginctl show-user -p Sessions "${USER}" | cut -d'=' -f2)

  for s in ${sessions}; do
    if [ $(loginctl show-session -pActive "${s}") = "Active=yes" ];
    then
      xDisplay=$(loginctl show-session -pDisplay "${s}" | cut -d'=' -f2)

      if [ "${xDisplay}" != "" ];
      then
        return 0
      fi
    fi
  done

  return 1
}


#*******************************************
#
#*******************************************
function getDbusAddr_SessionFile
{

  if [ "${xDisplay}" != "" ];
  then
    # the X display without the screen number, with the following prefixes removed,
    # if present: ":", "localhost:" ."localhost.localdomain:". That is, a display
    # of "localhost:10.0" produces just the number "10"
    dbusDisplay=$(echo ${xDisplay} | cut -d ':' -f 2 | cut -d '.' -f 1)
    debug "dbusDisplay: ${dbusDisplay}"
    if [ "${dbusDisplay}" == "" ];
    then
      error "Can't extract D-Bus display num from '${xDisplay}' for user '$USER' (UID: $uid)"
    fi
  else
    dbusDisplay='*'
  fi

  if [ ! -f "${DBUS_MACINE_ID_DIR}/machine-id" ];
  then
    error "Dbus machine-id file '${DBUS_MACINE_ID_DIR}/machine-id' not found."
  fi

  userDbusDir="${homeDir}/.dbus/session-bus/"
  if [ ! -d "${userDbusDir}" ]; then
    error "User Dbus session directory '${userDbusDir}' not found."
  fi
  debug "User Dbus session directory '${userDbusDir}'."

  dbusSessionFile=$(ls ${userDbusDir}$(cat "${DBUS_MACINE_ID_DIR}/machine-id" 2>/dev/null)-${dbusDisplay} 2>/dev/null | head -n 1 )
  if [ -z "${dbusSessionFile}" ] || [ ! -f ${dbusSessionFile} ];
  then
   error "Dbus session file '${dbusSessionFile}' not found."
 fi
  debug "dbusSessionFile: ${dbusSessionFile}"

  dbusSessionAddress=$(grep DBUS_SESSION_BUS_ADDRESS= ${dbusSessionFile} | cut -d "=" -f 2-)
  if [ "${dbusSessionAddress}" == "" ];
  then
    error "Can't extract D-Bus bus address from '${dbusSessionFile}' for user '$USER' (UID: $uid)"
  fi
}


#*******************************************
#
#*******************************************
function getDbusAddr_Linux_Proc
{
  prefFiles=""
  for proc in ${PREF_ENV_PROGS}; do
    pid=$(pidof ${proc})
    [ -n "$pid" ] && prefFiles="${prefFiles}/proc/$pid "
  done

  debug "Scan proc files:"
  for dir in ${prefFiles} $(find /proc -maxdepth 1 -user "${USER}" -type d -regex '/proc/[0-9]+' | sort -V -r); do
    file=${dir}/environ
    disp=$(grep -z DISPLAY "${file}"  | cut -d= -f2)
    addr=$(grep -z DBUS_SESSION_BUS_ADDRESS "${file}"  | cut -d= -f2-)

    debug "  * ${file}     disp='${disp}' addr='${addr}'"
    if [ -n "${addr}" ];
    then
      if [ "${disp}" = "${xDisplay}" ]   || \
         [ "${disp}.0" = "${xDisplay}" ] || \
         [ "${disp}" = "${xDisplay}.0" ] || \
         [ "${xDisplay}" = "" ];
      then
        debug "*** USE ${file} disp='${disp}' addr='${addr}'"
        dbusSessionAddress=${addr}
        BOOMAGA_ENV_FILE=${homeDir}/.cache/boomaga.env
        echo '' > ${BOOMAGA_ENV_FILE}
        chmod 600 ${BOOMAGA_ENV_FILE}
        chown ${USER} ${BOOMAGA_ENV_FILE}

        echo "BOOMAGA_PROC_FILE=${file}" >> ${BOOMAGA_ENV_FILE}

        grep -z KDE_FULL_SESSION "${file}" >> ${BOOMAGA_ENV_FILE}
        echo '' >> ${BOOMAGA_ENV_FILE}
        grep -z QT_PLUGIN_PATH "${file}" >> ${BOOMAGA_ENV_FILE}
        echo '' >> ${BOOMAGA_ENV_FILE}
        grep -z GTK_RC_FILES   "${file}" >> ${BOOMAGA_ENV_FILE}
        echo '' >> ${BOOMAGA_ENV_FILE}
        grep -z GTK2_RC_FILES  "${file}" >> ${BOOMAGA_ENV_FILE}
        echo '' >> ${BOOMAGA_ENV_FILE}
        break
      fi
    fi
  done
}

jobID=$1
title=$2
count=$3
options=$4

info "jobId: ${jobID}"
info "title: ${title}"
info "count: ${count}"
info "options: ${options}"

uid=$(getent passwd ${USER} | cut -d':' -f 3)
homeDir=$(getent passwd ${USER} | cut -d':' -f 6)

if [ "${uid}" == "" ];
then
  error "Can't found UID for user '${USER}'"
fi

if [ "${homeDir}" == "" ];
then
  error "Can't found home directory for user '$USER' (UID: $uid)"
fi

debug "User: $USER"
debug "Uid:  $uid"
debug "Home: $homeDir"

jobFileDir=${homeDir}/.cache
jobFile=${jobFileDir}/boomaga_in_file-${jobID}.pdf
export TMPDIR=$jobFileDir

createJobFileDir
copyInputFile "${jobFile}"

getActiveSessionDisplay_systemd || \
getActiveSessionDisplay_consolekit


if [ "${xDisplay}" = "" ];
then
  info "Can't found active session for user '$USER' (UID: $uid)."
fi
debug "xDisplay: ${xDisplay}"

if [ "$SYSTEM_NAME" == 'Linux' ]; then
  getDbusAddr_Linux_Proc
fi;

if [ "$SYSTEM_NAME" == 'FreeBSD' ]; then
  getDbusAddr_SessionFile
fi

if [ "${dbusSessionAddress}" == "" ];
then
  error "Can't extract D-Bus bus address files for user '$USER' (UID: $uid)"
fi


debug "dbusSessionAddress: ${dbusSessionAddress}"


errorLog=$(mktemp /tmp/boomaga.err.XXXXX)

res=${CUPS_BACKEND_OK}
export DBUS_SESSION_BUS_ADDRESS=${dbusSessionAddress}
dbus-send --session --type=method_call --print-reply\
   --dest=org.boomaga /boomaga \
   org.boomaga.add \
   string:"${jobFile}" \
   string:"${title}" \
   boolean:true \
   string:"${options}" \
   uint32:${count} \
   2>${errorLog} 1>/dev/null \
   || res=${CUPS_BACKEND_FAILED}

if [ "$res" !=  $CUPS_BACKEND_OK ];
then
  cat ${errorLog} | sed -e"s/^/ERROR: /" 1>&2
fi

rm ${errorLog}
exit $res
