Nettoyage d'hiver

This commit is contained in:
Pierre-Elliott Bécue 2015-11-23 23:54:23 +01:00
parent 4279b3db23
commit bbcd49c88c
10 changed files with 0 additions and 21 deletions

View file

@ -1,219 +0,0 @@
#!/usr/bin/python
# -*- encoding: utf-8 -*-
#canon_wrapper.py
"""
.. codeauthor:: Daniel STAN <dstan@crans.org>
.. codeauthor:: Antoine Durand-Gasselin <adg@crans.org>
Pour envoyer des jobs d'impression à l'imprimante canon via son interface web.
License: GPLv3
"""
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):
"""Type function for a given range"""
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():
"""Make argparse object"""
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):
"""Effectively compatibilize then print the file"""
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
else:
parser = build_parser()
__doc__ += '''\nHelp message : ::\n\n'''
__doc__ += '\n'.join(' ' + l for l in parser.format_help().split('\n')) + "\n"

View file

@ -1,189 +0,0 @@
#!/bin/bash /usr/scripts/python.sh
# -*- coding: utf-8 -*-
# #############################################################
# ..
# .... ............ ........
# . ....... . .... ..
# . ... .. .. .. .. ..... . ..
# .. .. ....@@@. .. . ........ .
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
# ...@@@.... @@@ .@@.......... ........ ..... ..
# . ..@@@@.. . .@@@@. .. ....... . .............
# . .. .... .. .. . ... ....
# . . .... ............. .. ...
# .. .. ... ........ ... ...
# ................................
#
# #############################################################
"""
cout.py
Fonctions pour calculer le prix d'une impression
(ne calcul que le prix de l'encre.
retourne le prix pour une copie en A4)
Copyright (c) 2006 by www.crans.org
"""
# Début : Ajout log pour réestimer les coûts
import time
# Fin
import sys
import tempfile
import os
import commands
import shutil
import syslog
import stat
if '/usr/scripts' not in sys.path:
sys.path.append('/usr/scripts')
from cranslib.deprecated import module as deprecated_module
deprecated_module()
from cranslib.utils import QuoteForPOSIX as escapeForShell
def __init__():
pass
# ########################################################### #
# CONSTANTES #
# ########################################################### #
#
#
from gestion import config
import gestion.config.impression
COUT_UNITE_COULEUR = config.impression.c_coul
COUT_UNITE_NOIRE = config.impression.c_noir
COUT_PASSAGE_TAMBOUR_NOIR = config.impression.c_tambour_noir
COUT_PASSAGE_TAMBOUR_COULEUR = config.impression.c_tambour_coul
# Début : Ajout log pour réestimer les coûts
FICHIER_LOG="/var/log/log_couts/estimations"
# Fin
# ########################################################### #
# ERREURS #
# ########################################################### #
#
#
class FichierInvalide(Exception):
"""
Si le fichier est invalide
"""
def __str__(self):
return self.args[0]
def file(self):
try:
return self.args[1]
except:
return "n/a"
def try_command(cmd, tmp_rep, error_msg):
u""" Execute a command, log output and raise exception if it fails. """
(status, rep) = commands.getstatusoutput(cmd)
if status:
syslog.openlog('impression')
syslog.syslog(syslog.LOG_ERR, 'command failed (%d): %s' % (status, cmd))
for l in rep.split('\n'):
syslog.syslog(syslog.LOG_ERR, 'output: %s' % l)
syslog.closelog()
shutil.rmtree(tmp_rep)
raise ValueError, error_msg % status
# ########################################################### #
# PRIX #
# ########################################################### #
def base_prix(path_pdf_file, color=False):
u""" Calcul le prix d'une impression couleur ou noir et blanc sur papier A4 """
# nom_rep seras le dossier dans tmp ou tous les fichier créé par
# convert seront entreposé
nom_rep = tempfile.mkdtemp(prefix='tmpimpr')
nom_png = "%s/convert.png" % nom_rep # Nom prefixe et chemin des png créé par convert
escaped_path_pdf_file = escapeForShell(path_pdf_file)
escaped_path_ps_file = escapeForShell(path_pdf_file + ".ps")
error_msg = "ERREUR %%d : Fichier invalide. Aucun %s cree."
if color:
error_msg += " (couleurs)"
gs_device = "png16m"
nb_composante = 4 # Cyan, Magenta, Jaune, Noir
percent_program = "percentcolour"
else:
gs_device = "pnggray"
nb_composante = 1 # Noir
percent_program = "percentblack"
if not os.access(path_pdf_file + ".ps",os.F_OK) or \
os.stat(path_pdf_file)[stat.ST_MTIME] > os.stat(path_pdf_file + ".ps")[stat.ST_MTIME]:
# Convertit les pdf en ps
try_command("nice -n 5 pdftops %s %s" % (escaped_path_pdf_file,
escaped_path_ps_file),
nom_rep,
error_msg % "ps")
# Convertit les ps en png (il est néscessaire de passer par un ps
# car ghostscript refuse certain pdf)
try_command("nice -n 5 gs -sDEVICE=%s -r30 -dBATCH -dNOPAUSE -dSAFER -dPARANOIDSAFER -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dMaxBitmap=50000000 -sOutputFile=%s%%d -q %s" %
(gs_device, nom_png, escaped_path_ps_file),
nom_rep,
error_msg % "png")
# Récupère la liste des fichiers
list_filepng=os.listdir(nom_rep)
# Calcule le nombre de pixel
remplissage = [0] * (nb_composante + 1) # couleurs (N ou CMJN), nombre de pages
for fichier in list_filepng:
resultats = commands.getoutput("nice -n 5 /usr/scripts/impression/%s %s/%s" % (percent_program, nom_rep, fichier))
l_resultats = resultats.split(":")
for i in range(nb_composante):
remplissage[i] += float(l_resultats[i])*float(l_resultats[nb_composante])
remplissage[nb_composante] += float(l_resultats[nb_composante])
# suppression des fichiers temporaires
shutil.rmtree(nom_rep)
total_noir = remplissage[nb_composante-1]
total_couleur = sum(remplissage[0:nb_composante-1])
faces = int(remplissage[nb_composante])
if total_couleur > 0:
c_total = ((COUT_PASSAGE_TAMBOUR_COULEUR + COUT_PASSAGE_TAMBOUR_NOIR) * faces # passage dans les toners
+ COUT_UNITE_NOIRE * total_noir # cout encre noire
+ COUT_UNITE_COULEUR * total_couleur) # cout encre couleur
else: # Pas de couleur, malgre l'indication
c_total = (COUT_PASSAGE_TAMBOUR_NOIR * faces # passage dans les toners
+ COUT_UNITE_NOIRE * total_noir) # cout encre noire
# Début : Ajout log pour réestimer les coûts
fichier_log_est=open(FICHIER_LOG,"a")
fichier_log_est.write("%d %d %3d %10.3f %10.3f %s\n" % (time.time(), color, faces, total_noir, total_couleur, path_pdf_file) )
fichier_log_est.close()
# Fin
return (float(c_total)/100, faces)
# ########################################################### #
# PRIX COULEURS #
# ########################################################### #
#
# Clacul le prix d'une impression couleur
#
def base_prix_couleurs(path_pdf_file):
"""
Clacul le prix d'une impression couleur sur papier A4 pour le fichier path_pdf_file
"""
return base_prix(path_pdf_file, color=True)
# ########################################################### #
# PRIX N&B #
# ########################################################### #
#
# calcul le prix d'une impression en noir et blanc
#
def base_prix_nb(path_pdf_file):
"""
Clacul le prix d'une impression noire et blanc sur papier A4 pour le fichier path_pdf_file
"""
return base_prix(path_pdf_file, color=False)

View file

@ -1,530 +0,0 @@
# -*- coding: utf-8 -*-
# #############################################################
# ..
# .... ............ ........
# . ....... . .... ..
# . ... .. .. .. .. ..... . ..
# .. .. ....@@@. .. . ........ .
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
# ...@@@.... @@@ .@@.......... ........ ..... ..
# . ..@@@@.. . .@@@@. .. ....... . .............
# . .. .... .. .. . ... ....
# . . .... ............. .. ...
# .. .. ... ........ ... ...
# ................................
#
# #############################################################
# impression_canon.py
#
# Classe impression pour l'imprimante canon iR C3580i
#
# Copyright (c) 2006, 2007, 2008, 2009 by Cr@ns (http://www.crans.org)
# #############################################################
"""
Classe pour gérer l'envoie de pdf à l'imprimante.
Calcule le coût des options d'impression.
"""
__version__ = '9.11'
import sys, os.path
from gestion.config import impression as config_impression
from commands import getstatusoutput
if '/usr/scripts' not in sys.path:
sys.path.append('/usr/scripts')
from cranslib.utils import logs
from subprocess import Popen, PIPE
from base import FichierInvalide, SoldeInsuffisant, PrintError, SettingsError
# ######################################################## #
# CONSTANTES #
# ######################################################## #
FICHIER_LOG = "/var/log/log_couts/impressions"
SNMP_CAPA_B = "mib-2.43.11.1.1.8.1.1"
SNMP_CAPA_C = "mib-2.43.11.1.1.8.1.2"
SNMP_CAPA_M = "mib-2.43.11.1.1.8.1.3"
SNMP_CAPA_Y = "mib-2.43.11.1.1.8.1.4"
SNMP_TON_B = "mib-2.43.11.1.1.9.1.1"
SNMP_TON_C = "mib-2.43.11.1.1.9.1.2"
SNMP_TON_M = "mib-2.43.11.1.1.9.1.3"
SNMP_TON_Y = "mib-2.43.11.1.1.9.1.4"
SNMP_BAC1 = "mib-2.43.8.2.1.10.1.2"
SNMP_BAC2 = "mib-2.43.8.2.1.10.1.3"
SNMP_BAC3 = "mib-2.43.8.2.1.10.1.4"
SNMP_BAC4 = "mib-2.43.8.2.1.10.1.5"
SNMP_COUNT_A4 = "enterprises.1602.1.11.1.4.1.4.113"
SNMP_COUNT_A3 = "enterprises.1602.1.11.1.4.1.4.112"
SNMP_COUNT_A4c = "enterprises.1602.1.11.1.4.1.4.123"
SNMP_COUNT_A3c = "enterprises.1602.1.11.1.4.1.4.122"
SNMP_COUNT_TOT = "enterprises.1602.1.11.1.4.1.4.101"
SNMP_ETAT = "hrPrinterStatus.1"
SNMP_ERR = "hrPrinterDetectedErrorState.1"
DECOUVERT_AUTHORISE = config_impression.decouvert
DICT_AGRAFAGE = { "None" : "aucune agrafe",
"TopLeft" : u"agrafe en haut à gauche",
"TopRight" : u"agrafe en haut à droite",
"BottomLeft" : u"agrafe en bas à gauche",
"BottomRight" : u"agrafe en bas à droite",
"Left": u"deux agrafes sur le bord gauche",
"Right" : u"deux agrafes sur le bord droit",
"Top" : u"deux agrafes sur le bord supérieur",
"Bottom" : u"deux agrafes sur le bord inférieur",
}
#AVAIL_AGRAFES = ["None", "TopLeft", "TopRight", "Left", "BottomLeft", "BottomRight", "Right"]
#les agrafes sur les côtés (*2) sont désactivées, car elles nécessitent des
#feuilles en A4. On alimente désormais l'imprimante exclusivement en A4R
#(plus faible probabilité de bourrer)
AVAIL_AGRAFES = ["None", "TopLeft", "TopRight", "BottomLeft", "BottomRight"]
DICT_PAPIER = { 'A4' : "Papier A4 ordinaire",
'A3' : "Papier A3 ordinaire",
#'A4tr' : "Transparent A4",
}
def _uniq_jid():
""" Alloue un jid unique """
fname = '/var/impression/jid'
## Maybe need a lock ?
try:
f = file(fname,'r+')
cur = int(f.read())+1
f.seek(0)
except (IOError,ValueError):
cur = 0
f = file(fname,'w')
f.write(str(cur))
f.close()
return cur
# ######################################################## #
# CLASSE IMPRESSION #
# ######################################################## #
#
#
class impression:
"""impression
Un objet impression correspond à un fichier pdf et un adhérent.
"""
# fichier (chemin)
_fichier = ""
# adherent (instance)
_adh = None
# paramettres
_settings = {
'agrafage': 'None',
'papier': 'A4',
'couleur': False,
'recto_verso': False,
'livret': False,
'copies': 1,
'portrait': True,
}
# le prix de l'impression
_prix = 0.0
_pages = 0
# le cout de base encre pour une impression en couleurs/n&b
# (prix pour papier A4)
_base_prix_nb = 0.0
_base_prix_couleurs = 0.0
# Format du pdf, tout droit sorti de pdfinfo
# (les dimensions sont donc en pts)
_format = '(A4)'
_width = 595.28
_height = 841.89
# Jid unique, à définir avant l'impression
_jid = 0
def __init__(self, path_to_pdf, adh = None):
"""impression(path_to_pdf [, adh])
Crée un nouvel objet impression à partir du fichier pdf pointé
par path_to_pdf. Si adh ext donné, il peut être soit une
instance d'un objet adhérent de crans_ldap soit le login de
l'adhérent. Lève l'exception FichierInvalide si le fichier
n'existe pas ou si ce n'est pas un pdf.
"""
# On ouvre les logs
self.log = logs.getFileLogger('impression')
self._fichier = path_to_pdf
self._adh = adh
# on verifie que le fichier existe
if not os.path.isfile(path_to_pdf):
raise FichierInvalide, ("Fichier introuvable", path_to_pdf)
if not open(path_to_pdf).read().startswith("%PDF"):
raise FichierInvalide, ("Le fichier ne semble pas etre un PDF", path_to_pdf)
# on compte les pages et on regarde le format
pdfinfo = Popen(["pdfinfo",self._fichier],stdout=PIPE,stderr=PIPE).communicate()
if pdfinfo[1] <> '':
raise FichierInvalide(u"pdfinfo n'arrive pas a lire le fichier (il est peut-etre corrompu ou protege par un mot de passe), https://wiki.crans.org/VieCrans/ImpressionReseau#Format_des_fichiers",path_to_pdf)
self._pages = -1
for line in pdfinfo[0].split('\n'):
if line.startswith('Pages'):
self._pages = int(line.split()[1])
elif line.startswith('Page size'):
size = line.split()
if len(size) <= 6:
self._format = "Unknown"
else:
self._format = size[6]
self._width = float(size[2])
self._height = float(size[4])
# Hack pour mieux reconnaître les formats
w = min(self._width,self._height)
h = max(self._width,self._height)
err = 100
if abs(w - 595) < err and abs(h - 842) < err:
self._format = "(A4)"
elif abs(w - 842) < err and abs(h - 1180) < err:
self._format = "(A3)"
if self._pages <= 0:
raise FichierInvalide(u"Impossible de lire le nombre de pages",path_to_pdf)
if not self._format in ['(A4)','(A3)']:
pass
#raise FichierInvalide, u"Seuls les formats A3 et A4 sont supportes"
# calcule le prix de l'encre tout de suite
self._calcule_prix()
def _pdfbook(self):
page = "pdfinfo \"%s\" | grep Pages | awk '{print $2}'" % self._fichier
(status, npage) = getstatusoutput(page)
if status != 0:
self.log.error("pdfinfo status:%d | rep: %s" % (status, npage))
raise FichierInvalide, ("pdfinfo: Impossible de trouver le nombre de page du fichier",
self._fichier)
if int(int(npage)/4*4) < int(npage):
sig=int((int(npage)/4 +1)*4)
else:
sig=int(npage)
if self._settings['papier'] == 'A3':
newfile = self._fichier[:-4] + '-a3book.pdf'
pdfbook = "pdfbook --signature %s --paper a3paper %%s --outfile %s" % (sig,newfile)
else:
newfile = self._fichier[:-4] + '-book.pdf'
pdfbook = "pdfbook --signature %s %%s --outfile %s" % (sig,newfile)
(status, rep) = getstatusoutput(pdfbook % self._fichier)
self.log.info("%s | rep: %s" % ((pdfbook % self._fichier), rep))
self._fichier = newfile
if status != 0:
self.log.error("pdfbook status:%d | rep: %s" % (status, rep))
raise FichierInvalide, ("pdfbook: Impossible de convertir le fichier",
self._fichier)
def changeSettings(self, **kw):
"""changeSettings([keyword=value])
Change les parametres de l'impression, recalcule et renvoie le nouveau prix.
Lève une exceotion SettingError si les paramètres son invalides.
"""
#recalcule et renvoie le prix
couleur = kw.get('couleur', None)
if couleur in [True, False]:
self._settings['couleur'] = couleur
elif couleur == "True":
self._settings['couleur'] = True
elif couleur == "False":
self._settings['couleur'] = False
try:
if int(kw['copies']) >= 1:
self._settings['copies'] = int(kw['copies'])
except:
pass
recto_verso = kw.get('recto_verso', None)
if recto_verso == "True": recto_verso = True
if recto_verso == "False": recto_verso = False
if recto_verso in [True, False]:
self._settings['recto_verso'] = recto_verso
papier = kw.get('papier', None)
if papier in ['A4', 'A3', 'A4tr']:
self._settings['papier'] = papier
if papier == 'A4tr':
self._settings['recto_verso'] = False
self._settings['agrafage'] = 'None'
agrafage = kw.get('agrafage', None)
if agrafage in ["None", "TopLeft", "Top", "TopRight",
"Left", "Right", "BottomLeft", "BottomRight"]:
self._settings['agrafage'] = agrafage
livret = kw.get('livret', None)
if livret == "True": livret = True
if livret == "False": livret = False
if livret in [True, False]:
self._settings['livret'] = livret
if livret:
self._settings['portrait'] = True #Le mode paysage est géré par _pdfbook
self._settings['recto_verso'] = True
self._settings['agrafage'] = 'None'
if self._settings['papier'] == 'A4tr':
self._settings['papier'] = 'A4'
else:
self._settings['portrait'] = self._width < self._height
return self._calcule_prix()
def printSettings(self):
"""printSettings()
Affiche les paramètres courrants sur la sortie standard
"""
if self._settings['couleur']:
print "Type impression: Couleur"
else:
print "Type impression: Noir et blanc"
print "Papier: " + DICT_PAPIER[self._settings['papier']]
if self._settings['livret']:
print u"Agrafage: Livret (piqûre à cheval)"
else:
print "Agrafage: " + DICT_AGRAFAGE[self._settings['agrafage']]
if self._settings['recto_verso']:
print "Disposition: recto/verso"
else:
print "Disposition: recto"
print "Copies: " + str(self._settings['copies'])
def prix(self):
"""prix()
Renvoie le prix courrant de l'impression
"""
return self._prix
def fileName(self):
"""fileName()
renvoie le nom du fichier pdf (exemple : monPdf.pdf)
"""
return os.path.basename(self._fichier)
def filePath(self):
"""filePath()
renvoie le chemin d'accès au fichier pdf.
"""
return self._fichier
def pages(self):
"""pages()
renvoie le nombre de pages du document (page au sens nombre de
faces à imprimer et non le nombre de feuilles)
"""
return self._pages
def imprime(self):
"""imprime()
imprime le document pdf. débite l'adhérent si adhérent il y a.
(si il a été indiqué à l'initialisation de l'objet)
"""
# Ce fichier est rempli par le script print_status.py du même dossier
# à intervalle régulier
with open('/usr/scripts/var/print_status/error.txt', 'r') as stat:
err = stat.read()
if err:
raise PrintError('Imprimante en panne :' + err)
self._jid = _uniq_jid()
# debite l'adhérent si adherent il y a
if (self._adh != None):
adh = self._adh.split('@')
if len(adh) > 1:
adh = adh[1:]
adh = self._get_adh(adh[0])
self._calcule_prix() # Normalement inutile, mais évite les races
if (self._prix > (adh.solde() - DECOUVERT_AUTHORISE)):
raise SoldeInsuffisant
adh.solde(-self._prix, "impression(%d): %s par %s" % (self._jid,self._fichier,self._adh))
adh.save()
del adh
# imprime le document
self._exec_imprime()
def _calcule_prix(self):
faces = self._pages
if self._settings['livret']:
feuilles = int((faces+3)/4)
faces = 2 * feuilles
elif self._settings['recto_verso']:
feuilles = int(faces/2.+0.5)
else:
feuilles = faces
if (self._settings['papier'] == "A3"):
c_papier = config_impression.c_a3
pages = 2*faces
else:
pages = faces
if self._settings['papier'] == "A4tr":
c_papier = config_impression.c_trans
else:
c_papier = config_impression.c_a4
if self._settings['couleur']:
c_impression = c_papier * feuilles + config_impression.c_face_couleur * pages
else:
c_impression = c_papier * feuilles + config_impression.c_face_nb * pages
# Cout des agrafes
if self._settings['agrafage'] in ["Top", "Bottom", "Left", "Right"] or self._settings['livret']:
nb_agrafes = 2
elif self._settings['agrafage'] in ["None", None]:
nb_agrafes = 0
else:
nb_agrafes = 1
if feuilles <= 50:
c_agrafes = nb_agrafes * config_impression.c_agrafe
else:
c_agrafes = 0
c_total = int(self._settings['copies'] * ( c_impression +
c_agrafes ) + 0.5) # arrondi et facture
self._prix = float(c_total)/100
return self._prix
def _get_adh(self, adh):
if type(adh) == str:
from gestion.ldap_crans import CransLdap
adh = CransLdap().getProprio(adh, 'w')
return adh
## ################################# ##
## fonction qui imprime pour de vrai ##
## ################################# ##
##
def _exec_imprime(self):
""" Envoie l'impression a l'imprimante avec les parametres actuels """
if self._settings['livret']:
self._pdfbook()
if (self._adh != None):
self.log.info('Impression(%d) [%s] : %s' % (self._jid, self._adh, self._fichier))
else:
self.log.info("Impression(%d) : %s" % (self._jid, self._fichier))
# Envoi du fichier à CUPS
options = ''
# Création de la liste d'options
# pour le nombre de copies et specifie non assemblee
#options += '-# %d -o Collate=True' % self.nb_copies
# Pour spécifier l'imprimante
options += ' -P canon_irc3580'
# Pour spécifier un jobname de la forme jid:adh:nom_du_fichier
jobname = '%d:%s:%s' % (self._jid, self._adh, self._fichier.split('/')[-1].replace("\"","\\\""))
# Ce nom apparaît sur l'interface d'impression de l'imprimante:
options += " -o CNDocName=\"%s\"" %jobname
# Et dans lpq:
options += " -T \"%s\"" % jobname
# Pour donner le login de l'adherent
options += ' -U \"%s\"' % self._adh
# Pour spécifier la version du language postscript utilisé par pdftops
# options += ' -o pdf-level3'
# Pour demander une page de garde
#options += ' -o job-sheets=crans' #page de garde de type standard
#options += " -o job-billing=%.2f" % self.cout
#options += ' -o job-sheets=none'
#Indique la présence d'un bac de sortie avec agrafeuse
# options += " -o Option20=MBMStaplerStacker -o OutputBin=StackerDown"
if self._settings['papier'] == 'A4tr':
options += ' -o InputSlot=SideDeck -o MediaType=OHP'
options += ' -o PageSize=A4'
elif self._settings['papier'] == 'A4':
options += ' -o PageSize=A4'
else:
options += ' -o pdf-expand -o pdf-paper=841x1190 -o PageSize=A3'
if self._settings['portrait']:
if self._settings['recto_verso']:
options += ' -o sides=two-sided-long-edge'
else:
options += ' -o sides=one-sided'
else:
if self._settings['recto_verso']:
options += ' -o sides=two-sided-short-edge -o landscape'
else:
options += ' -o sides=one-sided -o landscape'
if self._settings['couleur']:
options += ' -o CNColorMode=color'
else:
options += ' -o CNColorMode=mono'
if self._settings['livret']:
options += ' -o CNSaddleStitch=True'
options += ' -o OutputBin=TrayC'
else:
options += ' -o OutputBin=TrayA'
options += ' -o Collate=StapleCollate -o StapleLocation=%s' % self._settings['agrafage']
if not self._settings['livret'] and self._settings['agrafage'] in ['None', None]:
left = self._settings['copies']
while left >= 100:
cmd = "lpr %s -# %d %s" % (options, 99, self._fichier)
left -= 99
(status, rep) = getstatusoutput(cmd)
self.log.info("printing: %s" % cmd)
if status != 0:
self.log.error("erreur impression")
self.log.error("lpr status:%d | rep: %s" % (status, rep))
raise PrintError, "%s \n status:%d rep: %s" % (cmd, status, rep)
cmd = "lpr %s -# %d %s" % (options, left, self._fichier)
(status, rep) = getstatusoutput(cmd)
self.log.info("printing: %s" % cmd)
if status != 0:
self.log.error("erreur impression")
self.log.error("lpr status:%d | rep: %s" % (status, rep))
raise PrintError, "%s \n status:%d rep: %s" % (cmd, status, rep)
else:
cmd = "lpr %s %s" % (options, self._fichier)
self.log.info("printing [%s]: %s" % (cmd, self._settings['copies']))
for i in range(self._settings['copies']):
(status, rep) = getstatusoutput(cmd)
if status != 0:
self.log.error("erreur impression")
self.log.error("lpr status:%d | rep: %s" % (status, rep))
raise PrintError, "%s \n status:%d rep: %s" % (cmd, status, rep)

View file

@ -1,45 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess
from impression_canon import DECOUVERT_AUTHORISE, DICT_AGRAFAGE, AVAIL_AGRAFES,\
DICT_PAPIER, FichierInvalide, SoldeInsuffisant, PrintError, SettingsError
import impression_canon
class impression(impression_canon.impression):
""" Extension de la classe d'impression de l'imprimante canon,
la seule méthode ayant un comportement différent est _exec_imprime
qui fait appel à canon_wrapper.py au lieu de lp"""
def _exec_imprime(self):
""" Envoie l'impression à l'imprimante avec les parametres actuels """
opt=[]
if (self._adh != None):
self.log.info('Impression(%d) [%s] : %s' % (self._jid, self._adh, self._fichier))
else:
self.log.info("Impression(%d) : %s" % (self._jid, self._fichier))
# Pour spécifier un jobname de la forme jid:adh:nom_du_fichier
jobname = '%d:%s:%s' % (self._jid, self._adh, self._fichier.split('/')[-1].replace("\"","\\\""))
opt += ['--jobname', jobname]
opt += ['--copies', str(self._settings['copies'])]
opt += ['--page-size', self._settings['papier']]
opt += ['--colors', 'yes' if self._settings['couleur'] else 'no']
if self._settings['livret']:
opt += ['--duplex-type', 'book']
else: # Not livret
if self._settings['recto_verso']:
opt += ['--duplex-type', ('long' if self._settings['portrait']
else 'short')+'-edge']
else:
opt += ['--duplex-type', 'one-sided']
opt += ['--staple-position', self._settings['agrafage']]
opt.append(self._fichier)
self.log.info("Impression(%d) : %s" % (self._jid, " ".join(opt)))
subprocess.Popen(['/usr/scripts/impression/canon_wrapper.py'] + opt)

View file

@ -1,72 +0,0 @@
#!/bin/bash /usr/scripts/python.sh
# -*- coding: utf-8 -*-
import netsnmp
from utils import sendmail
from time import time
import json
from md5 import md5
STATUS_FILE = "/usr/scripts/var/impression/printer_watch_status.json"
STATUS_MESSAGE_FILE = "/usr/scripts/var/impression/error_message"
PRINTER_HOST = "imprimante.adm.crans.org"
successfuly_imported = False
try:
with open(STATUS_FILE, "r") as to_load:
extracted_dict = json.load(to_load)
try:
last_status = extracted_dict[u"last_status"]
message_id = extracted_dict[u"message_id"]
successfuly_imported = True
except (KeyError, ValueError):
pass
except (IOError, ValueError, TypeError):
pass
# On check le statut de l'imprimante
status_id = netsnmp.Varbind("hrDeviceStatus.1")
status = netsnmp.snmpget(status_id, Version=1, DestHost=PRINTER_HOST, Community="public")
if status == ('5',) and (not successfuly_imported or successfuly_imported and (last_status == '2' or last_status == '3')):
"""
Cas 1: L'imprimante est down et soit elle était précédemment fonctionnelle ou son statut précédent est inconnu.
On envoie un mail pour signaler qu'elle est down.
"""
# On récolte la liste des erreurs dans cette branche
errors = netsnmp.snmpwalk(netsnmp.Varbind("mib-2.43.18.1.1.8.1"), Version=1, DestHost=PRINTER_HOST, Community="public")
errors_list = [error + '\n' for error in errors]
#On crée un joli message d'erreur contenant la liste des erreurs
msg = """ L'imprimante est actuellement hors service. Les erreurs suivantes se sont produites:
%s""" % ''.join(errors_list)
#On crée un Message-ID
message_id = md5(str(time())).hexdigest() + "@imprimante.adm.crans.org"
sendmail.sendmail(u"imprimante.adm@crans.org", u"impression@lists.crans.org", u"Imprimante hors service", msg, more_headers={"X-Mailer": "/usr/scripts/impression/printer_watch.py", "Message-ID": message_id})
elif (status == ('2',) or status == ('3',)) and successfuly_imported and last_status == '5':
"""
Cas 2: L'imprimante est fonctionnelle après une panne.
On envoi un mail pour signaler que ce n'est plus la peine de se déplacer.
"""
msg = " L'imprimante est de nouveau fonctionnelle \o/"
sendmail.sendmail(u"imprimante.adm@crans.org", u"impression@lists.crans.org", u"Imprimante fonctionnelle", msg, more_headers={"X-Mailer": "/usr/scripts/impression/printer_watch.py", "In-Reply-To": message_id})
message_id = None
elif successfuly_imported:
pass
else:
message_id = None
with open(STATUS_FILE, "w") as dump_file:
json.dump({u"last_status": status[0], u"message_id": message_id}, dump_file)
with open(STATUS_MESSAGE_FILE, 'w') as f:
if message_id:
f.write(message_id)