On gère l'urgence… À re-rendre générique plus tard…
[progfou.git] / coda / coda-filter.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 #
4 # Objectifs :
5 # 05. si le destinataire est noreply@auf.org, on le remplace par l'émetteur
6 # (ANNULÉ car ça ne devrait plus arriver)
7 # (REPRIS pour le cas où le destinataire est impression-coda@auf.org)
8 # 10. envoyer une copie à l'émetteur, sauf s'il est déjà le destinataire
9 # (ANNULÉ car envoi déjà vers les bons destinataires)
10 # 20. ajouter une en-tête X-Coda pour faciliter les filtrages
11 # 30. préfixer le sujet par '[CODA] '
12 # 40. remplacer l'organisation par AuF (forme longue, au lieu de CODA)
13 # 50. renommer l'attachement en utilisant le sujet
14 # Content-Type: application/pdf; name=attachment.pdf
15 # Content-Disposition: inline; filename=attachment.pdf
16 #
17 import sys
18 import email
19 from email.header import decode_header
20 import smtplib
21 import re
22
23 # préfixe pour le sujet
24 SUBJECT_PREFIX = "[CODA] "
25 # contenu pour l'en-tête X-Coda qui sera ajoutée
26 X_CODA_VALUE = "Filtre AuF pour Coda v2"
27 # contenu pour l'en-tête Organisation
28 ORGANIZATION = "Agence universitaire de la Francophonie"
29 # masque de repérage du type et numéro de document
30 DOC_PATTERN = r'^(.*:)?\s*(\S+)\s*/\s*(\d+)\s*$'
31 # format du nouveau nom de document (à partir du type et numéro)
32 DOC_FORMAT = 'CODA-%s-%08d.pdf'
33
34 # codes de sortie venant de <sysexits.h>
35 EX_TEMPFAIL = 75
36 EX_UNAVAILABLE = 69
37
38 # on récupère l'expéditeur et le(s) destinataire(s) en paramètres
39 #email_from = 'jca.test@auf.org'
40 email_from = sys.argv[1]
41 email_to_list = sys.argv[2:]
42
43 # on tente de récupérer le message arrivant sur l'entrée standard (pipe)
44 try:
45 msg = email.message_from_file(sys.stdin)
46 # en cas d'échec on demande à Postfix de considérer que c'est temporaire
47 except Exception, err:
48 print "Error: %s" % err
49 sys.exit(EX_TEMPFAIL)
50
51 #--------------------------------------------------------------------------
52 # TRAITEMENTS
53 #--------------------------------------------------------------------------
54
55 # 05. si le destinataire est noreply@auf.org, on le remplace par l'émetteur
56 # (ANNULÉ car ça ne devrait plus arriver)
57 # (REPRIS pour le cas où le destinataire est impression-coda@auf.org)
58 if 'impression-coda@auf.org' in email_to_list:
59 old_to = 'impression-coda@auf.org'
60 email_to_list.remove(old_to)
61 email_to_list.append(email_from)
62 msg.replace_header('To', email_from)
63 msg.add_header('X-Coda-Was-To', old_to)
64
65 # 10. on ajoute l'émetteur aux destinataires, sauf s'il est déjà le destinataire
66 # (ANNULÉ car envoi déjà vers les bons destinataires)
67 #if email_from not in email_to_list and not email_from.endswith('@ca.auf.org'):
68 # email_to_list.append(email_from)
69 # msg.add_header('Cc', email_from)
70
71 # 20. on ajoute une en-tête pour aider aux filtrages
72 msg.add_header('X-Coda', X_CODA_VALUE)
73
74 # 30. on préfixe le sujet actuel par '[CODA] '
75 subject = msg['Subject']
76 try:
77 parts = decode_header(subject)
78 subject = u' '.join([unicode(s, e or 'ascii') for s,e in parts])
79 except:
80 pass
81 msg.replace_header('Subject', SUBJECT_PREFIX + subject)
82
83 # 40. on remplace l'organisation par l'AuF
84 del msg['ORGANISATON'] # non, ce n'est pas une faute de frappe…
85 msg.add_header('Organization', ORGANIZATION)
86
87 # 50. on renomme l'attachement
88
89 # construction du nouveau nom de fichier
90 # on tente de repérer le type et numéro de document
91 try:
92 m = re.match(DOC_PATTERN, subject)
93 prefix, com_type, com_num = m.groups()
94 new_filename = DOC_FORMAT % (com_type, int(com_num))
95 # en cas d'échec on ignore le problème
96 except Exception, err:
97 print "Error: %s" % err
98 new_filename = 'document-coda.pdf'
99
100 # parcours des différentes parties du courriel
101 for part in msg.walk():
102 if part.get_content_type() != 'application/pdf':
103 continue
104 # adaptation du nom de fichier dans le Content-Type
105 try:
106 raw_param = part.get_param('name')
107 param = email.utils.collapse_rfc2231_value(raw_param)
108 if param == 'attachment.pdf':
109 part.set_param('name', new_filename)
110 except:
111 pass
112 # adaptation du nom de fichier dans le Content-Disposition
113 try:
114 raw_param = part.get_param('filename', header='Content-Disposition')
115 param = email.utils.collapse_rfc2231_value(raw_param)
116 if param == 'attachment.pdf':
117 part.set_param('filename', new_filename, header='Content-Disposition')
118 except:
119 pass
120
121 #--------------------------------------------------------------------------
122
123 # on se connecte à Postfix via le port de retour de filtrage
124 client = smtplib.SMTP('localhost', 10026)
125 #client.set_debuglevel(1)
126
127 # on tente d'envoyer le courriel modifié
128 try:
129 client.sendmail(email_from, email_to_list, msg.as_string())
130 # en cas d'échec on demande à Postfix de considérer que c'est temporaire
131 except Exception, err:
132 print "Error: %s" % err
133 sys.exit(EX_TEMPFAIL)
134
135 # on termine proprement
136 client.quit()
137 sys.exit(0)