#!/usr/bin/perl

# X2Go CUPS backend
# Copyright 2009-2015 Obviously Nice
#
#  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
#  Free Software Foundation, Inc.,
#  51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

use Sys::Syslog qw( :standard :macros );
use Sys::Hostname;
use File::Basename;
use File::Copy;
use strict;

openlog($0,'cons,pid','user');

## if the CUPS server is X2Go server at the same time, use ,,local'' here, otherwise
## name the hostname of your master X2Go server within in your X2Go cluster. This
## host then is used for querying session information.
my $x2goserver = "local";

## DSA key for user x2goprint (new path and filename, default in cups-x2go backend)
## this private key has to be valid for all X2Go servers that print via the CUPS
## server that cups-x2go is installed on. The corresponding public key has to
## be installed in <remote-x2goserverX>:~x2goprint/.ssh/authorized_keys
my $printdsa = "/root/.ssh/id_dsa-x2goprint";

# PS2PDF command
my $ps2pdf = "/usr/bin/gs -q -dCompatibilityLevel=1.4 -dNOPAUSE -dBATCH -dSAFER -sDEVICE=pdfwrite -sOutputFile=\"%s.pdf\" -dAutoRotatePages=/PageByPage -dAutoFilterColorImages=false -dColorImageFilter=/FlateEncode -dPDFSETTINGS=/prepress -dDoNumCopies -c .setpdfwrite -f \"%s\"";
#my $ps2pdf = "/usr/bin/gs -q -dCompatibilityLevel=1.4 -dNOPAUSE -dBATCH -dSAFER -sDEVICE=pdfwrite -sOutputFile=\"%s.pdf\" -dAutoRotatePages=/PageByPage -dAutoFilterColorImages=false -dColorImageFilter=/FlateEncode -dPDFSETTINGS=/prepress -dDoNumCopies -c .setpdfwrite -f /usr/bin/margin-offset.ps \"%s\"";

## loglevel for cups-x2go, possible values: emerg, alert, crit, err, warning, notice, info, debug
my $strloglevel = "notice";

# override hardcoded settings via config file
my $cfgfile="/etc/cups/cups-x2go.conf";

my $userName;
my @sessions;
my $this_host=hostname();

sub readconfig
{
	if( -e $cfgfile)
	{
		open(CFG,"<$cfgfile");
		while(!eof(CFG))
			{
				my $ln=<CFG>;
				my $nocomln=(split("#",$ln))[0];
				$nocomln=~s/\n//g;
				my @valarr=split("=",$nocomln);
				my $option=@valarr[0];
				shift(@valarr);
				my $value=join("=",@valarr);
				$option=~s/ //g;
				if($option eq "x2goserver")
				{
					$x2goserver=$value;
					$x2goserver=~s/ //g;
					$x2goserver=~s/\"//g;
				}
				if($option eq "printdsa")
				{
					$printdsa=$value;
				}
				if($option eq "ps2pdf")
				{
					$ps2pdf=$value;
				}
				if($option eq "loglevel")
				{
					$strloglevel=$value;
					$strloglevel=~s/ //g;
				}
			}
		close(CFG);
	}
}


sub setmylogmask {
	my $loglevel = LOG_ERR;
	if    ( $strloglevel eq "emerg" )  { $loglevel = LOG_EMERG; }
	elsif ( $strloglevel eq "alert" )  { $loglevel = LOG_ALERT; }
	elsif ( $strloglevel eq "crit" )   { $loglevel = LOG_CRIT; }
	elsif ( $strloglevel eq "err" )    { $loglevel = LOG_ERR; }
	elsif ( $strloglevel eq "warning" )   { $loglevel = LOG_WARNING; }
	elsif ( $strloglevel eq "notice" ) { $loglevel = LOG_NOTICE; }
	elsif ( $strloglevel eq "info" )   { $loglevel = LOG_INFO; }
	elsif ( $strloglevel eq "debug" )  { $loglevel = LOG_DEBUG; }
	setlogmask( LOG_UPTO( $loglevel ) );
}

sub getsessions
{
	my $sesslist;
	if ( $x2goserver eq "local" )
	{
		syslog("debug", "Querying local X2Go server for a session list...");

		# run x2golistsessions locally
		$sesslist=`su $userName -c "x2golistsessions --all-servers"`;
	}
	else
	{
		syslog("debug", "Querying remote X2Go server $x2goserver for a session list...");
		# Calling x2goprint with a single parameter <username> will result in an
		# x2golistsessions --all-servers command on the remote X2Go server.
		$sesslist=`ssh -i $printdsa x2goprint\@$x2goserver "sudo x2goprint $userName"`;
	}
	syslog("debug", $sesslist);
	@sessions=split("\n",$sesslist);
}


