2 # $Id: t-prot,v 1.218 2005/02/02 13:46:42 jochen Exp $
6 use Fcntl qw(O_EXCL O_WRONLY O_CREAT);
7 use Getopt::Mixed qw(nextOption);
8 use constant VER => '1.49';
9 use constant REV => '';
10 use constant REL => q$Revision: 1.218 $=~m/(\d+(?:\.\d+)+)/;
11 # MTA expecting mail on STDIN
12 # (you might have to adjust this if using a different MTA)
13 use constant SENDMAIL => '/usr/sbin/sendmail -oi';
15 # (you might have to adjust those if your libc wants different values)
16 use constant EX_OK => 0;
17 use constant EX_USAGE => 64;
18 use constant EX_DATAERR => 65;
19 use constant EX_UNAVAILABLE => 69;
20 use constant EX_IOERR => 74;
21 use constant EX_BOUNCE => EX_UNAVAILABLE;
23 $ad $ads $bigqn $bigqx $boun $check $check_ratio $cr $diff $elli
24 $footers $ftr_ad $ftr_ml $hdrs $indent $kamm $kdiff $kminl $kmaxl
25 $lax $lsig $maxsig $mda $ml $ms $ms_smart $msg_quote $msg_ratio
26 $mua $ofile $pgpshort $pgpmove $pgpmovevrf $sig $sigint $sign
27 $spass $spass_prefix $sysl $trad $trsp
29 $gpg_WARNING $gpg_Warning $gpg_Cantcheck $gpg_aka $gpg_bad
30 $gpg_expired $gpg_good $gpg_bug
32 $mutt_attachment $mutt_contenttype $mutt_pgpsigned $mutt_beginsigned
33 $mutt_pgpclearsigned $mutt_pgpclearsigstart $mutt_pgpencrypted
34 $mutt_pgpoutstart $mutt_pgpoutend
38 # Please adjust these vals to your needs (they are no constants because
39 # command line can change them or they are used in rexexp's):
41 $maxsig = 4; # max. valid signature length
42 $indent = '>'; # Indent string, regexp to identify a quoted line
43 $kminl = 65; # see decomb() for details
46 $pgpshort = 0; # hide pgp key ids if set
47 $pgpmove = 0; # move pgp output to bottom if set
49 $sign = 1; # max number of sigs tolerated, undef for no limit
50 $boun = "Blocked by $0: This user does not accept TOFUed email. Please see <http://learn.to/quote/> and <http://www.escape.de/users/tolot/mutt/> for more info. Have a nice day!\n";
51 $ftr_ad = undef; # too hard on performance to be default
52 $ftr_ml = undef; # too hard on performance to be default
53 $ofile = '-'; # use STDOUT if nothing is specified
54 $spass_prefix = 'SPAM: ';
55 $check_ratio = .75; # 3/4 tofu is enough not to accept the message
56 $msg_quote = "Blocked by $0: This message has been rejected because of a full quote. Please see http://learn.to/quote/ and http://www.escape.de/users/tolot/mutt/ for more info. Have a nice day!\n";
57 $msg_ratio = "Blocked by $0: This message has been rejected because of excessive quoting. Please see http://learn.to/quote/ and http://www.escape.de/users/tolot/mutt/ for more info. Have a nice day!\n";
58 # end of user adjusted vals
60 # mutt's locales as in mutt-1.3.28 up to mutt-1.4.2.1 {{{
61 my %mutt_attachment = (
62 'bg' => '[-- Ïðèêà÷åí ôàéë: #',
63 'ca' => '[-- Fitxer adjunt #',
64 'cs' => '[-- Pøíloha #',
65 'da' => '[-- Brevdel #',
66 'de' => '[-- Anhang #',
67 'el' => '[-- ÐñïóÜñôçóç #',
68 'eo' => '[-- Parto #',
69 'es' => '[-- Archivo adjunto #',
71 'fr' => '[-- Attachement #',
72 'gl' => '[-- Adxunto #',
73 'hu' => '[-- Melléklet #',
74 'id' => '[-- Lampiran #',
75 'it' => '[-- Allegato #',
76 'ja' => '[-- źÉÕ¥Õ¥¡¥¤¥ë #',
77 'ko' => '[-- ÷ºÎ¹° #',
78 'lt' => '[-- Priedas #',
79 'nl' => '[-- Bijlage #',
80 'pl' => '[-- Za³±cznik #',
81 'pt_BR' => '[-- Anexo No.',
82 'ru' => '[-- ÷ÌÏÖÅÎÉÅ #',
83 'sk' => '[-- Príloha #',
84 'sv' => '[-- Bilaga #',
85 'tr' => '[-- Eklenti #',
86 'uk' => '[-- äÏÄÁÔÏË ÎÏÍÅÒ ',
87 'zh_CN' => '[-- ¸½¼þ #',
90 my %mutt_contenttype = (
92 'ca' => '[-- Tipus: ',
95 'el' => '[-- Ôýðïò: ',
96 'eo' => '[-- Speco: ',
99 'fr' => '[-- Type : ',
100 'gl' => '[-- Tipo: ',
101 'hu' => '[-- Típus: ',
102 'id' => '[-- Jenis: ',
103 'it' => '[-- Tipo: ',
104 'ja' => '[-- ¥¿¥¤¥×: ',
105 'ko' => '[-- Á¾·ù: ',
106 'lt' => '[-- Tipas: ',
108 'pt_BR' => '[-- Tipo: ',
114 'zh_CN' => '[-- ÐÎ̬: ',
117 my %mutt_pgpsigned = (
118 'bg' => '[-- Êðàé íà ïîäïèñàíèòå äàííè --]',
119 'ca' => '[-- Final de les dades signades. --]',
121 'da' => '[-- Slut på underskrevne data --]',
122 'de' => '[-- Ende der signierten Daten --]',
123 'el' => '[-- ÔÝëïò äåäïìÝíùí õðïãåãñáììÝíùí --]',
124 'eo' => '[-- Fino de subskribitaj datenoj --]',
126 'et' => '[-- Allkirjastatud info lõpp --]',
127 'fr' => '[-- Fin des données signées --]',
130 'id' => '[-- Akhir data yang ditandatangani --]',
131 'it' => '[-- Fine dei dati firmati --]',
132 'ja' => '[-- ½ð̾¥Ç¡¼¥¿½ªÎ» --]',
133 'ko' => '[-- ¼¸í ÀÚ·á ³¡ --]',
136 'pl' => '[-- Koniec podpisanych danych --]',
138 'ru' => '[-- ëÏÎÅà ÐÏÄÐÉÓÁÎÎÙÈ ÄÁÎÎÙÈ --]',
140 'sv' => '[-- Slut på signerat data --]',
142 'uk' => '[-- ë¦ÎÅÃØ Ð¦ÄÐÉÓÁÎÉÈ ÄÁÎÉÈ --]',
146 my %mutt_beginsigned = (
147 'bg' => '[-- Ñëåäíèòå äàííè ñà ïîäïèñàíè --]',
148 'ca' => '[-- Les dades següents es troben signades: --]',
149 'cs' => '[-- Následují podepsaná data --]',
150 'da' => '[-- Følgende data er underskrevet --]',
151 'de' => '[-- Die folgenden Daten sind signiert --]',
152 'el' => '[-- Ôá åðüìåíá äåäïìÝíá åßíáé õðïãåãñáììÝíá --]',
153 'eo' => '[-- La sekvaj datenoj estas subskribitaj --]',
154 'es' => '[-- Los siguientes datos están firmados --]',
155 'et' => '[-- Järgnev info on allkirjastatud --]',
156 'fr' => '[-- Les données suivantes sont signées --]',
157 'gl' => '[-- Os datos a continuación están asinados --]',
158 'hu' => '[-- A következõ adatok alá vannak írva --]',
159 'id' => '[-- Data berikut ini ditandatangani --]',
160 'it' => '[-- I seguenti dati sono firmati --]',
161 'ja' => '[-- °Ê²¼¤Î¥Ç¡¼¥¿¤Ï½ð̾¤µ¤ì¤Æ¤¤¤ë --]',
162 'ko' => '[-- ¾Æ·¡ÀÇ ÀÚ·á´Â ¼¸í µÇ¾úÀ½ --]',
163 'lt' => '[-- Toliau einantys duomenys yra pasiraðyti --]',
164 'nl' => '[-- De volgende gegevens zijn PGP/MIME ondertekend --]',
165 'pl' => '[-- Poni¿sze dane s± podpisane --]',
166 'pt_BR' => '[-- Os dados a seguir estão assinados --]',
167 'ru' => '[-- îÁÞÁÌÏ ÐÏÄÐÉÓÁÎÎÙÈ ÄÁÎÎÙÈ --]',
168 'sk' => '[-- Nasledujúce dáta sú podpísané s PGP/MIME --]',
169 'sv' => '[-- Följande data är signerat --]',
170 'tr' => '[-- Bu bilgi imzalanmýþtýr --]',
171 'uk' => '[-- îÁÓÔÕÐΦ ÄÁΦ ЦÄÐÉÓÁÎÏ --]',
172 'zh_CN' => '[-- ÒÔϵÄ×ÊÁÏÒѱ»Ç©Êð --]',
173 'zh_TW' => '[-- 以下的資料已被簽署 --]',
175 my %mutt_pgpencrypted = (
176 'bg' => '[-- Êðàé íà PGP/MIME øèôðîâàíèòå äàííè --]',
177 'ca' => '[-- Final de les dades xifrades amb PGP/MIME. --]',
179 'da' => '[-- Slut på PGP/MIME-krypteret data --]',
180 'de' => '[-- Ende der PGP/MIME-verschlüsselten Daten --]',
181 'el' => '[-- ÔÝëïò äåäïìÝíùí êñõðôïãñáöçìÝíùí ìÝóù PGP/MIME --]',
182 'eo' => '[-- Fino de PGP/MIME-æifritaj datenoj --]',
184 'et' => '[-- PGP/MIME krüptitud info lõpp --]',
185 'fr' => '[-- Fin des données chiffrées avec PGP/MIME --]',
188 'id' => '[-- Akhir data yang dienkripsi dg PGP/MIME --]',
189 'it' => '[-- Fine dei dati cifrati con PGP/MIME --]',
190 'ja' => '[-- PGP/MIME°Å¹æ²½¥Ç¡¼¥¿½ªÎ» --]',
191 'ko' => '[-- PGP/MIME ¾ÏÈ£È ÀÚ·á ³¡ --]',
194 'pl' => '[-- Koniec danych zaszyfrowanych PGP/MIME --]',
196 'ru' => '[-- ëÏÎÅà ÄÁÎÎÙÈ, ÚÁÛÉÆÒÏ×ÁÎÎÙÈ × ÆÏÒÍÁÔÅ PGP/MIME --]',
198 'sv' => '[-- Slut på data krypterad enligt PGP/MIME --]',
200 'uk' => '[-- ë¦ÎÅÃØ ÄÁÎÉÈ, ÚÁÛÉÆÒÏ×ÁÎÉÈ PGP/MIME --]',
204 my %mutt_pgpclearsigned = (
205 'bg' => '[-- ÊÐÀÉ ÍÀ PGP-ÏÎÄÏÈÑÀÍÎÒÎ ÏÈÑÌÎ --]',
206 'ca' => '[-- TERMINA EL MISSATGE PGP SIGNAT --]',
208 'el' => '[-- ÔÅËÏÓ ÕÐÏÃÅÃÑÁÌÌÅÍÏÕ PGP ÌÇÍÕÌÁÔÏÓ --]',
209 'eo' => '[-- FINO DE PGP-SUBSKRIBITA MESAØO --]',
211 'et' => '[-- PGP ALLKIRJASTATUD TEATE LÕPP --]',
212 'fr' => '[-- FIN DE MESSAGE SIGNÉ PGP --]',
215 'id' => '[-- AKHIR PESAN DG TANDATANGAN PGP --]',
216 'it' => '[-- FINE DEL MESSAGGIO FIRMATO CON PGP --]',
217 'ja' => '[-- PGP½ð̾¥á¥Ã¥»¡¼¥¸½ªÎ» --]',
218 'ko' => '[-- PGP ¼¸í ¸ÞÀÏ ³¡ --]',
221 'pl' => '[-- KONIEC LISTU PODPISANEGO PGP --]',
223 'ru' => '[-- ëÏÎÅà ÓÏÏÂÝÅÎÉÑ, ÐÏÄÐÉÓÁÎÎÏÇÏ PGP --]',
225 'sv' => '[-- SLUT PÅ MEDDELANDE SIGNERAT MED PGP --]',
227 'uk' => '[-- ë¦ÎÅÃØ ÐÏצÄÏÍÌÅÎÎÑ Ú PGP ЦÄÐÉÓÏÍ --]',
231 my %mutt_pgpclearsigstart = (
232 'bg' => '[-- ÍÀ×ÀËÎ ÍÀ PGP-ÏÎÄÏÈÑÀÍÎÒÎ ÏÈÑÌÎ --]',
233 'ca' => '[-- COMENÇA EL MISSATGE PGP SIGNAT --]',
234 'cs' => '[-- ZAÈÁTEK PODEPSANÉ PGP ZPRÁVY --]',
235 'el' => '[-- ÅÍÁÑÎÇ ÕÐÏÃÅÃÑÁÌÌÅÍÏÕ PGP ÌÇÍÕÌÁÔÏÓ --]',
236 'eo' => '[-- KOMENCO DE PGP-SUBSKRIBITA MESAØO --]',
237 'es' => '[-- PRINCIPIO DEL MENSAJE FIRMADO CON PGP --]',
238 'et' => '[-- PGP ALLKIRJASTATUD TEATE ALGUS --]',
239 'fr' => '[-- DÉBUT DE MESSAGE SIGNÉ PGP --]',
240 'gl' => '[-- COMEZA A MESAXE FIRMADA CON PGP --]',
241 'hu' => '[-- PGP ALÁÍRT LEVÉL KEZDÕDIK --]',
242 'id' => '[-- AWAL SURAT DG TANDATANGAN PGP --]',
243 'it' => '[-- INIZIO DEL MESSAGGIO FIRMATO CON PGP --]',
244 'ja' => '[-- PGP½ð̾¥á¥Ã¥»¡¼¥¸³«»Ï --]',
245 'ko' => '[-- PGP ¼¸í ¸ÞÀÏ ½ÃÀÛ --]',
246 'lt' => '[-- PGP PASIRAÐYTO LAIÐKO PRADÞIA --]',
247 'nl' => '[-- BEGIN PGP ONDERTEKEND BERICHT --]',
248 'pl' => '[-- POCZ¡TEK LISTU PODPISANEGO PGP --]',
249 'pt_BR' => '[-- INÍCIO DE MENSAGEM ASSINADA POR PGP --]',
250 'ru' => '[-- îÁÞÁÌÏ ÓÏÏÂÝÅÎÉÑ, ÐÏÄÐÉÓÁÎÎÏÇÏ PGP --]',
251 'sk' => '[-- ZAÈIATOK SPRÁVY PODPÍSANEJ S PGP --]',
252 'sv' => '[-- MEDDELANDE SIGNERAT MED PGP BÖRJAR --]',
253 'tr' => '[-- PGP IMZALANMIÞ ILETI BAÞI --]',
254 'uk' => '[-- ðÏÞÁÔÏË ÐÏצÄÏÍÌÅÎÎÑ Ú PGP ЦÄÐÉÓÏÍ --]',
255 'zh_CN' => '[-- PGP Ç©ÃûµÄÐżþ¿ªÊ¼ --]',
256 'zh_TW' => '[-- PGP 簽名的信件開始 --]'
258 my %mutt_pgpoutstart = (
259 'bg' => '[-- ñëåäâà ðåçóëòàòà îò PGP (òåêóùî âåìå: ',
260 'ca' => '[-- Aquesta és l\'eixida de PGP (data actual: ',
261 'cs' => '[-- následuje výstup PGP (aktuální èas: ',
262 'da' => '[-- PGP-uddata følger (aktuelt tidspunkt: ',
263 'de' => '[-- PGP-Ausgabe folgt (aktuelle Zeit: ',
264 'el' => '[-- Áêïëïõèåß Ýîïäïò ôïõ PGP (ôñÝ÷ïõóá þñá: ',
265 'eo' => '[-- Eligo de PGP sekvas (nuna horo: ',
266 'es' => '[-- Salida de PGP a continuación (tiempo actual: ',
267 'et' => '[-- järgneb PGP väljund (praegune aeg: ',
268 'fr' => '[-- La sortie PGP suit (heure courante : ',
269 'gl' => '[-- Saída PGP a continuación (hora actual: ',
270 'hu' => '[-- PGP kimenet következik (idõ: ',
271 'id' => '[-- Keluaran dari PGP (waktu skrg: ',
272 'it' => '[-- Segue l\'output di PGP (ora attuale: ',
273 'ja' => '[-- PGP ½ÐÎϤϰʲ¼¤ÎÄ̤ê (¸½ºß»þ¹ï: ',
274 'ko' => '[-- PGP Ãâ·Â (ÇöÀç ½Ã°£: ',
275 'lt' => '[-- Toliau PGP iðvestis (esamas laikas: ',
276 'nl' => '[-- PGP uitvoer volgt (Huidige tijd: ',
277 'pl' => '[-- Wynik dzia³ania PGP (bie¿±ca data i czas: ',
278 'pt_BR' => '[-- Saída do PGP a seguir (hora atual: ',
279 'ru' => '[-- òÅÚÕÌØÔÁÔ ÒÁÂÏÔÙ ÐÒÏÇÒÁÍÍÙ PGP (ÔÅËÕÝÅÅ ×ÒÅÍÑ: ',
280 'sk' => '[-- Nasleduje výstup PGP (aktuálny èas: ',
281 'sv' => '[-- Utdata från PGP följer (aktuell tid: ',
282 'tr' => '[-- PGP geri verisi (geçerli zaman: ',
283 'uk' => '[-- ÔÅËÓÔ ÎÁ ×ÉÈÏĦ PGP (ÞÁÓ: ',
284 'zh_CN' => '[-- ÒÔÏÂΪ PGP Êä³öµÄ×ÊÁÏ£¨ÏÖÔÚʱ¼ä£º ',
285 'zh_TW' => '[-- 以下為 PGP 輸出的資料(現在時間:'
287 my %mutt_pgpoutend = (
288 'bg' => '[-- Êðàé íà PGP-ðåçóëòàòà --]',
289 'ca' => '[-- Final de l\'eixida de PGP. --]',
290 'cs' => '[-- Konec výstupu PGP --]',
291 'da' => '[-- Slut på PGP-uddata --]',
292 'de' => '[-- Ende der PGP-Ausgabe --]',
293 'el' => '[-- ÔÝëïò ôçò åîüäïõ PGP --]',
294 'eo' => '[-- Fino de PGP-eligo --]',
295 'es' => '[-- Fin de salida PGP --]',
296 'et' => '[-- PGP väljundi lõpp --]',
297 'fr' => '[-- Fin de sortie PGP --]',
298 'gl' => '[-- Fin da saída PGP --]',
299 'hu' => '[-- PGP kimenet vége --]',
300 'id' => '[-- Akhir keluaran PGP --]',
301 'it' => '[-- Fine dell\'output di PGP --]',
302 'ja' => '[-- PGP½ÐÎϽªÎ» --]',
303 'ko' => '[-- PGP Ãâ·Â ³¡ --]',
304 'lt' => '[-- PGP iðvesties pabaiga --]',
305 'nl' => '[-- Einde van PGP uitvoer --]',
306 'pl' => '[-- Koniec komunikatów PGP --]',
307 'pt_BR' => '[-- Fim da saída do PGP --]',
308 'ru' => '[-- ëÏÎÅà ×Ù×ÏÄÁ ÐÒÏÇÒÁÍÍÙ PGP --]',
309 'sk' => '[-- Koniec výstupu PGP --]',
310 'sv' => '[-- Slut på utdata från PGP --]',
311 'tr' => '[-- PGP geri verisi sonu --]',
312 'uk' => '[-- ë¦ÎÅÃØ ÔÅËÓÔÕ ÎÁ ×ÉÈÏĦ PGP --]',
313 'zh_CN' => '[-- PGP Êä³ö²¿·Ý½áÊø --]',
314 'zh_TW' => '[-- PGP 輸出部份結束 --]'
317 # set the defaults to the C locale
318 $mutt_attachment = '[-- Attachment #';
319 $mutt_contenttype = '[-- Type: ';
320 $mutt_pgpsigned = '[-- End of signed data --]';
321 $mutt_beginsigned = '[-- The following data is signed --]';
322 $mutt_pgpclearsigstart = '[-- BEGIN PGP SIGNED MESSAGE --]';
323 $mutt_pgpclearsigned = '[-- END PGP SIGNED MESSAGE --]';
324 $mutt_pgpencrypted = '[-- End of PGP/MIME encrypted data --]';
325 $mutt_pgpoutstart = '[-- PGP output follows (current time:';
326 $mutt_pgpoutend = '[-- End of PGP output --]';
328 # gpg's locales as in gpg-1.4.0 {{{
332 'cs' => 'VAROVÁNÍ: ',
333 'da' => 'ADVARSEL: ',
335 'el' => 'ÐÑÏÅÉÄÏÐÏÉÇÓÇ: ',
337 'es' => 'ATENCIÓN: ',
339 'fi' => 'VAROITUS: ',
340 'fr' => 'ATTENTION: ',
342 'hu' => 'FIGYELEM: ',
343 'id' => 'PERINGATAN: ',
344 'it' => 'ATTENZIONE: ',
346 'pl' => 'OSTRZE¯ENIE: ',
348 'pt_BR' => 'AVISO: ',
349 'ro' => 'AVERTISMENT: ',
350 'ru' => 'ВНИМАНИЕ: ',
351 'sk' => 'VAROVANIE: ',
354 'zh_CN' => '警告:我们不信任这把密钥!',
355 'zh_TW' => 'ĵ§i¡G§ÚÌ *¤£* «H¥ô³o§âª÷Æ_¡I'
360 'cs' => 'VAROVÁNÍ: ',
363 'el' => 'ÐÑÏÅÉÄÏÐÏÉÇÓÇ: ',
365 'es' => 'ATENCIÓN: ',
367 'fi' => 'VAROITUS: ',
368 'fr' => 'AVERTISSEMENT: ',
370 'hu' => 'FIGYELEM: ',
371 'id' => 'PERINGATAN: ',
372 'it' => 'ATTENZIONE: ',
374 'pl' => 'OSTRZE¯ENIE: ',
376 'pt_BR' => 'CUIDADO: ',
377 'ro' => 'AVERTISMENT: ',
378 'ru' => 'ВНИМАНИЕ: ',
379 'sk' => 'VAROVANIE: ',
382 'zh_CN' => '警告:加密过的报文已经变造!',
383 'zh_TW' => 'ĵ§i¡G¥[±K¹Lªº°T®§¤w¸g³QÅܳy¤F¡I'
385 my %gpg_Cantcheck = (
387 'ca' => 'No sha pogut comprovar la signatura: ',
388 'cs' => 'Nemohu ovìøit podpis: ',
389 'da' => 'Kan ikke tjekke signatur: ',
390 'de' => 'Unterschrift kann nicht geprüft werden: ',
391 'el' => 'Áäõíáìßá åëÝã÷ïõ ôçò õðïãñáöÞò: ',
392 'eo' => 'Ne povas kontroli subskribon: ',
393 'es' => 'Imposible comprobar la firma: ',
394 'et' => 'Allkirja ei saa kontrollida: ',
395 'fi' => 'Allekirjoitusta ei voi tarkistaa: ',
396 'fr' => 'Impossible de vérifier la signature: ',
397 'gl' => 'Non foi posible verifica-la sinatura: ',
398 'hu' => 'Nem tudom ellenõrizni az aláírást: ',
399 'id' => 'Tidak dapat memeriksa signature: ',
400 'it' => 'Impossibile controllare la firma: ',
401 'ja' => '½ð̾¤ò¸¡ºº¤Ç¤¤Þ¤»¤ó: ',
402 'pl' => 'Nie mo¿na sprawdziæ podpisu: ',
403 'pt' => 'Impossível verificar assinatura: ',
404 'pt_BR' => 'Impossível verificar assinatura: ',
405 'ro' => 'Nu pot verifica semnãtura: ',
406 'ru' => 'Не могу проверить подпись: ',
407 'sk' => 'Nemô¾em overi» podpis: ',
408 'sv' => 'Kan inte verifiera signaturen: ',
409 'tr' => 'İmza kontrol edilemedi: ',
410 'zh_CN' => '无法检查签字:',
411 'zh_TW' => 'µLªkÀˬdñ³¹¡G '
419 'el' => ' ãíùóôü óáí ',
433 'sv' => ' även känd som ',
439 'be' => 'нерэчаісны хэш-альгарытм ',
440 'ca' => 'Signatura INCORRECTA de ',
441 'cs' => '©PATNÝ podpis od ',
442 'da' => 'DÅRLIG signatur fra ',
443 'de' => 'FALSCHE Unterschrift von ',
444 'el' => 'ÊÁÊÇ õðïãñáöÞ áðü ',
445 'eo' => 'MALBONA subskribo de ',
446 'es' => 'Firma INCORRECTA de ',
447 'et' => 'HALB allkiri kasutajalt ',
448 'fi' => 'VÄÄRÄ allekirjoitus lähettäjältä ',
449 'fr' => 'MAUVAISE signature de « ',
450 'gl' => 'Sinatura INCORRECTA de',
451 'hu' => 'ROSSZ aláírás a következõtõl: ',
452 'id' => 'signature BURUK dari ',
453 'it' => 'Firma NON corretta da ',
455 'pl' => 'NIEPOPRAWNY podpis z³o¿ony przez ',
456 'pt' => 'Assinatura INCORRECTA de ',
457 'pt_BR' => 'Assinatura INCORRETA de ',
458 'ro' => 'Semnãturã INCORECTÃ din ',
459 'ru' => 'ПЛОХАЯ подпись от ',
460 'sk' => 'ZLÝ podpis od ',
461 'sv' => 'FELAKTIG signatur från ',
462 'tr' => 'KÖTÜ imza: ',
463 'zh_CN' => '已损坏的签字,来自于“',
464 'zh_TW' => '*·lÃa* ªºÃ±³¹¨Ó¦Û©ó '
468 'ca' => 'Nota: La clau ha caducat!',
469 'cs' => 'Poznámka: Skonèila platnost tohoto klíèe!',
470 'da' => 'Bemærk: Denne nøgle er forældet!',
471 'de' => 'Hinweis: Dieser Schlüssel ist verfallen!',
472 'el' => 'Óçìåßùóç: Áõôü ôï êëåéäß Ý÷åé ëÞîåé!',
473 'eo' => 'Noto: Æi tiu þlosilo eksvalidiøis!',
474 'es' => 'Nota: ¡Esta clave ha caducado!',
475 'et' => 'Märkus: See võti on aegunud!',
476 'fi' => 'Huom: Tämä avain on vanhentunut!',
477 'fr' => 'Note: Cette clé a expiré !',
478 'gl' => 'Nota: ¡Esta chave xa caducou!',
479 'hu' => 'Megjegyzés: Ez a kulcs lejárt!',
480 'id' => 'Catatan: Kunci ini telah berakhir!',
481 'it' => 'Nota: questa chiave è scaduta!',
482 'ja' => 'Ãí°Õ: ¤³¤Î¸°¤ÏËþλ¤Ç¤¹!',
483 'pl' => 'Uwaga: Data wa¿no¶ci tego klucza up³ynê³a!',
484 'pt' => 'Nota: Esta chave expirou!',
485 'pt_BR' => 'Nota: Esta chave expirou!',
486 'ro' => 'Notã: Aceastã cheie a expirat!',
487 'ru' => 'ПРЕДУПРЕЖДАЮ: Данный ключ просрочен!',
488 'sk' => 'Poznámka: Skonèila platnos» tohto kµúèa!',
489 'sv' => 'Obs: Giltighetstiden för denna nyckel har gått ut!',
490 'tr' => 'Bilgi: Bu anahtarın kullanım süresi dolmuştu!',
491 'zh_CN' => '注意:这把密钥已经过期了!',
492 'zh_TW' => '½Ðª`·N¡G³o§âª÷Æ_¤w¸g¹L´Á¤F¡I'
495 'be' => 'нерэчаісны хэш-альгарытм ',
496 'ca' => 'Signatura correcta de ',
497 'cs' => 'Dobrý podpis od ',
498 'da' => 'God signatur fra ',
499 'de' => 'Korrekte Unterschrift von ',
500 'el' => 'ÊáëÞ õðïãñáöÞ áðü ',
501 'eo' => 'Bona subskribo de ',
502 'es' => 'Firma correcta de ',
503 'et' => 'Korrektne allkiri kasutajalt ',
504 'fi' => 'Allekirjoitus täsmää lähettäjään ',
505 'fr' => 'Bonne signature de « ',
506 'gl' => 'Sinatura correcta de ',
507 'hu' => 'Jó aláírás a következõtõl: ',
508 'id' => 'Signature baik dari ',
509 'it' => 'Firma valida da ',
511 'pl' => 'Poprawny podpis z³o¿ony przez ',
512 'pt' => 'Assinatura correcta de ',
513 'pt_BR' => 'Assinatura correta de ',
514 'ro' => 'Semnãturã bunã din ',
515 'ru' => 'Действительная подпись от ',
516 'sk' => 'Dobrý podpis od ',
517 'sv' => 'Korrekt signatur från ',
518 'tr' => 'Kullanıcı kimliği: ',
519 'zh_CN' => '完好的签字,来自于“',
520 'zh_TW' => '§¹¦nªºÃ±³¹¨Ó¦Û©ó '
524 'ca' => '... a�� �s un bug (',
525 'cs' => '... toto je chyba v programu (',
526 'da' => '... dette er en fejl (',
527 'de' => '... dies ist ein Bug (Programmfehler) (',
528 'el' => '... áõôü åßíáé bug (',
529 'eo' => '... æi tio estas cimo (',
530 'es' => '... esto es un bug (',
531 'et' => '... see on viga (',
532 'fi' => '...tämä on ohjelmistovika (',
533 'fr' => '... cest un bug (',
534 'gl' => '... isto é un erro (',
535 'hu' => 'Ez egy programhiba... (',
536 'id' => '... kesalahan (',
537 'it' => '... questo è un bug (',
538 'ja' => '... ¥Ð¥°¤Ç¤¹ (',
539 'pl' => '... to jest b³±d programu (',
540 'pt' => '... isto é um bug (',
541 'pt_BR' => '... isto é um bug (',
542 'ro' => '... acesta este un bug (',
543 'ru' => ' ... это ошибка (',
544 'sk' => '... toto je chyba v programe (',
545 'sv' => '... detta är ett fel i programmet (',
546 'tr' => '... bu bir yazılım hatası (',
547 'zh_CN' => '……这是个程序缺陷(',
548 'zh_TW' => '... ³o¬Oӷ岫 ('
551 # set the defaults to the C locale
552 $gpg_WARNING = 'WARNING: ';
553 # (yes, the translations in gnupg's po files *are* braindamaged):
554 $gpg_Warning = 'WARNING: ';
555 $gpg_Cantcheck = 'Can\'t check signature: ';
557 $gpg_bad = 'BAD signature from ';
558 $gpg_expired = 'Note: This key has expired!';
559 $gpg_good = 'Good signature from';
560 # (actually, this bugs me quite often since upgrading gpg from v1.0.7):
561 $gpg_bug = '... this is a bug (';
564 # help(): print help text and exit with appropriate exit code
566 print "Usage: $0 [options]
567 -a remove ad footers; requires -A
568 -A=DIRECTORY ad footer directory, treat ad footers as signature
569 --bigq[=n[,x]] remove all but x lines of quotes with more than n
570 lines; default is n=30 and x=10
571 -c merge multiple blank lines
572 --check[=FLAGS] check various criteria, print error message and quit;
573 see man page for details
574 -d, --debug print notice to syslog when bouncing; requires -p
575 --diff tolerate diffs appended *after* the signature
576 -e force ellipsis for excessive punctuation
577 --ftr-ad enable aggressive ad footer matching; requires -A
578 --ftr-ml enable aggressive mailing list footer matching; req. -L
579 -h, --help show this short help and exit
580 -i=INFILE file to be read; '-' for STDIN (default)
581 -k try to fix \"Kammquotes\"
582 --kminl=n min. line length for wrapped line; requires -k
583 --kmaxl=n max. line length for wrapped line; requires -k
584 --kdiff=n max. length difference between wrapped lines; req. -k
585 -L=DIRECTORY mailling list footer directory, treat mailing list
587 -l delete mailing list footer; requires -L
588 --lax-security use unsafe writing method; USE ON YOUR OWN RISK!
589 --locale=LOCALE internationalization; currently only used with -Mmutt
590 -M, --mua=MUA turn on special treatment for some mail user agents
591 -m delete MS style TOFU; careful: might be too agressive
592 --ms-smart try to be smart with MS style TOFU; req. -Mmutt and -m
593 -o=OUTFILE file to be written to; '-' for STDOUT (default), 'NONE'
595 -P=MESSAGE user defined bounce message; requires -p
596 -p[=ADDRESS] redirect to ADDRESS if no TOFU was found
597 --pgp-move move pgp verification output to bottom; requires -Mmutt
598 --pgp-move-vrf move pgp output if verified and good; requires -Mmutt
599 --pgp-short hide non-relevant pgp key uids; requires -Mmutt
600 -r delete mail header lines
601 -S[=n] supress signatures with more than n lines;
602 default is $maxsig if n not specified
604 --sigsmax[=n] max number of sigs tolerated, no value for unlimited
605 --spass enable SpamAssassin workaround
606 -t delete traditional style TOFU
607 -v, --version show version string and exit
608 -w delete trailing whitespaces\n";
612 # version(): print version info and exit with appropriate exit code
614 print "$0 v".VER.REV." (Rev. ".REL."), Jochen Striepe <t-prot\@tolot.escape.de>
615 Get the latest version at <http://www.escape.de/users/tolot/mutt/>\n";
619 # sigint_handler(): what to do if we receive a single SIGINT
624 # esc(): escapes a scalar reference for use in perl regexp
625 sub esc { ${$_[0]} =~ s/([\[\]\(\)\*\.\-\^\$\@])/\\$1/go; }
627 # remove_footers(): remove any trailing appearance of footers contained
628 # in the given directory.
630 my $L = shift; # array of message lines
631 my $S = shift; # array to store removed lines in
632 my $F = shift; # footers dir name
633 my $O = shift; # remove only one footer?
634 my $V = shift; # allow footers match before end of message
638 for ($off = 0; $#$L>=$off && $$L[$#$L-$off] =~ /^\s*$/; $off++) {;};
641 if ($F && scalar(@$L)) {
642 if (!opendir(DIR, $F)) { print STDERR "Could not open $F: $!\n"; exit(EX_IOERR); }
643 my @feet = grep { /^[^.]/ && -f "$F/$_" } readdir DIR;
646 foreach my $f (@feet) {
647 if (!open(IN, "$F/$f")) { print STDERR "Could not open $F/$f: $!\n"; exit(EX_IOERR); }
651 if (!scalar(@l)) { next; }
652 for (my $z=0; $z<=$#l; $z++) { chomp($l[$z]); }
655 WIPE: for (my $z=scalar(@$L)-scalar(@l); $z>=0; $z--)
657 if (scalar(@l)+$z<=scalar(@$L)) {
659 for(my $x=1; $x<=scalar(@l); $x++) {
660 if (index($$L[scalar(@$L)-$x-$z], $l[scalar(@l)-$x])!=0) {
665 unshift(@$S, @$L[$#$L-$#l-$z..$#$L]);
666 splice(@$L, $#$L-$#l-$z);
667 while (scalar(@$L) && $$L[$#$L] =~ /^\s*$/) {
668 unshift(@$S, pop(@$L));
670 if ($O) { last; } else { goto WIPE; }
676 while (scalar(@l)<=scalar(@$L)) {
677 for(my $x=1; $x<=scalar(@l); $x++) {
678 if (index($$L[scalar(@$L)-$x-$off], $l[scalar(@l)-$x])!=0) {
682 unshift(@$S, @$L[$#$L-$off-$#l..$#$L]);
683 splice(@$L, $#$L-$off-$#l);
684 while (scalar(@$L) && $$L[$#$L] =~ /^\s*$/) {
685 unshift(@$S, pop(@$L));
695 # decomb(): Try to detect and fix zig-zag shaped quoting (a.k.a. German
698 my $L = shift; # array of message lines
699 my $V = shift; # array with verbatim list
700 my $max = 0; # plausible wraparound pos
702 # We scan the whole message first for a plausible common maximum line
703 # length where longer lines would be wrapped.
704 for (my $x=0; $x<$#$L; $x++) {
705 if ($$V[$x]!=1 && $max<length($$L[$x])) { $max = length($$L[$x]); }
708 # Next we see if there are plausible wraparounds.
709 for (my $x=0; $x+1<$#$L; $x++) {
712 # * it must not be verbatim,
713 # * the 2nd line must not be quoted nor empty nor just
714 # underlining some part of the line above (using '^')
715 # nor begin with a whitespace,
716 # * the 1st line must not end with a hyphen,
717 # * the 2nd line must not be some mutt(1) commentary,
718 # * there must not be a valid word wrap to produce a longer
719 # 1st line (if not quoted),
720 # * the 1st and 2nd line together must not be longer than some
721 # magical upper limit nor shorter than some magical lower
722 # bound nor nearly of the same length, and
723 # * the 3rd line must not be empty.
724 # With all that odds should be quite good that we have an
725 # automatedly wrapped line. Please send a note if you have
726 # additional good criteria. Thanks.
727 if (($$V[$x]!=1 && $$V[$x+1]!=1) &&
728 (index($$L[$x+1], $indent)!=0) &&
729 ($$L[$x+1] !~ /^$/) &&
730 ($$L[$x+1] !~ /^[\s^]/) &&
732 ($mua ne 'mutt' || $$L[$x+1] !~ /^(?:\e.+?\a)?\[-- .* --]/) &&
733 (length($$L[$x])+index($$L[$x+1], ' ')>$max ||
734 (index($$L[$x+1], ' ')<0 && length($$L[$x])+length($$L[$x+1])>$max)) &&
735 (length($$L[$x])+length($$L[$x+1])<$kmaxl) &&
736 (length($$L[$x])+length($$L[$x+1])>$kminl) &&
737 (length($$L[$x])-length($$L[$x+1])>$kdiff) &&
738 ($$L[$x+2] !~ /^\s*$/))
740 $$L[$x] =~ s/\s*$/' ' . $$L[$x+1]/e;
741 splice(@$L, $x+1, 1);
742 splice(@$V, $x+1, 1);
747 # debigq(): Finds big quotes (more than $n lines quoted) and deletes all
748 # but $x lines of them.
750 my $L = shift; # array of message lines
751 my $V = shift; # array with verbatim list
754 for (my $i=0; $i<=$#$L; $i++) {
761 if (index($$L[$i], $indent)==0) { $k++; } else {
766 $$L[$i] = "[---=| Quote block shrinked by $0: " .
767 "$x lines snipped |=---]\n";
769 splice(@$L, $i, $x-1);
770 splice(@$V, $i, $x-1);
779 # pgp(): treat mutt(1)'s pgp/gpg output contained in signed or encrypted
784 my $L = shift; # message body
785 my $X = shift; # start line
786 my $Z = shift; # end line
791 if ($$L[$X] =~ /^gpg:\s(?:$gpg_WARNING|$gpg_Warning|$gpg_bad|$gpg_Cantcheck|$gpg_expired)/o)
793 if ($$L[$X] =~ /^gpg:\s$gpg_bug/o)
795 if ($$L[$X] =~ /^gpg:\s$gpg_good/o)
803 my $L = shift; # message body
804 my $V = shift; # verbatim list
805 my $H = shift; # headers
810 for (my $x=0; $x<scalar(@$L); $x++) {
811 if ($$V[$x]) { next; }
813 if ($$L[$x]=~/^(?:\e.+?\a)?(?:$mutt_pgpoutstart)/o)
816 for (my $m=0; $m<scalar(@$H); $m++) {
817 if ($$H[$m] =~ /^From:/) {
820 while ($$H[$m] =~ /^\s/) { $from .= $$H[$m]; $m++; }
824 ($from) = $from=~m/([a-z\d][a-z_\d\+-\.]*\@(?:[a-z_\d\+-\.]+\.)+[a-z]{2,})/i;
829 for (my $i=$x+1; $i<scalar(@$L); $i++) {
830 if ($pgpshort && $$L[$i] =~ /^gpg:\s$gpg_aka/o) { $uid++; }
832 if ($pgpshort && $uid>1 &&
833 $$L[$i] =~ /^gpg:\s$gpg_aka/o && $$L[$i] !~ /$from/)
839 elsif ($$L[$i]=~/^(?:\e.+?\a)?(?:$mutt_pgpoutend)/o)
842 ($pgpmovevrf && (!$sigint) && verified($L, $x+1, $i)))
844 push(@{$tmp[++$tmp]}, "\n", @$L[$x..($i+1)]);
845 splice(@$L, $x, $i-$x+2);
846 splice(@$V, $x, $i-$x+2);
847 $i -= $#{$tmp[$tmp]}-2;
855 $$L[$x]=~/^(?:\e.+?\a)?(?:$mutt_pgpencrypted|$mutt_pgpclearsigned|$mutt_pgpsigned)/o)
857 splice(@$L, $x+1, 0, @{$tmp[$tmp]});
858 for (my $i=$x; $i<scalar(@{$tmp[$tmp]}); $i++) {
859 splice(@$V, $x+1, 0, (0));
861 $x += scalar(@{$tmp[$tmp--]});
867 push(@$L, @{$tmp[$tmp--]});
869 for (my $i=$#$V; $i<$#$L; $i++) { push(@$V, 0); }
873 # write_msg(): output
878 if ((!$lax) && ($O =~ /^>(.*)/) && ($1 ne '-')) {
879 if (!sysopen(OUT, $1, O_EXCL|O_CREAT|O_WRONLY)) {
880 print STDERR "Could not open $1: $!\n"; exit(EX_IOERR);
883 elsif (!open(OUT, $O)) {
884 print STDERR "Could not open $O: $!\n"; exit(EX_IOERR);
897 # process_msg(): This one proc does *everything* what has to be done with
898 # the lines of the message
902 my ($j, $x, $verb) = (0, 0, 0);
903 my (@ads, @hdr, @bo1, @bo2, @ftr, @sig, @vrb, @att) =
904 ((), (), (), (), (), (), (), (), ());
906 # First, remove and store lines we might need later...
908 for ($x=0; $x<$#$lines; $x++) { if (@$lines[$x] =~ /^$/) { last; }; }
909 @hdr = @$lines[0..$x];
910 splice(@$lines, 0, $x+1);
911 # remember the original body lines count
912 my $linecount = scalar(@$lines);
915 # See if we have a multipart content type. If yes, see if it is already
916 # ripped (e.g. by mutt(1)), otherwise only leave the first part if it
917 # is plain text (if not, we are done - non-text messages are not our
919 if ($mua ne 'mutt') {
920 for ($x=0; $x<scalar(@hdr); $x++) {
921 if ($hdr[$x] =~ /^Content-Type:\s+(.*)$/i) {
924 if ($foo =~ /^multipart\//i) {
927 if ($hdr[$x] =~ /\Wboundary="([^"]+)"/i) { $foo = $1; }
929 for (my $z=1; $x+$z<@hdr && $hdr[$x+$z]=~/^\s/; $z++) {
930 if ($hdr[$x] =~ /\Wboundary="?([^"\s]+)"?$/i) {
938 for (my $x=0; $x<scalar(@$lines); $x++) {
939 if (index($$lines[$x], '--'.$foo)!=0) { next; }
941 my $bar = 'text/plain';
942 for ($x++; $x<@$lines && $$lines[$x]!~/^$/; $x++)
944 if ($$lines[$x] =~ /^Content-Type:\s+(.*)/i) {
948 if ($x>=scalar(@$lines)) { exit(EX_DATAERR); }
950 if ($bar =~ /^text\/plain/i) {
952 for ($z=1; $x+$z<@$lines; $z++) {
953 if (index($$lines[$x+$z], '--'.$foo)==0) {
957 if ($x+$z>=scalar(@$lines)) { exit(EX_DATAERR); }
959 @bo2 = @$lines[$x+$z..$#$lines];
960 splice(@$lines, $x+$z);
961 if ($$lines[$#$lines] =~ /^\s*$/) {
962 unshift(@bo2, pop @$lines);
964 @bo1 = @$lines[0..$x];
965 splice(@$lines, 0, $x+1);
969 write_msg(($mda?'|'.SENDMAIL." $mda":">$ofile"),
970 ($hdrs?undef:\@hdr), $lines);
984 for ($x=0; $x<scalar(@$lines); $x++) {
985 if ($$lines[$x] =~ /^\s*#v([+-])$/) {
986 $verb = $1 eq '+' ? 1 : 0;
988 } else { $vrb[$x] = $verb; }
991 # Calculate quoting ratio (with respect to verbatims):
992 if ($check && scalar(@$lines)) {
993 my ($y, $z) = (0, 0);
994 for ($x=0; $x<scalar(@$lines); $x++) {
997 if ($$lines[$x] =~ /^$indent/) { $y++; }
1002 if ($y>=$check_ratio) {
1004 exit EX_UNAVAILABLE;
1008 # Remove ML footers:
1009 remove_footers($lines, \@ftr, $footers, undef, $ftr_ml);
1011 # Remove ad footers:
1012 remove_footers($lines, \@ads, $ads, undef, $ftr_ad);
1014 if ($mua eq 'mutt') {
1015 # See if we find pgp output generated by mutt before we scramble
1016 # the thing. If yes, see if we can beautify it.
1017 if ($pgpshort || $pgpmove || $pgpmovevrf) { pgp($lines, \@vrb, \@hdr); }
1019 # Remove all but the first attachment (if this is text/plain)
1020 # mutt did introduce (bah!). Remember, all this ugliness could
1021 # be replaced with a proper and clean edit_filter patch in
1023 for ($x=$#$lines; $x>=0; $x--) {
1024 if ($vrb[$x]) { next; }
1025 # The following regexp's are quite ugly because for most users
1026 # these lines are coloured using termcap... (bah!)
1027 if (($$lines[$x] =~ /^(?:\e.+?\a)?$mutt_attachment(\d+)(?::.*)? \-\-\]/o &&
1030 $$lines[$x+1] !~ /^(?:\e.+?\a)?(?:$mutt_contenttype)(?:text\/plain|application\/pgp)/io))) ||
1031 ($$lines[$x] =~ /^(?:\e.+?\a)?(?:$mutt_pgpsigned|$mutt_pgpclearsigned|$mutt_pgpencrypted)/o))
1033 # Strip attachments to prepare further processing
1034 unshift(@att, @$lines[$x..$#$lines]);
1035 splice(@$lines, $x);
1036 # Try to fix trailing empty lines
1037 while (scalar(@$lines) && $$lines[$#$lines] =~ /^(?:\e.+?\a)?\s*$/) {
1038 unshift(@att, pop(@$lines));
1041 # Remove ML and ad footers within attachments:
1043 if ($ml) { remove_footers($lines, \@tmp, $footers, undef); }
1044 if ($ad) { remove_footers($lines, \@tmp, $ads, undef); }
1045 $x = scalar(@$lines);
1049 # care about the rest
1051 for ($x=0; $x<$#att; $x++) {
1052 if ($vrb[scalar(@$lines)+$x]) { next; }
1054 # Pipe message/rfc822 parts to another instance of
1055 # process_msg() for further processing.
1056 # Please note that we cannot see what a hierarchy the
1057 # original message had -- if there were message/rfc822
1058 # parts within other message/rfc822 parts constellations
1059 # can occur which we cannot resolve. Therefore we simply
1060 # do not even try to be smart. This should work for most
1062 # The following regexp is quite ugly because for most
1063 # users the line is coloured using termcap... (bah!)
1064 if ($att[$x]=~/^(?:\e.+?\a)?$mutt_attachment\d+.* --\]/o &&
1065 $att[$x+1] =~ /^(?:\e.+?\a)?(?:$mutt_contenttype)message\/rfc822/o)
1068 while ($att[$x] !~ /^\s*$/) { $x++; }
1071 my @tmp = @att[$x..$#att];
1073 splice(@att, $x, scalar(@att)-$x, @tmp);
1081 if (scalar(@$lines)) {
1083 for ($x = $#$lines; $x>=0; $x--) {
1084 if ((!$vrb[$x]) && $$lines[$x] =~ /^-- $/) {
1086 for (my $i=1; $x+$i+1<scalar(@$lines); $i++) {
1087 if ($$lines[$x+$i] =~ /^\-\-\-\s+\S/ &&
1088 $$lines[$x+$i+1] =~ /^\+\+\+\s+\S/)
1091 unshift(@sig, @$lines[$x..$#$lines]);
1092 splice(@$lines, $x);
1097 if (defined($sign) && ++$sn==$sign) { last; } else { next; }
1101 if ($sig || ($lsig && ($#$lines-$x>$lsig))) {
1102 if ($lsig && !$sig) {
1103 unshift(@sig, "[---=| Overlong signature removed by $0: " .
1104 (scalar(@$lines)-$x) . " lines snipped |=---]\n");
1106 splice(@$lines, $x);
1109 unshift(@sig, @$lines[$x..$#$lines]);
1110 splice(@$lines, $x);
1112 if (defined($sign) && ++$sn==$sign) { last; } else { next; }
1117 # See if there is some Kammquoting to fix:
1118 if ($kamm) { decomb($lines, \@vrb); }
1120 # Now care about TOFU.
1121 # One common mispractice is M$ style TOFU:
1123 # bloat this array if you want more internationalization:
1124 my @tofu = ('Original Message',
1125 'Ursprüngliche Nachricht',
1126 'Ursprungliche Nachricht',
1127 'Mensagem original',
1128 'Ursprungligt meddelande',
1129 'Oorspronkelijk bericht',
1130 'Message d\'origine',
1131 'Forwarded message',
1132 'Weitergeleitete Nachricht / Forwarded Message');
1133 my $k = 0; # any text above?
1134 my $tmp = 0; # flagged if inside PGP output
1136 DONE: for ($x=0; $x<scalar(@$lines); $x++) {
1138 foreach my $tmp (@tofu) {
1139 if ($$lines[$x] =~ /^-+\s?$tmp\s?-+/) {
1147 if ((!$k) && $$lines[$x] !~ /^\s*$/o &&
1150 $$lines[$x] !~ /^(?:\e.+?\a)?(?:$mutt_attachment)/o &&
1151 $$lines[$x] !~ /^(?:\e.+?\a)?(?:$mutt_contenttype)/o)) &&
1152 ((!$spass) || $$lines[$x]!~/^$spass_prefix/o))
1154 if ($mua eq 'mutt' && (!$tmp) &&
1155 $$lines[$x] =~ /^(?:\e.+?\a)?(?:$mutt_pgpoutstart)/o) {
1157 } elsif ($mua eq 'mutt' && $tmp &&
1158 ($$lines[$x] =~ /^(?:\e.+?\a)?(?:$mutt_beginsigned)/o ||
1159 $$lines[$x] =~ /^(?:\e.+?\a)?(?:$mutt_pgpclearsigstart)/o)) {
1168 # try to avoid false positives and only delete m$ style tofu if
1169 # there is text above
1171 if (!$ms_smart) { goto CLEAN; }
1173 # first, see if there is pgp stuff inside the tofu:
1174 my $p = 0; # levels of pgp signed parts
1176 for (my $i=$x+1; $i<scalar(@$lines); $i++) {
1177 if ($$lines[$i] =~ /^(?:\e.+?\a)?(?:$mutt_pgpclearsigstart)/o) {
1182 STAIRS: for (my $i=0; $i<scalar(@att); $i++) {
1183 if ($p==0 && $att[$i] =~ /^(?:\e.+?\a)?\[\-\-\ /o) {
1184 splice(@att, 0, $i);
1185 unshift(@att, "\n");
1187 } elsif ($att[$i] =~ /^(?:\e.+?\a)?(?:$mutt_pgpclearsigned)/o) {
1188 splice(@att, 0, $i+1);
1196 # now removing is safe:
1197 CLEAN: $j = scalar(@$lines)-$x;
1198 splice(@$lines, $x);
1202 # Nothing? Then try traditional TOFU (deleting M$ style TOFU is done
1203 # much more aggressively, so we won't need to search any more if we
1205 if ($trad && (!$j) && !$vrb[$#$lines]) {
1206 if (scalar(@$lines) && $$lines[$#$lines] =~ /^\s*$/) {
1207 unshift(@sig, pop(@$lines));
1213 for (my $i=$#$lines; $i>=0; $i--) {
1214 if ($$lines[$i] =~ /^$indent/o) {
1218 elsif ($$lines[$i] !~ /^\s*$/) { last; }
1222 # if there is no text above, we will assume the message is meant
1223 # as forwarding and therefore OK
1224 for (my $i=$k-1; $i>=0; $i--) {
1225 if ($$lines[$i] !~ /^\s*$/o) {
1233 splice(@$lines, $k);
1238 # OK, if we found TOFU, we will leave a message that we were here...
1240 # make sendmail bounce if we shall be picky
1241 # and indeed found something:
1247 eval { require Sys::Syslog; };
1248 if ($@) { warn $@; } else {
1249 Sys::Syslog::setlogsock('unix');
1250 Sys::Syslog::openlog("$0[$$]", 'pid', 'mail');
1251 Sys::Syslog::syslog('debug', 'bounced message %s', $hdr[0]);
1252 Sys::Syslog::closelog();
1260 # if we were invoked just for checking and indeed found something,
1261 # print out the error message and quit:
1264 exit EX_UNAVAILABLE;
1267 push(@$lines, "[---=| TOFU protection by $0: " .
1268 "$j lines snipped |=---]\n");
1270 elsif ($mda eq '1') { exit EX_OK; }
1272 # Care for huge blocks of quoted original message:
1273 if ($bigqn) { debigq($lines, \@vrb); }
1275 # Care for trailing whitespaces:
1277 for ($x=0; $x<scalar(@$lines); $x++) {
1278 if (!$vrb[$x]) { $$lines[$x] =~ s/[\ \t]+$//; }
1282 # Care for punctuation abuse:
1284 for ($x=0; $x<scalar(@$lines); $x++) {
1285 if (!$vrb[$x]) { $$lines[$x] =~ s/(([.?!])\2\2)\2+/$1/eg; }
1289 # (Nearly) at last care for multiple blank lines. (Do not do this
1290 # earlier -- the way it is done right now would screw up the verbatim
1294 for ($x=scalar(@$lines)-1; $x>=0; $x--) {
1295 if ((!$vrb[$x]) && $$lines[$x] =~ /^\s*$/) {
1296 if ($t<2) { $t++; } else { splice(@$lines, $x, 1); }
1302 # Everything changing the body is done now. Time to fix the line count
1303 # header so naive clients do not get confused. Just to be sure, append
1304 # the old line count to X-headers.
1305 my $l = scalar(@bo1) + scalar(@$lines) + scalar(@att) + scalar(@bo2) +
1306 (!$sig?scalar(@sig):0) + (!$ml?scalar(@ftr):0) +
1307 (!$ad?scalar(@ads):0);
1308 if ($linecount-$l!=0) {
1309 for ($x=0; $x<scalar(@hdr); $x++) {
1311 s/^(Lines:\s+)(\d+)/$1.($2-$linecount+$l)/e)
1313 $hdr[$#hdr] = "X-Old-Lines: $2\n";
1319 # Finally, before leaving we put everything back in right order.
1320 unshift(@$lines, (!$hdrs?@hdr:()), @bo1);
1321 push(@$lines, (!$sig?@sig:()), (!$ad?@ads:()), (!$ml?@ftr:()), @att,
1327 my $locale = $ENV{'LC_ALL'}?$ENV{'LC_ALL'}:($ENV{'LC_MESSAGES'}?$ENV{'LC_MESSAGES'}:$ENV{'LANG'});
1329 # command line switches
1330 ($ad, $ads, $bigqn, $bigqx, $check, $cr, $sysl, $diff, $elli, $footers, $lax,
1331 $ml, $ms, $ms_smart, $mda, $mua, $hdrs, $kamm, $lsig, $sig, $sigint,
1332 $spass, $trad, $trsp) =
1333 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1334 my $ifile = '-'; # use STDIN if nothing specified
1336 # get command line params:
1337 Getopt::Mixed::init('a A=s c d e h i=s k L=s l m M=s o=s P=s p:s r S:i'.
1338 ' s t v w bigq:s check:s debug>d diff ftr-ad ftr-ml help>h kminl=i'.
1339 ' kmaxl=i kdiff=i lax-security locale=s ms-smart mua>M pgp-short'.
1340 ' pgp-move pgp-move-vrf sigsmax:i spass version>v');
1341 while (my ($opt, $val, $pretty) = nextOption()) {
1342 if ($opt eq 'a') { $ad = 1; }
1343 elsif ($opt eq 'A') { $ads = $val; }
1344 elsif ($opt eq 'bigq') {
1345 if ($val !~ /^(?:(\d+)(?:,(\d+))?)?$/) { help(); }
1348 if ($bigqn<=0 || $bigqx<=0 || $bigqn<=$bigqx) { help(); }
1350 elsif ($opt eq 'c') { $cr = 1; }
1351 elsif ($opt eq 'check') {
1353 while ($val && $val =~ s/^([^,\s]+)(?:,(\S+))?$/$2/) {
1356 if ($foo =~ /^ratio=(0?\.\d+)$/) {
1357 $check_ratio = $1?$1:1;
1361 elsif ($opt eq 'd') { $sysl = 1; }
1362 elsif ($opt eq 'diff') { $diff = 1; }
1363 elsif ($opt eq 'e') { $elli = 1; }
1364 elsif ($opt eq 'ftr-ad') { $ftr_ad = 1; $ad = 1; }
1365 elsif ($opt eq 'ftr-ml') { $ftr_ml = 1; $ml = 1; }
1366 elsif ($opt eq 'i') { $ifile = $val; }
1367 elsif ($opt eq 'k') { $kamm = 1; }
1368 elsif ($opt eq 'kminl') { $kminl = $val; $kamm = 1; }
1369 elsif ($opt eq 'kmaxl') { $kmaxl = $val; $kamm = 1; }
1370 elsif ($opt eq 'kdiff') { $kdiff = $val; $kamm = 1; }
1371 elsif ($opt eq 'L') { $footers = $val; }
1372 elsif ($opt eq 'l') { $ml = 1; }
1373 elsif ($opt eq 'lax-security') { $lax = 1; }
1374 elsif ($opt eq 'locale') { $locale = $val; }
1375 elsif ($opt eq 'm') { $ms = 1; }
1376 elsif ($opt eq 'ms-smart') { $ms_smart = 1; $ms = 1; }
1377 elsif ($opt eq 'M') {
1380 if ($mua eq 'mutt') {
1381 # mutt still displays the message when ^C'ing pgp verification:
1382 $SIG{'INT'} = 'sigint_handler';
1385 elsif ($opt eq 'o') { $ofile = $val; }
1386 elsif ($opt eq 'P') { $boun = $val; }
1387 elsif ($opt eq 'p') { $mda = $val ? $val : '1'; }
1388 elsif ($opt eq 'pgp-short') { $pgpshort = 1; }
1389 elsif ($opt eq 'pgp-move') { $pgpmove = 1; }
1390 elsif ($opt eq 'pgp-move-vrf') { $pgpmovevrf = 1; }
1391 elsif ($opt eq 'r') { $hdrs = 1; }
1392 elsif ($opt eq 'S') { $lsig = $val ? $val : $maxsig; }
1393 elsif ($opt eq 's') { $sig = 1; }
1394 elsif ($opt eq 'sigsmax') { $sign = $val ? $val : undef; }
1395 elsif ($opt eq 'spass') { $spass = 1; }
1396 elsif ($opt eq 't') { $trad = 1; }
1397 elsif ($opt eq 'v') { version(); }
1398 elsif ($opt eq 'w') { $trsp = 1; }
1401 Getopt::Mixed::cleanup();
1402 if (($ml && $footers eq '')|| # no -l without -L
1403 ($ad && $ads eq '')|| # no -a without -A
1404 ($ifile eq '')|| # no empty -i
1405 ($ofile eq '')) # no empty -o
1409 if ($mua eq 'mutt') {
1410 if (defined $locale && $locale ne '' && $locale ne 'C' && $locale ne 'POSIX') {
1411 foreach my $key (keys %mutt_attachment) {
1412 if ($locale =~ /^$key/) {
1413 if ($mutt_attachment{$key})
1414 { $mutt_attachment = $mutt_attachment{$key}; }
1415 if ($mutt_contenttype{$key})
1416 { $mutt_contenttype = $mutt_contenttype{$key}; }
1417 if ($mutt_pgpsigned{$key})
1418 { $mutt_pgpsigned = $mutt_pgpsigned{$key}; }
1419 if ($mutt_beginsigned{$key})
1420 { $mutt_beginsigned = $mutt_beginsigned{$key}; }
1421 if ($mutt_pgpclearsigned{$key})
1422 { $mutt_pgpclearsigned = $mutt_pgpclearsigned{$key}; }
1423 if ($mutt_pgpclearsigstart{$key})
1424 { $mutt_pgpclearsigstart = $mutt_pgpclearsigstart{$key}; }
1425 if ($mutt_pgpencrypted{$key})
1426 { $mutt_pgpencrypted = $mutt_pgpencrypted{$key}; }
1427 if ($mutt_pgpoutstart{$key})
1428 { $mutt_pgpoutstart = $mutt_pgpoutstart{$key}; }
1429 if ($mutt_pgpoutend{$key})
1430 { $mutt_pgpoutend = $mutt_pgpoutend{$key}; }
1434 foreach my $key (keys %gpg_WARNING) {
1435 if ($locale =~ /^$key/) {
1436 if ($gpg_WARNING{$key})
1437 { $gpg_WARNING = $gpg_WARNING{$key}; }
1438 if ($gpg_Warning{$key})
1439 { $gpg_Warning = $gpg_Warning{$key}; }
1440 if ($gpg_Cantcheck{$key})
1441 { $gpg_Cantcheck = $gpg_Cantcheck{$key}; }
1443 { $gpg_aka = $gpg_aka{$key}; }
1445 { $gpg_bad = $gpg_bad{$key}; }
1446 if ($gpg_expired{$key})
1447 { $gpg_expired = $gpg_expired{$key}; }
1448 if ($gpg_good{$key})
1449 { $gpg_good = $gpg_good{$key}; }
1455 esc(\$mutt_attachment);
1456 esc(\$mutt_contenttype);
1457 esc(\$mutt_pgpsigned);
1458 esc(\$mutt_beginsigned);
1459 esc(\$mutt_pgpclearsigned);
1460 esc(\$mutt_pgpclearsigstart);
1461 esc(\$mutt_pgpencrypted);
1462 esc(\$mutt_pgpoutstart);
1463 esc(\$mutt_pgpoutend);
1467 esc(\$gpg_Cantcheck);
1475 if ($ms_smart || $pgpshort || $pgpmove || $pgpmovevrf) { help(); }
1478 esc(\$spass_prefix);
1482 if (!open(IN, $ifile)) { print STDERR "Could not open $ifile: $!\n"; exit(EX_IOERR); }
1486 # this should be self-explanatory:
1487 process_msg(\@message);
1489 # Finally, print clean lines:
1490 if ($ofile ne 'NONE') {
1491 write_msg(($mda?'|'.SENDMAIL." $mda":">$ofile"), \@message);
1494 # vim600:set foldmethod=marker: