
Il reste un bug de notification pour le club Crans: la liste des imprimeurs de ce club semble vide. En attendant, le cron va envoyer des mails si ça arrive.
203 lines
6.7 KiB
Python
Executable file
203 lines
6.7 KiB
Python
Executable file
#!/usr/bin/python
|
|
# -*- encoding: utf-8 -*-
|
|
|
|
import requests #pip install requests
|
|
# See:
|
|
# http://docs.python-requests.org/en/latest/user/quickstart/#post-a-multipart-encoded-file
|
|
import os, os.path, sys
|
|
import time
|
|
import argparse
|
|
import types
|
|
import tempfile, atexit
|
|
import subprocess
|
|
from syslog import syslog, openlog
|
|
|
|
|
|
BASE_URL = "http://imprimante.adm.crans.org"
|
|
URIs = {
|
|
'root': '/',
|
|
'ended_jobs_csv': '/pprint.csv?Flag=Csv_Data&LogType=0&Dummy=%(timestamp)s',
|
|
'current_jobs': '/jpl.cgi?Flag=Init_Data&CorePGTAG=6&Dummy=%(timestamp)s',
|
|
'print': '/ppdf.cgi?Type=PDF&Dummy=%(timestamp)s',
|
|
'do_print': '/pprint.cgi',
|
|
}
|
|
|
|
STAPLE_POSITIONS={"TopLeft":"5", "TopRight":"6", "BottomLeft":"7",
|
|
"BottomRight":"8", "Top":"1", "Bottom":"2", "Left":"3",
|
|
"Right":"4", "None":"0", "Book":"9",}
|
|
|
|
OPTIONS = {
|
|
"Url": "http://",
|
|
"Mode": 100,
|
|
"ManualNo": 0,
|
|
"DocPasswd": "",
|
|
"WebUserName": '',
|
|
"WebPasswd": '',
|
|
"PageMode": {'all': 0, 'range': 1, 'default': 0},
|
|
"StartPage": 1,
|
|
"EndPage": 1,
|
|
"Copies": lambda args: args.copies,
|
|
"MediaSize": lambda args: {
|
|
'auto': 0, 'default': 0,
|
|
"a4": 5, "a3": 6, "a5": 16, "b4": 12, "b5": 13,
|
|
"ltr": 1, "lgl": 2, "11x17": 3, "exec": 4, "com-10": 7,
|
|
"monarch": 8, "c5 env": 9, "b5 env": 10, "dl env": 11,
|
|
}.get(args.page_size.lower()),
|
|
"MediaType": 0, # TODO
|
|
"ManualFeed": 0,
|
|
"FitSize": lambda args: {'no': 0, 'yes': 1, 'default': 1}.get(args.expand),
|
|
#expand to mediasize
|
|
"DuplexType": lambda args:
|
|
{'book': 0, 'one-sided': 0, 'short-edge': 1,
|
|
'long-edge': 2}.get(args.duplex_type),
|
|
# NB: book => one-sided (sinon, ça peut merder)
|
|
"Sort": {'none': 0, 'finition': 1, 'default': 1},
|
|
#finition: pour tout ce qui a une finition
|
|
# TODO
|
|
"PunchPos": 0,
|
|
"StapleType": lambda args: STAPLE_POSITIONS['Book'] if args.duplex_type == 'book'
|
|
else STAPLE_POSITIONS[args.staple_position],
|
|
"BookType": lambda args: 0 if args.duplex_type == 'book' else 2,
|
|
"Annotation": 2,
|
|
"ColorMode": lambda args: {'yes': 2, 'no': 1}.get(args.colors),
|
|
"C_Render": 0, "C_RGB_Pro": 1, "C_CMYK_Pro": 4, "C_OUT_Pro": 1,
|
|
"C_GRAY_Pro": 1, "C_Matching": 0,
|
|
"SPOT_Color": 1,
|
|
"C_Pure_B": 1, "C_B_OVPrn": 1, "C_Bright": 100, "C_Gray_Com": 1,
|
|
"C_OVR_EFF": 1,
|
|
"WidePrn": 0,
|
|
"NupPrint": 0, "NupStart": 0,
|
|
"Resolution": 1,
|
|
"HalfToneTxt": 1, "HalfToneGrp": 1, "HalfToneImg": 1,
|
|
"AstIntensity": 2, "AstText": 0, "AstGrap": 1, "AstImag": 1,
|
|
"StoreBox": lambda args: int(args.test),
|
|
"BoxNo": 17,
|
|
"RGBDLName": "",
|
|
"CMYKDLName": "",
|
|
"OUTDLName": "",
|
|
"BOXName": lambda args: args.jobname + '_%d' % int(time.time()),
|
|
"Flag": "Exec_Data_Pdf",
|
|
"Dummy": lambda _: int(time.time()),
|
|
"Direct": 100,
|
|
}
|
|
|
|
def build_options(args):
|
|
opt = {}
|
|
for (k,v) in OPTIONS.iteritems():
|
|
if isinstance(v, types.FunctionType):
|
|
v = v(args)
|
|
if isinstance(v, dict):
|
|
v = v['default']
|
|
if not isinstance(v, file):
|
|
v = str(v)
|
|
opt[k] = v
|
|
return opt
|
|
|
|
|
|
def build_url(name):
|
|
""" Build url from a page name (see URIs) """
|
|
return (BASE_URL + URIs[name]) % {
|
|
'timestamp': int(time.time()),
|
|
}
|
|
|
|
|
|
def range_checker(a, b):
|
|
def cast(x):
|
|
try:
|
|
v = int(x)
|
|
except ValueError(err):
|
|
raise argparse.ArgumentTypeError(str(err))
|
|
if v not in xrange(a, b):
|
|
raise argparse.ArgumentTypeError("should be between %d and %d" % (a, b))
|
|
return v
|
|
return cast
|
|
|
|
def build_parser():
|
|
parser = argparse.ArgumentParser(
|
|
description="HTTP printing driver for irc3580, with compatibility mode.",
|
|
epilog="logs are sent to syslog (eg /var/log/canon_wrapper.log)",
|
|
prog='canon_wrapper',
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
)
|
|
parser.add_argument('--jobname', help="job name as seen by the printer",
|
|
default="unamed job",
|
|
)
|
|
parser.add_argument('--copies', default=1,
|
|
help="number of copies",
|
|
type=range_checker(1,1000),
|
|
)
|
|
parser.add_argument('--colors', type=str, default='yes', const="yes",
|
|
nargs="?",
|
|
choices=["yes", "no"],
|
|
)
|
|
parser.add_argument('--expand', type=str, default='yes', const="yes",
|
|
nargs="?",
|
|
choices=["yes", "no"],
|
|
help="expand to page size",
|
|
)
|
|
parser.add_argument('--duplex-type', type=str, default='one-sided',
|
|
choices=["one-sided", "short-edge", "long-edge",
|
|
"book"],
|
|
)
|
|
parser.add_argument('--page-size', type=str, default='A4',
|
|
choices=["A3", "A4"],
|
|
help="page size",
|
|
)
|
|
parser.add_argument('--test', default=False, const=True,
|
|
action='store_const',
|
|
help="Don't really print, send to box folder",
|
|
)
|
|
parser.add_argument('--staple-position', default='None',
|
|
choices=STAPLE_POSITIONS.keys(),
|
|
help="Where to staple",
|
|
)
|
|
parser.add_argument('filename')
|
|
return parser
|
|
|
|
def do_print(args):
|
|
opt=build_options(args)
|
|
syslog('Options: %s' % repr(opt))
|
|
#syslog('Starting ghostscript compat, piped mode')
|
|
|
|
temppdf = tempfile.NamedTemporaryFile(suffix='.pdf')
|
|
syslog('Starting ghostscript compat to %s' % temppdf.name)
|
|
atexit.register(temppdf.close)
|
|
proc = subprocess.Popen(['/usr/bin/gs','-dCompatibilityLevel=1.2',
|
|
'-dBATCH','-dNOPAUSE','-sDEVICE=pdfwrite',
|
|
'-sOutputFile=' + temppdf.name,
|
|
args.filename])
|
|
# '-sOutputFile=%stdout%', '-q',
|
|
# args.filename], stdout=subprocess.PIPE)
|
|
ret = proc.wait()
|
|
syslog('ghostscript compat finished with ret=%d' % ret)
|
|
if ret != 0:
|
|
syslog('aborting.')
|
|
return ret
|
|
syslog('Getting cookie...')
|
|
cook = requests.get(build_url('root')).cookies
|
|
syslog('Sending pdf (%d bytes)...' % os.stat(temppdf.name).st_size)
|
|
temppdf.seek(0)
|
|
filename = args.jobname
|
|
if not filename.endswith('.pdf'):
|
|
filename += '.pdf'
|
|
req = requests.post(build_url('do_print'), cookies=cook, data=opt,
|
|
files={'File': (filename, temppdf)})
|
|
#files={'File': (args.jobname + '.pdf', proc.stdout)})
|
|
temppdf.close()
|
|
if "ms_err.gif" in req.text:
|
|
syslog("Printer side ERROR !")
|
|
return 42
|
|
syslog('Compatibilized pdf successfully sent. Continue tracking on the printer !')
|
|
return 0
|
|
|
|
if __name__ == '__main__':
|
|
parser = build_parser()
|
|
args = parser.parse_args()
|
|
if args:
|
|
try:
|
|
openlog('canon_wrapper[%s]' % args.jobname)
|
|
sys.exit(do_print(args))
|
|
except Exception as e:
|
|
syslog('Caught exception %s' % repr(e))
|
|
raise
|
|
|