
et d'espace dans le préfix utilisé pour géner le nom des fichiers temporaires darcs-hash:20060127083313-9e428-99048e14eafa9906e8ee1284c8090e0023f1fb62.gz
426 lines
19 KiB
Python
Executable file
426 lines
19 KiB
Python
Executable file
#! /usr/bin/env python
|
|
# -*- coding: iso-8859-15 -*-
|
|
#
|
|
# Class pour l'impression depuis le web par cups
|
|
# Codé par Francois
|
|
# Inspiré par le backend écrit par Benoit, Fred et Brice, inspirés par CUPSPykota
|
|
# Licence : GNU General Public Licence, version 2
|
|
|
|
import sys, time, tempfile, os, commands, string
|
|
sys.path.append('/usr/scripts/impression')
|
|
sys.path.append('/usr/scripts/gestion')
|
|
from config import impression
|
|
#sys.path.append('/localhome/bobot/scripts/gestion')
|
|
from ldap_crans import crans_ldap
|
|
#import vraicouts
|
|
|
|
duree_vie_pdf=3600
|
|
|
|
#fonction principal: impression (fichier_impression)
|
|
|
|
class test:
|
|
def mail(self):
|
|
return u"francois.bobot@crans.org"
|
|
def Nom(self):
|
|
return u"francois"
|
|
def solde(self,modif=0.):
|
|
return (40.+modif)
|
|
def save(self):
|
|
pass
|
|
|
|
|
|
class fichier_impression :
|
|
nom_job=''
|
|
nbr_pages=1
|
|
nb_copie=1
|
|
taille="A4"
|
|
recto_verso=False
|
|
transparent=False
|
|
couleur=True
|
|
cout=0.0
|
|
portrait=True
|
|
user=""
|
|
user_ldap=None #seras une instance de l'utilisateur dans la base ldap.
|
|
imprime=-1 #-2 impression en suspend, -1 mise dans la file d'attente, 0 devis, time pour l'heure, -3 déja imprimé ou devis fait depuis trops longtemps : le pdf n'est plus disponible
|
|
nom_fichier_pdf="" #chemin et nom du pdf
|
|
nom_fichier_desc="" #chemin et nom du fichier contenant les options de l'utilisateur
|
|
list_messages=[] #liste d'erreur et de remarque
|
|
list_messages_importants=[]
|
|
list_messages_admin=[] #liste d'erreur réservé au administrateur
|
|
erreur_critique=False #True si une erreur empêchant l'impression est apparue
|
|
code=None #code pour le digicode
|
|
modif_epoch=0.0 #moment de création du job ou devis. exprimé en epoch (float) : nombre de seconde depuis la référence du temps unix (+-=1970)
|
|
job_id=None #champs pour de futur amélioration
|
|
|
|
def actualise_cout(self):
|
|
# Calcul du cout de l'impression :
|
|
retour = cout(self)
|
|
|
|
# Met le prix dans cout s'il n'y a pas d'erreur
|
|
if type(retour) is float :
|
|
self.cout=retour
|
|
self.list_messages_importants.append('cout')
|
|
else:
|
|
self.erreur_critique=True
|
|
self.list_messages_importants.append('erreur_critique')
|
|
self.list_messages_admin.append('erreur_cout')
|
|
sys.stderr.write(retour)
|
|
|
|
#repond vrai si le solde est assez élevé.
|
|
def test_cout(self):
|
|
if self.user_ldap==None:
|
|
self.user_ldap = utilisateur(self.user,False)
|
|
#self.user_ldap = test()
|
|
return not (self.cout > (self.user_ldap.solde() - impression.decouvert)) #!impression.decouvert est négatif.
|
|
|
|
def fait_payer(self):
|
|
self.user_ldap = utilisateur(self.user,True)
|
|
#self.user_ldap = test()
|
|
self.user_ldap.solde(-self.cout)
|
|
self.user_ldap.save()
|
|
return not (self.cout > (self.user_ldap.solde() - impression.decouvert))
|
|
|
|
def gen_code(self):
|
|
#Génération du code et écriture du code
|
|
i=0
|
|
code=0
|
|
import random
|
|
#instance de base
|
|
rand=random.Random()
|
|
#graine automatique avec le temps
|
|
rand.seed()
|
|
while(i<1000) :
|
|
#on génère le numéro de session
|
|
code=rand.randint(100000,999999) #pour avoir six chiffres
|
|
#on verifie que le code n'est déja pas utilisé
|
|
try:
|
|
open("/var/impression/codes/%d" %code, 'r')
|
|
#open("/home/bobot/tmp/codes/%d" %code, 'r')
|
|
except :
|
|
break
|
|
i=i+1
|
|
|
|
if code:
|
|
#on enregistre le fichier avec le code pour numéro
|
|
codefichier=open("/var/impression/codes/%d" %code, 'w')
|
|
#codefichier=open("/localhome/bobot/codes/%d" %code, 'w')
|
|
codefichier.write("Utilisateur %s\n"%(self.user_ldap.Nom()))
|
|
codefichier.close()
|
|
self.code=code
|
|
self.list_messages_importants.append('code')
|
|
else :
|
|
# Grosse erreur : on logue, on previent et on stoppe.
|
|
print ("ERROR: Il n'y a pas de code disponible" )
|
|
sys.stderr.write ("ERROR: Il n'y a pas de code disponible" )
|
|
try:
|
|
#crans_backend.send_email(prix.From, "Impression <%s>" % impression.From_imprimante , u"ERREUR " + sujet, mail_err % {'erreur' : "Il n'y a plus de code disponible.\n"})
|
|
self.list_messages_importants.append('erreur gen_code')
|
|
sys.stderr.write("DEBUG: Un rapport de bug a ete automatiquement envoye.\n")
|
|
except :
|
|
sys.stderr.write("ERROR: Impossible d'envoyer le rapport de bug.\n")
|
|
sys.stderr.write("ERROR: Plus de codes disponibles.\n")
|
|
sys.stderr.write("ERROR: Penser a ouvrir a l'adherent debite...\n")
|
|
#sys.exit(1)
|
|
|
|
def impression(self):
|
|
# Envoi du fichier à CUPS
|
|
|
|
#Création de la liste d'options
|
|
#pour le nombre de copies
|
|
options ='-# '+str(self.nb_copie)
|
|
#options ='-n '+str(self.nb_copie)
|
|
|
|
#pour spécifier l'imprimante
|
|
options +=' -P laserjet'
|
|
|
|
#pour spécifier la version du language postscript utilisé par pdftops
|
|
options +=' -o pdf-level3'
|
|
|
|
#pour donner le titre de l'impression
|
|
options +=' -T '+self.nom_job
|
|
#options +=' -t '+self.nom_job
|
|
|
|
#pour donner le login de l'adherent
|
|
options +=' -U '+self.user
|
|
|
|
#pour demander une page de garde
|
|
options +=' -o job-sheets=crans' #page de garde de type standard
|
|
if self.transparent :
|
|
options+=' -o InputSlot=Tray1 -o Media=Transparency'
|
|
if self.taille=='A4':
|
|
options+=(' -o pdf-paper=571x817 -o PageSize=A4')
|
|
else:
|
|
options+=(' -o pdf-paper=825x1166 -o InputSlot=Tray3 -o HPPaperPolicy=A3 -o PageSize=A3')
|
|
|
|
if self.portrait:
|
|
if self.recto_verso:
|
|
options+=(' -o sides=two-sided-long-edge')
|
|
else:
|
|
options+=(' -o sides=one-sided')
|
|
else:
|
|
options+=(' -o landscape')
|
|
if self.recto_verso:
|
|
options+=' -o sides=two-sided-short-edge'
|
|
else:
|
|
options+=' -o sides=one-sided'
|
|
options+=' -o HPColorasGray='+str(not self.couleur)
|
|
(status,rep) = commands.getstatusoutput("lpr %s %s" %(options,self.nom_fichier_pdf))
|
|
if status<>0:
|
|
print "<p>status:"+str(status)+" rep:"+rep+"</p>"
|
|
#else:
|
|
#self.job_id=rep.split(' ')[3]
|
|
|
|
def corrige (self):
|
|
#
|
|
# fic_impr=fichier_impression()
|
|
# fic_impr.user=utilisateur(arguments[2],rw)
|
|
#trouve le nombre de pages
|
|
self.nbr_pages = int(os.popen("pdfinfo %s | grep Pages " % (self.nom_fichier_pdf)).readline().split()[1])
|
|
##Corrige les aberrations
|
|
##Correction des aberations (transparent et recto_verso :) )
|
|
##Priorité des informations par ordre décroissant
|
|
##Transparent, paper, nbr_page, recto_verso
|
|
if (self.taille<>'A4') & (self.taille<>'A3'):
|
|
self.list_messages_importants.append("paper")
|
|
self.erreur_critique=True
|
|
if self.transparent:
|
|
if self.paper<>'A4':
|
|
self.list_messages.append("A3 transparent")
|
|
self.paper='A4'
|
|
if self.recto_verso:
|
|
self.list_messages.append("Recto_verso transparent")
|
|
self.recto_verso=False
|
|
if self.nbr_pages==1 & self.recto_verso:
|
|
self.list_messages.append("Recto_verso 1 page")
|
|
self.recto_verso=False
|
|
|
|
def affiche_messages_html(self):
|
|
body=""
|
|
|
|
"""if self.imprime:
|
|
body=string.join(map ((dico_message_laserjet.get),self.list_messages_importants))
|
|
if len(self.list_messages)<>0:
|
|
body=body+'\nRemarques:\n'+string.join(map ((dico_message_laserjet.get),self.list_messages))
|
|
else:
|
|
body=string.join(map ((dico_message_devis.get),self.list_messages_importants))
|
|
body=body+'\nRemarque:\n'+string.join(map ((dico_message_devis.get),self.list_messages))
|
|
|
|
body=body % {'taille' : self.taille, 'code' : self.code, 'solde' : self.user_ldap.solde(), 'cout' : self.cout , 'adresse_imprimante' : impression.From_imprimante}
|
|
"""
|
|
body=string.join(self.list_messages_importants)
|
|
return "<p>"+body+"</p>"
|
|
|
|
def enregistre_pdf(self,f_value,f_nom,dossier):
|
|
f_nom=f_nom.translate(string.maketrans(string.punctuation+string.whitespace,'______________________________________'))
|
|
(fd_fichier_desc,self.nom_fichier_desc) = tempfile.mkstemp(suffix='.desc',prefix=f_nom,dir=dossier)
|
|
os.close(fd_fichier_desc)
|
|
os.chmod(self.nom_fichier_desc,33184)
|
|
self.nom_fichier_pdf=self.nom_fichier_desc[0:-5]+".pdf"
|
|
#(,self.nom_fichier_pdf) = tempfile.mkstemp(suffix='.pdf',prefix=identifiant+f_nom,dir=data_dir+identifiant)
|
|
file_obj_pdf=open(self.nom_fichier_pdf,'w')
|
|
file_obj_pdf.write(f_value)
|
|
file_obj_pdf.close()
|
|
self.nbr_pages = int(os.popen("pdfinfo %s | grep Pages " % (self.nom_fichier_pdf)).readline().split()[1])
|
|
self.modif_epoch=time.time()
|
|
|
|
def sauve_desc(self):
|
|
file_obj_desc=open(self.nom_fichier_desc,'w')
|
|
for key in ("erreur_critique","nom_job","nbr_pages","nb_copie","taille","recto_verso","transparent","couleur","cout","portrait","user","imprime","nom_fichier_pdf","nom_fichier_desc","code","modif_epoch","job_id"):
|
|
file_obj_desc.write(key+"="+str(getattr(self,key))+"\n")
|
|
file_obj_desc.close()
|
|
|
|
def read_desc(self):
|
|
file_obj_desc=open(self.nom_fichier_desc,'r')
|
|
ligne=file_obj_desc.readline()[0:-1]
|
|
while ligne<>"":
|
|
parse=ligne.split("=")
|
|
if parse[1]=='None':
|
|
setattr(self,parse[0],None)
|
|
else:
|
|
if parse[0] in ("nom_job","taille","user","nom_fichier_pdf","nom_fichier_desc","job_id"):
|
|
setattr(self,parse[0],parse[1])
|
|
else:
|
|
if parse[0] in ("nbr_pages","nb_copie","imprime","code"):
|
|
setattr(self,parse[0],int(parse[1]))
|
|
else:
|
|
if parse[0] in ("recto_verso","transparent","couleur","portrait","erreur_critique"):
|
|
setattr(self,parse[0],(parse[1]=='True'))
|
|
else:
|
|
if parse[0] in ("cout","modif_epoch"):
|
|
setattr(self,parse[0],float(parse[1]))
|
|
else:
|
|
self.erreur_critique=True
|
|
print '<p>ligne non parser:'+ligne+'</p>'
|
|
ligne=file_obj_desc.readline()[0:-1]
|
|
file_obj_desc.close()
|
|
#Vérifie que le fichier existe bien si il doit exister.
|
|
if not os.access(self.nom_fichier_pdf,os.F_OK):
|
|
if self.imprime<>-3:
|
|
self.imprime=-4
|
|
#else:
|
|
# if (time.time()-self.modif_epoch)>duree_vie_pdf:
|
|
# os.remove(self.nom_fichier_pdf)
|
|
# self.imprime=-4
|
|
|
|
|
|
#fonction utilisé par print et str : renvoie le string canonique de l'objet
|
|
def __repr__(self):
|
|
dict_contraire={'couleur' : 'Noir et Blanc' , 'transparent' : 'Normal' , 'portrait': 'Paysage' , 'recto_verso' : 'Recto' , 'erreur_critique' : "Pas d'erreur"}
|
|
dict_normale={'couleur' : 'Couleur' , 'transparent' : 'Transparent' , 'portrait': 'Portrait' , 'recto_verso' : 'Recto-Verso' , 'erreur_critique' : "Problême survenue"}
|
|
#dict_imprime={-4: 'PDF indisponible', -3: 'Envoyé', -2 : 'En suspend', -1 : "En cours d'envoi", 0 : "Devis"}
|
|
#corps="<TABLE BORDER=0 CELLPADDDING=2>\n<TR><th ALIGN=CENTER COLSPAN=2><U>"+self.nom_job+"</U></th><td ALIGN=RIGHT>"+time.ctime(self.modif_epoch)+"</TR>\n"
|
|
corps="<TABLE BORDER=0 CELLPADDDING=2>\n<TR><th ALIGN=CENTER COLSPAN=2><U>"+self.nom_job+"</U></th><td ALIGN=RIGHT>"+time.ctime(0.0)+"</TR>\n"
|
|
corps+="<TR><td>\n<TABLE BORDER=2 RULES=ROWS CELLPADDDING=0>\n"
|
|
#if self.imprime>0:
|
|
# t=time.localtime(self.imprime)
|
|
# date="le %i à %i:%i" % t[2:4]
|
|
#else:
|
|
# date=dict_imprime[self.imprime]
|
|
#corps+="<TR><td>Impression</td><td>"+date+"</td></TR>\n"
|
|
for key in ("nbr_pages","nb_copie","taille","code"):
|
|
corps+='<TR><td>'+key+"</td><td>"+str(getattr(self,key))+"</td></TR>\n"
|
|
corps+="</TABLE>\n</td>\n<td>\n<TABLE BORDER=2 RULES=ROWS CELLPADDDING=0>\n"
|
|
for key in ("couleur","transparent","portrait","recto_verso"):
|
|
if getattr(self,key):
|
|
corps+='<TR><td>'+dict_normale[key]+"</td></TR>\n"
|
|
else:
|
|
corps+='<TR><td>'+dict_contraire[key]+"</td></TR>\n"
|
|
corps+="</TABLE>\n</td><td><U>"
|
|
if self.erreur_critique:
|
|
corps+="erreur de comptage"
|
|
else:
|
|
corps+=str(self.cout)+"euros"
|
|
corps+="</U></td></TR>\n</TABLE>"
|
|
#if self.job_id<>None:
|
|
# corps+="Le travaille à été imprimé sous le nom : "+self.job_id+"<BR/>
|
|
return corps
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def utilisateur(user, rw):
|
|
""" Renvoie l'adherent qui imprime le job
|
|
* user est l'utilisateur (argument n°2 des paramètres passés au backend)
|
|
* rw vaut True si on veut modifier le compte LDAP de l'adhérent,
|
|
False dans le cas contraire
|
|
"""
|
|
|
|
# Impression en local avec les certificats (possible pour le groupe adm)
|
|
if user=="root":
|
|
sys.stderr.write("ERROR: Utilisateur root passé en paramètre.\n")
|
|
sys.exit(0) # On conclue l'impression
|
|
|
|
# Récupération de l'adhérent
|
|
try:
|
|
base = crans_ldap()
|
|
if rw:
|
|
res=base.search("login=%s"%user,'w')['adherent']
|
|
else:
|
|
res=base.search("login=%s"%user)['adherent']
|
|
except:
|
|
print ("ERROR: Erreur : Base LDAP non joignable\n")
|
|
sys.exit(0) # On arrete l'avant-impression ?on arrete l'imprimante?
|
|
|
|
# Si on ne trouve rien :
|
|
if len(res) != 1 :
|
|
print ("ERROR: Erreur : adhérent %s non trouvé\n" % user)
|
|
sys.exit(0) # On conclue l'avant-impression sans stopper l'imprimante
|
|
|
|
adherent = res[0]
|
|
sys.stderr.write("DEBUG: Adherent %s recupere.\n" % adherent.Nom())
|
|
return adherent
|
|
|
|
#fonction cout calcule le pourcentage de couleur sur les pages
|
|
# renvoit un string avec le nom de l'erreur si erreur il y a
|
|
#renvoit un float dans les cas de fonctionnement...
|
|
|
|
def cout( fic_impr):
|
|
#taille peut valoir A3 ou A4
|
|
#nb_copie est le nombre de copies désirées
|
|
|
|
#nom_rep seras le dossier dans tmp ou tous les fichier créé par convert seront entreposé
|
|
nom_rep=tempfile.mkdtemp(prefix='tmpimpr')
|
|
nom_png=nom_rep + "/convert.png" #nom prefixe et chemin des png créé par convert
|
|
|
|
if (fic_impr.taille == "A3"):
|
|
# Une feuille A3 couvre 2 fois plus de surface que A4
|
|
c_taille = impression.c_a3
|
|
cout_coul = 2*impression.c_coul
|
|
cout_noir = 2*impression.c_noir
|
|
else:
|
|
cout_coul = impression.c_coul
|
|
cout_noir = impression.c_noir
|
|
if fic_impr.transparent:
|
|
c_taille = impression.c_trans
|
|
else:
|
|
c_taille = impression.c_a4
|
|
|
|
if (fic_impr.couleur):
|
|
#convertit les pdf en png couleur
|
|
#(status,rep) = commands.getstatusoutput("nice -n 5 convert %s %s" % (fic_impr.nom_fichier_pdf,nom_png))
|
|
(status,rep) = commands.getstatusoutput("nice -n 5 gs -sDEVICE=png16m -r30 -dBATCH -dNOPAUSE -dSAFER -dPARANOIDSAFER -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dMaxBitmap=50000000 -sOutputFile=%s -q %s" % (nom_png,fic_impr.nom_fichier_pdf))
|
|
if status:
|
|
return "ERREUR : Fichier invalide. Aucun png n'a été créé.\n"
|
|
|
|
#récupère la liste des fichiers
|
|
list_filepng=os.listdir(nom_rep)
|
|
#calcule le nombre de pixel de couleur
|
|
remplissage = [0, 0, 0, 0, 0] # C, M, J, N, nombre de pages
|
|
for fichier in list_filepng:
|
|
resultats = commands.getoutput("nice -n 5 /usr/scripts/impression/percentcolour %s" % (nom_rep+'/'+fichier))
|
|
#resultats = '2.103:3.363:4.131:29.300:1'
|
|
l_resultats = resultats.split(":")
|
|
for i in [0, 1, 2, 3]:
|
|
remplissage[i] += float(l_resultats[i])*float(l_resultats[4])
|
|
remplissage[4] += float(l_resultats[4])
|
|
total_noir = remplissage[3]
|
|
total_couleur = sum(remplissage[0:3])
|
|
faces = int(remplissage[4])
|
|
if (fic_impr.recto_verso == False):
|
|
pages = faces # nb de pages par copies
|
|
else:
|
|
pages = int(faces/2.+0.5)
|
|
if total_couleur > 0:
|
|
c_total = c_taille*pages+(impression.c_tambour_coul+impression.c_tambour_noir)*faces+cout_noir*total_noir+cout_coul*total_couleur
|
|
else: # Pas de couleur, malgre l'indication
|
|
c_total = c_taille*pages+impression.c_tambour_noir*faces+cout_noir*total_noir
|
|
else:
|
|
#convertit les pdf en png
|
|
#(status,rep) = commands.getstatusoutput("nice -n 5 convert -colorspace GRAY %s %s" % (fic_impr.nom_fichier_pdf,nom_png))
|
|
(status,rep) = commands.getstatusoutput("nice -n 5 gs -sDEVICE=pnggray -r30 -dBATCH -dNOPAUSE -dSAFER -dPARANOIDSAFER -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dMaxBitmap=50000000 -sOutputFile=%s -q %s" % (nom_png,fic_impr.nom_fichier_pdf))
|
|
if status:
|
|
return "ERREUR : Fichier invalide. Aucun png n'a été créé.\n"
|
|
|
|
#récupère la liste des fichiers
|
|
list_filepng=os.listdir(nom_rep)
|
|
|
|
remplissage = [0, 0] # Noir, nombre de pages
|
|
for fichier in list_filepng:
|
|
#resultats = commands.getoutput("/home/bobot/crans/impression/percentblack '%s'" % (nomrep+'/'+fichier))
|
|
resultats = commands.getoutput("nice -n 5 /usr/scripts/impression/percentblack '%s'" % (nom_rep+'/'+fichier) )
|
|
#resultats = '2.103:3.363:4.131:29.300:1'
|
|
l_resultats = resultats.split(":")
|
|
remplissage[0] += float(l_resultats[0])*float(l_resultats[1])
|
|
remplissage[1] += float(l_resultats[1])
|
|
total_noir = remplissage[0]
|
|
faces = int(remplissage[1])
|
|
if (fic_impr.recto_verso == False):
|
|
pages = faces # nb de pages par copies
|
|
else:
|
|
pages = int(faces/2.+0.5)
|
|
c_total = c_taille*pages+impression.c_tambour_noir*faces+cout_noir*total_noir
|
|
|
|
c_total = int(fic_impr.nb_copie*c_total+impression.fact+0.5) # arrondi et facture
|
|
|
|
if commands.getoutput("rm -r -f " + nom_rep):
|
|
self.list_messages_admin.append('erreur_cout')
|
|
sys.stderr.write("ERREUR : Impossible d'enlever le dossier.\n")
|
|
|
|
return float(c_total)/100
|
|
|
|
|
|
|
|
|
|
|