sub printfile
{
	my ($pfile,$tfile,$x2gosession_host, $sess)=@_;
	my $bname=basename($pfile);
	if($x2gosession_host eq $this_host)
	{
		my ($tm,$tm,$uid,$gid,$tm,$tm,$tm,$spooldir)=getpwnam("x2goprint");
		my $spfile="$spooldir/${sess}_$bname";
		copy($pfile, $spfile);
		copy($tfile, "$spfile.title");
		chown $uid,$gid,"$spfile";
		chown $uid,$gid,"$spfile.title";
		# log that we are about to process a print job
		syslog('debug', "x2goprint $userName $sess ${sess}_$bname ${sess}_$bname.title");

		# process print job
		system( "x2goprint $userName $sess ${sess}_$bname ${sess}_$bname.title" );
	}
	else
	{
		# push spool job to remote X2Go server... and launch x2goprint there (with sudo!!!)

		# PDF file
		syslog('debug', "scp -i $printdsa $pfile x2goprint\@$x2gosession_host:~x2goprint/${sess}_$bname");
		system ("scp -i $printdsa $pfile x2goprint\@$x2gosession_host:~x2goprint/${sess}_$bname");
		# title file
		syslog('debug', "scp -i $printdsa $tfile x2goprint\@$x2gosession_host:~x2goprint/${sess}_$bname.title");
		system ("scp -i $printdsa $tfile x2goprint\@$x2gosession_host:~x2goprint/${sess}_$bname.title");
		# run x2goprint on remote X2Go server
		syslog('debug', "ssh -i $printdsa  x2goprint\@$x2gosession_host \"sudo x2goprint $userName $sess ${sess}_$bname ${sess}_$bname.title\"" );
		system( "ssh -i $printdsa  x2goprint\@$x2gosession_host \"sudo x2goprint $userName $sess ${sess}_$bname ${sess}_$bname.title\"" );

	}
}


### main ###

if (!$ARGV[0])
{
	print "file cups-x2go:/ \"Virtual X2Go Printer\" \"CUPS-X2Go\" \"MFG:Generic;MDL:CUPS-X2Go Printer;DES:Generic CUPS-X2Go Printer;CLS:PRINTER;CMD:POSTSCRIPT;\"\n";
	exit 0;
}

# read config file before we go on...
readconfig();
setmylogmask();

if (scalar(@ARGV) < 5 || scalar(@ARGV) > 6)
{
	print STDERR "ERROR: Usage: cups-x2go job-id user title copies options [file]\n";
	exit 1;
}

my $jobID;
my $jobTitle;
my $copies;
my $printOptions;
my $psFile;

($jobID, $userName, $jobTitle, $copies, $printOptions, $psFile) =  @ARGV;
syslog('notice', "Print job received from cups -> $jobID $userName $jobTitle $copies $printOptions $psFile");

my $tempFile;
if (!$psFile)
{
	my $jid = $jobID;
	my $uid = $userName;
	$jid =~ s/\W//g; #sanity check
	$uid =~ s/\W//g; #sanity check
	$tempFile = "/tmp/$jid-$uid-cupsjob$$";
	open (OUT, ">$tempFile") or die "ERROR: Cannot write $tempFile: $!\n";
	syslog('info', "Print job comes from STDIN, writing incoming job to temp file $tempFile\n");
	while(<STDIN>)
	{
		print OUT "$_";
	}
	close OUT;

	$psFile = $tempFile;
}

# converting PS file that we retrieved from CUPS into PDF format
$ps2pdf=~s/%s/$psFile/g;
syslog('info', "Converting printjob with command: $ps2pdf\n");

# the TMPDIR env var is needed for ghostscript...
$ENV{TMPDIR}="/tmp";
system("$ps2pdf");

# after we have created the PDF from CUPS's PS file, we can drop the PS file
unlink ($psFile);

my $pdfFile="$psFile.pdf";
my $titleFile="$pdfFile.title";
open (TITLE,">$titleFile");
print TITLE $jobTitle;
close (TITLE);

getsessions();
syslog('debug', "Retrieved session list: @sessions\n");

for(my $i=0; $i<scalar(@sessions);$i++ )
{
	my @sinfo=split("\\|",@sessions[$i]);
	if(@sinfo[4] eq "R")
	{
		syslog('debug', "Call to printfile function with: $pdfFile $titleFile @sinfo[3] @sinfo[1]\n");
		printfile( $pdfFile, $titleFile, @sinfo[3], @sinfo[1]);
	}
}

unlink ($pdfFile);
unlink ($titleFile);

# closing syslog 
closelog;
