#! /usr/bin/env python3

# Copyright (C) 2015 Inuvika Inc.
# http://www.inuvika.com
# Author David Lechevalier <d.lechevalier@inuvika.com> 2015
#
## xrdp_printer transform a ps file from cups to ps in a specific directory. This code has inspired by cups-pdf.
## Copyright (C) 2007  Julien LANGLOIS <julien@ulteo.com>
## Copyright (C) 2010  David LECHEVALIER <david@ulteo.com>

## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License
## as published by the Free Software Foundation; either version 2
## of the License, or (at your option) any later version.

## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.

## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

from __future__ import print_function

import sys
import re
import os
import pwd
import grp
import syslog
import shutil
import time
from syslog import LOG_DEBUG, LOG_ERR, LOG_INFO, LOG_WARNING

debug_mode=False

if debug_mode:
	buf = open("/tmp/xrdp_printer.out.log","a")
	sys.stderr.close()
	sys.stderr = buf
	sys.stdout.close()
	sys.stdout = buf
	print("#################################################")
	print("##")

CONF = {"ghostscript" : "/usr/bin/gs",
		"spool_dir" : "/var/spool/xrdp_printer/SPOOL",
		"our_spool_file" : False,
		"out_dir" : "/var/spool/xrdp_printer/users/${USER}/${PRINTER}",
		"out_file" : "%(title)s.%(type)s",
		"type"    : "pdf",
		"printer" : "default",
		"ps2pdf_ver" : "2.4",
		"ps2pdf_cmd" : '%(ghostscript)s -q -dCompatibilityLevel=%(ps2pdf_ver)s -dNOPAUSE -dBATCH -dSAFER -sDEVICE=pdfwrite -sOutputFile="%(tmp_file)s" -dAutoRotatePages=/PageByPage -dAutoFilterColorImages=false -dColorImageFilter=/FlateEncode -dPDFSETTINGS=/prepress -c "3000000 setvmthreshold" -f "%(spool_file)s"'
		}

FILEKEYS = {"OutDir" : "out_dir",
			"OutFile" : "out_file",
			"Type" : "type"}

CONFIGFILE = "/etc/cups/xrdp_printer.conf"
PDFTAG = "%%EOF\n"
PDFTAG_OFFSET = len(PDFTAG) * -1

class Transform:
	PROTECT_TAG1 = "mark currentfile eexec"
	PROTECT_TAG2 = "cleartomark"


	def __init__(self, psFile):
		self.psFile = psFile

	def isProtected(self):
		try:
			with open(self.psFile, 'r') as inp:
				for line in inp.xreadlines():
					if self.PROTECT_TAG1 in line:
						return True
		except Exception as e:
			print("Unable to check protection ", repr(e))

		return False


	def unprotect(self):
		cmd = 'sed -i -e "/%s/,/%s/ d" %s'%(self.PROTECT_TAG1, self.PROTECT_TAG2, self.psFile)
		system(cmd)


	def ps2pdf(self, conf):
		cmd = conf["ps2pdf_cmd"]%(conf)
		print(cmd)
		if system(cmd):
			return True

		if self.isProtected():
			print("Document is protected")
			self.unprotect()
			return system(cmd)

		return False

def init():
	syslog.openlog("xrdp_printer")

def end(ret):
	if CONF["our_spool_file"]:
		if os.path.isfile(CONF["spool_file"]):
			os.remove(CONF["spool_file"])
	syslog.closelog()

	return ret

def log(logType, message):
	syslog.syslog(logType, message)

def load_config():
	try:
		f = open(CONFIGFILE, "r")
	except IOError:
		log(LOG_ERR, "Unable to open %s file"%(CONFIGFILE))
		return False

	lines = f.readlines()
	f.close()

	for l in lines:
		buf = l.strip()
		if buf.startswith("#") or not len(buf):
			continue

		(key, value) = buf.split(" ", 1)
		if key not in FILEKEYS:
			log(LOG_WARNING, "Unknown key named %s"%(key))
			continue

		CONF[FILEKEYS[key]] = value
	return True

