From fc6003e7aeb05fd4e0368bb55ed456317cc20fe4 Mon Sep 17 00:00:00 2001
From: dubost
Date: Thu, 19 May 2005 22:06:07 +0200
Subject: [PATCH] Scripts pour l'impression
Mis a jour par rapport a ceux de sila
darcs-hash:20050519200607-c3cc4-4f4b1e259da0b201ec9a97a68b89b1f57e2fd940.gz
---
impression/couts.py | 289 +++++++++++++++++++++++++++++++++++++++++
impression/pjl_comm.py | 117 +++++++++++++++++
radius_digicode.py | 39 ++++++
3 files changed, 445 insertions(+)
create mode 100755 impression/couts.py
create mode 100755 impression/pjl_comm.py
create mode 100755 radius_digicode.py
diff --git a/impression/couts.py b/impression/couts.py
new file mode 100755
index 00000000..ef721988
--- /dev/null
+++ b/impression/couts.py
@@ -0,0 +1,289 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+
+# Utilisé par /usr/lib/cgi-bin/impression/analyse.py
+# /usr/lib/cups/backend/devis et /usr/lib/cups/backend/laserjet
+# Écrit par Benoit
+# modifie par Brice DUBOST
+
+import locale
+locale.setlocale(locale.LC_ALL, 'fr_FR')
+
+import os, commands
+import string
+import re
+import sys
+import tempfile
+
+sys.path.append('/usr/scripts/gestion')
+
+from config import impression
+
+
+class cout:
+ """Classe pour le calcul du cout d'une impression et de sa mise en page"""
+ #en centimes
+ c_total=0
+ #en euros
+ c_total_euros=0
+ total_noir=0
+ total_couleur=0
+ faces=1
+ pages=1
+ nb_copie=1
+ format="NON_VALIDE"
+ erreur=""
+ recto_v="None"
+
+ def __init__(self,fichierps, mode_couleur, recto_v="None", format="A4", nb_copie=1, media="" ):
+ """ * fichierps est le fichier PostScript (ou pdf) à analyser
+ * mode_couleur = Couleur pour traiter en couleur
+ * recto_v = Recto si l'on ne desire pas un recto-verso
+ * format vaut A3 ou A4 selon le bac choisi
+ * nb_copie est le nombre de copies désirées
+ * media vaut transparent le cas écheant (dans ce cas format=A4)
+ Le PostScript a toujours priorité sur ces parametres
+ """
+
+ self.nb_copie=nb_copie
+ # on compte le nb de copies et on enlève les balises pour ne pas recalculer
+ nb_copie_ps=0
+ original=open(fichierps)
+ fichier='/tmp/couts_temp'
+ try:
+ fic = open(fichier,'w')
+ except:
+ os.remove(fichier)
+ fic = open(fichier,'w')
+# fic = tempfile.NamedTemporaryFile()
+ ligne = original.readline()
+ while ligne:
+ if ligne.startswith('%%BeginFeature: *PageSize'):
+ format=ligne.split(' ')[-1].replace('\n','')
+ if ligne.startswith('%%BeginFeature: *Duplex'):
+ recto_v=ligne.split(' ')[-1].replace('\n','')
+ if ligne.find('%RBIBeginNonPPDFeature: *NumCopies') != -1:
+ nb_copie_ps=int(ligne.split(' ')[-1])
+ while ligne.find('%RBIEndNonPPDFeature') == -1:
+ ligne = original.readline()
+ ligne = original.readline()
+ fic.write(ligne)
+ ligne = original.readline()
+ fic.close()
+ original.close()
+
+ # Le PS a priorité
+ if nb_copie_ps:
+ self.nb_copie=nb_copie_ps
+
+ if format=="A4" or format=="A3":
+ self.format=format
+ else: # format invalide
+ self.erreur="Format invalide"
+ return
+
+ if recto_v == "None" or recto_v == "Recto":
+ recto_v="Recto"
+ else:
+ recto_v="Recto-verso"
+
+ self.recto_v=recto_v
+
+ if (mode_couleur == "Couleur"):
+ device = "png16m"
+ else:
+ device = "pnggray"
+
+ if (self.format == "A3"):
+ # Une feuille A3 couvre 2 fois plus de surface que A4
+ c_format = 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 (media == "transparent"):
+ c_format = impression.c_trans
+ else:
+ c_format = impression.c_a4
+
+ # Conversion en PostScript si le fichier est un pdf
+ # pour pouvoir le decouper en petits bouts.
+ # Vérification du format de fichier.
+ try:
+ en_tete=open(fichier).read(4)
+ except:
+ self.erreur="Le fichier ne peut etre ouvert"
+ return
+ # On vérifie que ce que l'on nous a envoyé est bien un PS ou un PDF
+ if en_tete!='%!PS' and en_tete!='%PDF':
+ self.erreur="ERREUR : Format non supporte !!"
+ return
+
+ (status,rep) = commands.getstatusoutput("nice -n 10 gs -sDEVICE=%s -r100 -dBATCH -dNOPAUSE -dSAFER -dPARANOIDSAFER -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dMaxBitmap=50000000 -sOutputFile='%s' -q '%s'" % (device, fichier+"%d.png", fichier) )
+ if (status != 0):
+ self.erreur="ERREUR : Ghostscript : Fichier Postscript invalide.\n"
+ self.erreur+= rep
+ # On détaille l'erreur dans le mail et
+ # il faut stopper l'impression.
+ return
+
+ # On a plus besoin du fichier temp, donc on le supprime.
+ os.remove(fichier)
+
+ if not os.system("ls '%s'*.png > /dev/null" % (fichier)):
+ if (mode_couleur == "Couleur"):
+ remplissage = [0, 0, 0, 0, 0] # C, M, J, N, nombre de pages
+ for file in string.split(commands.getoutput("ls '%s'*.png" % (fichier)),"\n"):
+ resultats = commands.getoutput("/usr/scripts/impression/percentcolour '%s'" % (file) )
+ l_resultats = string.split(resultats,":")
+ for i in [0, 1, 2, 3]:
+ remplissage[i] += float(l_resultats[i])*float(l_resultats[4])
+ remplissage[4] += float(l_resultats[4])
+ os.system("rm -f '%s'" % (file))
+ self.total_noir = remplissage[3]
+ self.total_couleur = sum(remplissage[0:3])
+ self.faces = remplissage[4]
+ if (recto_v == "Recto"):
+ self.pages = self.faces # nb de pages par copies
+ else:
+ self.pages = int(self.faces/2.+0.5)
+ self.c_total = c_format*self.pages+(impression.c_tambour_coul+impression.c_tambour_noir)*self.faces+cout_noir*self.total_noir+cout_coul*self.total_couleur
+ else:
+ remplissage = [0, 0] # Noir, nombre de pages
+ for file in string.split(commands.getoutput("ls '%s'*.png" % (fichier)),"\n"):
+ resultats = commands.getoutput("/usr/scripts/impression/percentblack '%s'" % (file))
+ l_resultats = string.split(resultats,":")
+ remplissage[0] += float(l_resultats[0])*float(l_resultats[1])
+ remplissage[1] += float(l_resultats[1])
+ os.system("rm -f '%s'" % (file))
+ self.total_noir = remplissage[0]
+ self.faces = remplissage[1]
+ if (recto_v == "Recto"):
+ self.pages = self.faces # nb de pages par copies
+ else:
+ self.pages = int(self.faces/2.+0.5)
+ self.c_total = c_format*self.pages+impression.c_tambour_noir*self.faces+cout_noir*self.total_noir
+ self.c_total = int(self.nb_copie*self.c_total+impression.fact+0.5) # arrondi et facture
+ self.c_total_euros=float(self.c_total)/100
+ os.system("rm -f '%s'*.png" %(fichier))
+ else:
+ self.erreur=u"ERREUR : Fichier Postscript invalide. aucun png a été créé\n"
+
+
+
+ def remplis_template(self,template):
+ """Cette fonction rempli le template avec les bonnes valeurs"""
+ if (self.c_total < 100):
+ str_cout = "%s centimes d'euros" % (self.c_total)
+ else :
+ str_cout = "%s euros" % (self.c_total/100.)
+
+ if self.format=="NON_VALIDE":
+ format=u"Le format de papier que vous avez demandé n'est pas valide"
+ else:
+ format=self.format
+ try:
+ return template % { 'prix' : str_cout }
+ except:
+ return template % { 'noir' : "%2.2f" % (self.total_noir/self.faces), 'couleur' : "%2.2f" % (self.total_couleur/self.faces), 'faces' :int(self.faces), 'pages' : int(self.pages), 'copies' : self.nb_copie, 'format' : format, 'prix' : str_cout}
+
+
+ def html_cout(self):
+ """Renvoie le cout formaté en html"""
+ # Format du PS (parfois different de celui choisi)
+ # Utile pour deboguage, sera supprime apres
+ template = """Résultats :
+ - Format de l'impression : %(format)s
+ - Noir (par copie) : %(noir)s%%
+ - Couleur (par copie) : %(couleur)s%%
+ - Nombre de faces (par copie) : %(faces)s
+ - Nombre de pages (par copie) : %(pages)s
+ - Nombre de copies : %(copies)s
+
Prix total : %(prix)s
+
\n
+
\n"""
+
+
+ if not self.erreur:
+ return self.remplis_template(template)
+ else:
+ return self.erreur
+
+
+ def send_mail(self, Dest , sujet, template):
+ """Cette fonction envoie le mail template correctement rempli
+ provenant de l'imprimante avec comme serveur
+ SMTP localhost
+ Arguments :
+ Dest : destinataire
+ sujet : sujet du mail
+ template : le corps du mail
+ Pour le remplissage du template voir source pour le moment"""
+
+ if not self.erreur:
+ mail=self.remplis_template(template)
+ else:
+ sujet="Erreur " + sujet
+ mail=self.erreur + "\n\n-- \nL'imprimante\n"
+
+ #l'envoi
+ self.send_email("Imprimante <%(From)s>" % { 'From' : impression.From_imprimante}, Dest , sujet, mail)
+
+
+ def send_email(self, sender, recipient, subject, body):
+ """Send an email.
+
+ All arguments should be Unicode strings (plain ASCII works as well).
+
+ Only the real name part of sender and recipient addresses may contain
+ non-ASCII characters.
+
+ The email will be properly MIME encoded and delivered though SMTP to
+ localhost port 25. This is easy to change if you want something different.
+
+ The charset of the email will be the first one out of US-ASCII, ISO-8859-1
+ and UTF-8 that can represent all the characters occurring in the email.
+ """
+ from smtplib import SMTP
+ from email.MIMEText import MIMEText
+ from email.Header import Header
+ from email.Utils import parseaddr, formataddr
+
+ # Header class is smart enough to try US-ASCII, then the charset we
+ # provide, then fall back to UTF-8.
+ header_charset = 'ISO-8859-1'
+
+ # We must choose the body charset manually
+ for body_charset in 'US-ASCII', 'ISO-8859-1', 'UTF-8':
+ try:
+ body.encode(body_charset)
+ except UnicodeError:
+ pass
+ else:
+ break
+
+ # Split real name (which is optional) and email address parts
+ sender_name, sender_addr = parseaddr(sender)
+ recipient_name, recipient_addr = parseaddr(recipient)
+
+ # We must always pass Unicode strings to Header, otherwise it will
+ # use RFC 2047 encoding even on plain ASCII strings.
+ sender_name = str(Header(unicode(sender_name), header_charset))
+ recipient_name = str(Header(unicode(recipient_name), header_charset))
+
+ # Make sure email addresses do not contain non-ASCII characters
+ sender_addr = sender_addr.encode('ascii')
+ recipient_addr = recipient_addr.encode('ascii')
+
+ # Create the message ('plain' stands for Content-Type: text/plain)
+ msg = MIMEText(body.encode(body_charset), 'plain', body_charset)
+ msg['From'] = formataddr((sender_name, sender_addr))
+ msg['To'] = formataddr((recipient_name, recipient_addr))
+ msg['Subject'] = Header(unicode(subject), header_charset)
+
+ # Send the message via SMTP to localhost:25
+ smtp = SMTP("localhost")
+ smtp.sendmail(sender, recipient, msg.as_string())
+ smtp.quit()
+
diff --git a/impression/pjl_comm.py b/impression/pjl_comm.py
new file mode 100755
index 00000000..5f3a1771
--- /dev/null
+++ b/impression/pjl_comm.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+
+"""Classe de communication avec l'imprimante
+HP9500"""
+
+import socket
+
+class hp9500:
+ "Classe de communication avec la HP9500"
+ #\x1B est le caractere d'échappement échap.
+ UEL="\x1b%-12345X"
+ __douille=None
+ def __init__(self,hostname="laserjet.adm.crans.org",port=9100):
+ """Appelle à l'initalisation
+ hostname : nom d'hôte de l'imprimante
+ port : le port de communication avec l'imprimante
+ """
+ self.hostname=hostname
+ self.port=port
+
+ def cx_open(self):
+ """Ouvre la connexion vers l'imprimante"""
+
+ if not self.__douille:
+ self.__douille = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.__douille.connect((self.hostname, self.port))
+ #delai d'attente pour la réception des données
+ self.__douille.settimeout(10)
+ self.__douille.send(self.UEL+"@PJL\n")
+
+ def cx_close(self):
+ """Ferme la connexion vers l'imprimante"""
+
+ if self.__douille:
+ self.__douille.send(self.UEL+"\n")
+ self.__douille.close()
+ self.__douille=None
+
+ def pjl_command(self,command):
+ """Cette fonction envoie la commande command à l'imprimante
+ Elle doit être une commande pjl sans @PJL devant
+
+ Paramètres :
+ command : la commande à envoyer à l'imprimante
+
+ """
+
+ if not self.__douille:
+ self.cx_open()
+
+ command=str(command)
+ command="@PJL " + command + "\n"
+ self.__douille.send(command)
+
+ #debug
+ print command
+
+ def pjl_read(self, display=0):
+ """Cette fonction lit le retour donné par l'imprimante
+ Elle retourne un message commençant par \"ERREUR :\" en
+ cas d'échec
+ Elle affiche le message si la variable display est vraie
+ """
+
+ if not self.__douille:
+ return "ERREUR : la connexion vers l'imprimante n'est pas ouverte"
+ message=""
+ caract=' '
+ while caract:
+ try:
+ caract=self.__douille.recv(1)
+ message+=caract
+ except:
+ caract=''
+ message+='\n'
+ if display:
+ print message
+ return message
+
+ def write_file(self,filename):
+ """Cette fonction envoie un fichier à l'imprimante.
+ Elle est utile pour envoyer une série de commande ou un fichier
+ postscript.
+
+ Arguments :
+ filename : nom du fichier à envoyer
+ """
+
+ if not self.__douille:
+ return "ERREUR : la connexion vers l'imprimante n'est pas ouverte"
+
+ fichier=open(filename)
+ self.__douille.sendall(fichier.read())
+ fichier.close()
+
+ def write_postscript(self,filename, name, display):
+ """Cette fonction envoie un fichier postscript à l'imprimante.
+ Elle envoie avant le ENTER LANGUAGE et le EOJ a la fin.
+
+ Arguments :
+ filename : nom du fichier à envoyer
+ name : le nom du job
+ display : ce qu'on met sur l'afficheur
+ """
+ if not self.__douille:
+ return "ERREUR : la connexion vers l'imprimante n'est pas ouverte"
+ self.pjl_command('JOB DISPLAY=\"%s\" NAME=\"%s\"' % (display,name))
+ self.pjl_command('ENTER LANGUAGE = POSTSCRIPT ')
+ self.write_file(filename)
+ self.__douille.send(self.UEL+"@PJL EOJ NAME=\"%s\"\n" % (name))
+
+
+ def __del__(self):
+ """Destructeur : ferme la connexion"""
+ self.cx_close()
+
diff --git a/radius_digicode.py b/radius_digicode.py
new file mode 100755
index 00000000..f233e13a
--- /dev/null
+++ b/radius_digicode.py
@@ -0,0 +1,39 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+
+"""
+Script de test du code de la porte du local de l'imprimante
+"""
+
+import os,sys
+
+def identification ( password ) :
+ # test un code entré sur la porte :
+ # doit retourner 0 si le code n'est pas bon
+ # 1 pour ouvrir la porte
+
+ #codes en statique pour les tests
+ #Dans l'avenir tout sera sous forme de fichiers
+ #si le fichier existe le code est bon (evite les problemes par rapport au fait de
+ # stocker les codes dans un fichier
+ if (password in ['123456','23']) or (password in os.listdir('/var/impression/codes')):
+ if password in os.listdir('/var/impression/codes'):
+ os.remove("/var/impression/codes/%s" %password)
+ return 1
+ else :
+ return 0
+
+if __name__ == '__main__' :
+ # on récupère le code dans les variables d'environement
+ try :
+ code = os.getenv('USER_PASSWORD','').replace('"','')
+ except :
+ code = ''
+
+ # test de l'authentification
+ if identification(code) :
+ # c'est bon
+ sys.exit(0)
+ else :
+ # c'est pas bon
+ sys.exit(1)