#!/bin/bash
#
# Ver. 0.3.0
#
# 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='/var/lib/dbus'
SYSTEM_NAME='Linux'

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

#*******************************************
#
#*******************************************
function createJobFileDir
{
  if [ ! -d ${jobFileDir} ];
  then
    mkdir ${jobFileDir}
    chmod 700 ${jobFileDir}
    chown ${user} ${jobFileDir}
  fi
}


#*******************************************
#
#*******************************************
function copyInputFile
{
  # Remove PJL commands
  grep --text -v '^@PJL\|%-12345X' $1 > $2
  chown ${user} $2
}


#*******************************************
#
#*******************************************
function getActiveSessionDisplay
{
  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
          break;
        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}
}


#*******************************************
#
#*******************************************
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)
    echo "DEBUG: [Boomaga] dbusDisplay: ${dbusDisplay}" >&2
    if [ "${dbusDisplay}" == "" ];
    then
      echo "ERROR: Can't extract D-Bus display num from '${xDisplay}' for user '$user' (UID: $uid)" >&2
      exit $CUPS_BACKEND_FAILED
    fi
  else
    dbusDisplay='*'
  fi

  if [ ! -f "${DBUS_MACINE_ID_DIR}/machine-id" ];
  then
    echo "ERROR: Dbus machine-id file '${DBUS_MACINE_ID_DIR}/machine-id' not found." >&2
    exit $CUPS_BACKEND_FAILED
  fi

  userDbusDir="${homeDir}/.dbus/session-bus/"
  if [ ! -d "${userDbusDir}" ]; then
    echo "ERROR: User Dbus session directory '${userDbusDir}' not found." >&2
    exit $CUPS_BACKEND_FAILED
  fi
  echo "DEBUG: [Boomaga] User Dbus session directory '${userDbusDir}." >&2

  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
   echo "ERROR: Dbus session file '${dbusSessionFile}' not found." >&2
   exit $CUPS_BACKEND_FAILED
 fi
  echo "DEBUG: [Boomaga] dbusSessionFile: ${dbusSessionFile}" >&2

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


#*******************************************
#
#*******************************************
function getDbusAddr_Linux_Proc
{

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


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

    if [ -n "${addr}" ];
    then
      if [ "${disp}" = "${xDisplay}" ] || [ "${xDisplay}" = "" ];
      then
        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
}


###########################################################
# Output "device discovery" information on stdout:
# http://www.cups.org/documentation.php/doc-1.6/man-backend.html
# device-class device-uri "device-make-and-model" "device-info" "device-id"
if test "$#" = "0";
then
  echo "file boomaga:/ \"Boomaga printer\" \"Boomaga\" \"MFG:Generic;CMD:PJL,PDF;MDL:Boomaga printer;CLS:PRINTER;DES:Virtual boomaga printer;DRV:DPDF,R1,M0;\""
  exit 0
fi

jobID=$1
user=$2
title=$3
count=$4
options=$5
inputFile=$6

if [ -z "${inputFile}" ]; then
  inputFile='-'
fi

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

if [ "${uid}" == "" ];
then
  echo "ERROR: Can't found UID for user '${user}'" >&2
  exit $CUPS_BACKEND_FAILED
fi

if [ "${homeDir}" == "" ];
then
  echo "ERROR: Can't found home directory for user '$user' (UID: $uid)" >&2
  exit $CUPS_BACKEND_FAILED
fi

echo "DEBUG: [Boomaga] User: $user" >&2
echo "DEBUG: [Boomaga] Uid:  $uid" >&2

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


createJobFileDir
copyInputFile "${inputFile}" "${jobFile}"
getActiveSessionDisplay


if [ "${xDisplay}" = "" ];
then
  echo "INFO: Can't found active session for user '$user' (UID: $uid)." >&2
fi
echo "DEBUG: [Boomaga] xDisplay: ${xDisplay}" >&2

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

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

if [ "${dbusSessionAddress}" == "" ];
then
  echo "ERROR: Can't extract D-Bus bus address from /proc files for user '$user' (UID: $uid)" >&2
  exit $CUPS_BACKEND_FAILED
fi


echo "DEBUG: [Boomaga] dbusSessionAddress: ${dbusSessionAddress}" >&2

cmd="dbus-send --session --type=method_call --print-reply \
  --dest=org.boomaga /boomaga \
  org.boomaga.add \
  string:'${jobFile}' \
  string:'${title}' \
  boolean:true"

echo "DEBUG: [Boomaga] command: ${cmd}" >&2

errorLog="/tmp/boomaga_${jobID}.err"
res=${CUPS_BACKEND_OK}
su -c "DBUS_SESSION_BUS_ADDRESS=${dbusSessionAddress} ${cmd}" ${user} 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