def getPrettyTitle():
	if not len(CONF["title"]):
		return "Untitlet-Document"

	title = CONF["title"].replace("\\","-").replace(" ","-").replace("(","").replace(")","").replace("/","")
	if not len(title):
		return "Untitlet-Document"

	return title

def getFileFromStdin(filename):
	content = sys.stdin.read()

	t = ""
	titles = re.findall("%%Title: (.*)", content)
	if len(titles) > 0:
		t = titles[0]

	f = open(filename,"w")
	f.write(content)
	f.close()

	return t

def makedirs(directory):
	if os.path.isdir(directory):
		return

	dir1 = directory
	while(not os.path.isdir(dir1)):
		(dir1, dir2) = os.path.split(directory)

	os.chdir(dir1)
	os.makedirs(directory)

def replaceUserGroup():
	CONF["out_dir"] = CONF["out_dir"]%(CONF)
	CONF["out_file"] = CONF["out_file"]%(CONF)

	CONF["out_dir"] = CONF["out_dir"].replace("${USER}", CONF["jobuser"])
	CONF["out_dir"] = CONF["out_dir"].replace("${PRINTER}", CONF["printer"])

	CONF["out_file"] = CONF["out_file"].replace("${USER}", CONF["jobuser"])
	CONF["out_file"] = CONF["out_file"].replace("${EXT}", CONF["type"])
	CONF["out_file"] = CONF["out_file"].replace("${TIME}", str(int(time.time())))
	CONF["out_file"] = CONF["out_file"].replace("${TITLE}", "%(title)s")

def system(cmd):
	ret = os.system(cmd)
	if debug_mode:
		print("result of cmd '%s' => %d"%(cmd, ret))

	return ret==0


def addTag(filename, key, value):
	with open(filename, "ab") as f:
		f.seek(PDFTAG_OFFSET, 2)
		f.write(f"%{key}={value}\n{PDFTAG}".encode())


def main():
	init()

	argc = len(sys.argv)
	if argc==1:
		print('file xrdp_printer cups virtual printer')
		return end(0)

	if not (6 <= len(sys.argv) <= 7):
		print("Usage: %s job-id user title copies options [file]"%(sys.argv[0]))
		return end(0)

	CONF["job"] = sys.argv[1]
	CONF["jobuser"] = sys.argv[2]
	CONF["title"] = sys.argv[3]
	CONF["settings"] = { kv[0].lower(): (kv[1] if len(kv) == 2 else "") for kv in [d.split("=", 1) for d in sys.argv[5].split(" ")] }
	CONF["printer"] = os.getenv("PRINTER")

	load_config()

	if argc == 7:
		CONF["spool_file"] = sys.argv[6]
	else:
		CONF["spool_file"] = "%(spool_dir)s/job-%(job)s.ps"%(CONF)
		CONF["our_spool_file"] = True
		title = getFileFromStdin(CONF["spool_file"])
		if not len(CONF["title"]) and len(title):
			CONF["title"] = title

	CONF["title"] = getPrettyTitle()
	replaceUserGroup()

	CONF["tmp_file"] = "%s.%s"%(CONF["spool_file"], CONF["type"])

	t = Transform(CONF["spool_file"])
	t.ps2pdf(CONF)

	os.chmod(CONF["tmp_file"], 0o777)

	CONF["out_file"] = "%s/%s"%(CONF["out_dir"]%(CONF), CONF["out_file"]%(CONF))

	duplex = CONF["settings"].get("duplex")
	if duplex:
		addTag(CONF["tmp_file"], "duplex", "long" if duplex == "DuplexNoTumble" else "short")

	shutil.move(CONF["tmp_file"], CONF["out_file"])

	return end(0)

if __name__ == "__main__":
	main()
