]> git.deb.at Git - pkg/t-prot.git/blob - t-prot
Imported Upstream version 1.49
[pkg/t-prot.git] / t-prot
1 #!/usr/bin/perl -w
2 # $Id: t-prot,v 1.218 2005/02/02 13:46:42 jochen Exp $
3
4 require 5.006;
5 use strict;
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';
14 # From <sysexits.h>
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;
22 use vars qw(
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
28
29     $gpg_WARNING $gpg_Warning $gpg_Cantcheck $gpg_aka $gpg_bad
30     $gpg_expired $gpg_good $gpg_bug
31
32     $mutt_attachment $mutt_contenttype $mutt_pgpsigned $mutt_beginsigned
33     $mutt_pgpclearsigned $mutt_pgpclearsigstart $mutt_pgpencrypted
34     $mutt_pgpoutstart $mutt_pgpoutend
35 );
36
37
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):
40 $0 =~ 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
44 $kmaxl          = 80;
45 $kdiff          = 20;
46 $pgpshort       = 0;      # hide pgp key ids if set
47 $pgpmove        = 0;      # move pgp output to bottom if set
48 $pgpmovevrf     = 0;
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
59
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 #',
70         'et' => '[-- Lisa #',
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' => '[-- ¸½¼þ #',
88         'zh_TW' => '[-- 附件 #'
89 );
90 my %mutt_contenttype = (
91         'bg' => '[-- Òèï: ',
92         'ca' => '[-- Tipus: ',
93         'cs' => '[-- Typ: ',
94         'de' => '[-- Typ: ',
95         'el' => '[-- Ôýðïò: ',
96         'eo' => '[-- Speco: ',
97         'es' => '[-- Tipo: ',
98         'et' => '[-- Tüüp: ',
99         'fr' => '[-- Type : ',
100         'gl' => '[-- Tipo: ',
101         'hu' => '[-- Típus: ',
102         'id' => '[-- Jenis: ',
103         'it' => '[-- Tipo: ',
104         'ja' => '[-- ¥¿¥¤¥×: ',
105         'ko' => '[-- Á¾·ù: ',
106         'lt' => '[-- Tipas: ',
107         'pl' => '[-- Typ: ',
108         'pt_BR' => '[-- Tipo: ',
109         'ru' => '[-- ôÉÐ: ',
110         'sk' => '[-- Typ: ',
111         'sv' => '[-- Typ: ',
112         'tr' => '[-- Tip: ',
113         'uk' => '[-- ôÉÐ: ',
114         'zh_CN' => '[-- ÐÎ̬:  ',
115         'zh_TW' => '[-- 種類:'
116 );
117 my %mutt_pgpsigned = (
118         'bg' => '[-- Êðàé íà ïîäïèñàíèòå äàííè --]',
119         'ca' => '[-- Final de les dades signades. --]',
120         'cs' => '',
121         'da' => '[-- Slut på underskrevne data --]',
122         'de' => '[-- Ende der signierten Daten --]',
123         'el' => '[-- ÔÝëïò äåäïìÝíùí õðïãåãñáììÝíùí --]',
124         'eo' => '[-- Fino de subskribitaj datenoj --]',
125         'es' => '',
126         'et' => '[-- Allkirjastatud info lõpp --]',
127         'fr' => '[-- Fin des données signées --]',
128         'gl' => '',
129         'hu' => '',
130         'id' => '[-- Akhir data yang ditandatangani --]',
131         'it' => '[-- Fine dei dati firmati --]',
132         'ja' => '[-- ½ð̾¥Ç¡¼¥¿½ªÎ» --]',
133         'ko' => '[-- ¼­¸í ÀÚ·á ³¡ --]',
134         'lt' => '',
135         'nl' => '',
136         'pl' => '[-- Koniec podpisanych danych --]',
137         'pt_BR' => '',
138         'ru' => '[-- ëÏÎÅàÐÏÄÐÉÓÁÎÎÙÈ ÄÁÎÎÙÈ --]',
139         'sk' => '',
140         'sv' => '[-- Slut på signerat data --]',
141         'tr' => '',
142         'uk' => '[-- ë¦ÎÅÃؠЦÄÐÉÓÁÎÉÈ ÄÁÎÉÈ --]',
143         'zh_CN' => '',
144         'zh_TW' => ''
145 );
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' => '[-- 以下的資料已被簽署 --]',
174 );
175 my %mutt_pgpencrypted = (
176         'bg' => '[-- Êðàé íà PGP/MIME øèôðîâàíèòå äàííè --]',
177         'ca' => '[-- Final de les dades xifrades amb PGP/MIME. --]',
178         'cs' => '',
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 --]',
183         'es' => '',
184         'et' => '[-- PGP/MIME krüptitud info lõpp --]',
185         'fr' => '[-- Fin des données chiffrées avec PGP/MIME --]',
186         'gl' => '',
187         'hu' => '',
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 ¾Ïȣȭ ÀÚ·á ³¡ --]',
192         'lt' => '',
193         'nl' => '',
194         'pl' => '[-- Koniec danych zaszyfrowanych PGP/MIME --]',
195         'pt_BR' => '',
196         'ru' => '[-- ëÏÎÅàÄÁÎÎÙÈ, ÚÁÛÉÆÒÏ×ÁÎÎÙÈ × ÆÏÒÍÁÔÅ PGP/MIME --]',
197         'sk' => '',
198         'sv' => '[-- Slut på data krypterad enligt PGP/MIME --]',
199         'tr' => '',
200         'uk' => '[-- ë¦ÎÅÃØ ÄÁÎÉÈ, ÚÁÛÉÆÒÏ×ÁÎÉÈ PGP/MIME --]',
201         'zh_CN' => '',
202         'zh_TW' => ''
203 );
204 my %mutt_pgpclearsigned = (
205         'bg' => '[-- ÊÐÀÉ ÍÀ PGP-ÏÎÄÏÈÑÀÍÎÒΠÏÈÑÌΠ--]',
206         'ca' => '[-- TERMINA EL MISSATGE PGP SIGNAT --]',
207         'cs' => '',
208         'el' => '[-- ÔÅËÏÓ ÕÐÏÃÅÃÑÁÌÌÅÍÏÕ PGP ÌÇÍÕÌÁÔÏÓ --]',
209         'eo' => '[-- FINO DE PGP-SUBSKRIBITA MESAØO --]',
210         'es' => '',
211         'et' => '[-- PGP ALLKIRJASTATUD TEATE LÕPP --]',
212         'fr' => '[-- FIN DE MESSAGE SIGNÉ PGP --]',
213         'gl' => '',
214         'hu' => '',
215         'id' => '[-- AKHIR PESAN DG TANDATANGAN PGP --]',
216         'it' => '[-- FINE DEL MESSAGGIO FIRMATO CON PGP --]',
217         'ja' => '[-- PGP½ð̾¥á¥Ã¥»¡¼¥¸½ªÎ» --]',
218         'ko' => '[-- PGP ¼­¸í ¸ÞÀÏ ³¡ --]',
219         'lt' => '',
220         'nl' => '',
221         'pl' => '[-- KONIEC LISTU PODPISANEGO PGP --]',
222         'pt_BR' => '',
223         'ru' => '[-- ëÏÎÅàÓÏÏÂÝÅÎÉÑ, ÐÏÄÐÉÓÁÎÎÏÇÏ PGP --]',
224         'sk' => '',
225         'sv' => '[-- SLUT PÅ MEDDELANDE SIGNERAT MED PGP --]',
226         'tr' => '',
227         'uk' => '[-- ë¦ÎÅÃØ ÐÏצÄÏÍÌÅÎÎÑ Ú PGP Ð¦ÄÐÉÓÏÍ --]',
228         'zh_CN' => '',
229         'zh_TW' => ''
230 );
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 簽名的信件開始 --]'
257 );
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 輸出的資料(現在時間:'
286 );
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 輸出部份結束 --]'
315 );
316 # }}}
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 --]';
327
328 # gpg's locales as in gpg-1.4.0 {{{
329 my %gpg_WARNING = (
330         'be' => '',
331         'ca' => 'AV�S: ',
332         'cs' => 'VAROVÁNÍ: ',
333         'da' => 'ADVARSEL: ',
334         'de' => 'WARNUNG: ',
335         'el' => 'ÐÑÏÅÉÄÏÐÏÉÇÓÇ: ',
336         'eo' => 'AVERTO: ',
337         'es' => 'ATENCIÓN: ',
338         'et' => 'HOIATUS: ',
339         'fi' => 'VAROITUS: ',
340         'fr' => 'ATTENTION: ',
341         'gl' => 'AVISO: ',
342         'hu' => 'FIGYELEM: ',
343         'id' => 'PERINGATAN: ',
344         'it' => 'ATTENZIONE: ',
345         'ja' => '·Ù¹ð: ',
346         'pl' => 'OSTRZE¯ENIE: ',
347         'pt' => 'AVISO: ',
348         'pt_BR' => 'AVISO: ',
349         'ro' => 'AVERTISMENT: ',
350         'ru' => 'ВНИМАНИЕ: ',
351         'sk' => 'VAROVANIE: ',
352         'sv' => 'VARNING: ',
353         'tr' => 'UYARI: ',
354         'zh_CN' => '警告:我们不信任这把密钥!',
355         'zh_TW' => 'ĵ§i¡G§Ú­Ì *¤£* «H¥ô³o§âª÷Æ_¡I'
356 );
357 my %gpg_Warning = (
358         'be' => '',
359         'ca' => 'AV�S: ',
360         'cs' => 'VAROVÁNÍ: ',
361         'da' => '',
362         'de' => 'Warnung: ',
363         'el' => 'ÐÑÏÅÉÄÏÐÏÉÇÓÇ: ',
364         'eo' => 'AVERTO: ',
365         'es' => 'ATENCIÓN: ',
366         'et' => 'HOIATUS: ',
367         'fi' => 'VAROITUS: ',
368         'fr' => 'AVERTISSEMENT: ',
369         'gl' => 'AVISO: ',
370         'hu' => 'FIGYELEM: ',
371         'id' => 'PERINGATAN: ',
372         'it' => 'ATTENZIONE: ',
373         'ja' => '·Ù¹ð: ',
374         'pl' => 'OSTRZE¯ENIE: ',
375         'pt' => 'CUIDADO: ',
376         'pt_BR' => 'CUIDADO: ',
377         'ro' => 'AVERTISMENT: ',
378         'ru' => 'ВНИМАНИЕ: ',
379         'sk' => 'VAROVANIE: ',
380         'sv' => 'VARNING: ',
381         'tr' => 'UYARI: ',
382         'zh_CN' => '警告:加密过的报文已经变造!',
383         'zh_TW' => 'ĵ§i¡G¥[±K¹Lªº°T®§¤w¸g³QÅܳy¤F¡I'
384 );
385 my %gpg_Cantcheck = (
386         'be' => '',
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 '
412 );
413 my %gpg_aka = (
414         'be' => '',
415         'ca' => '              alias ',
416         'cs' => '                alias ',
417         'da' => '              alias ',
418         'de' => '                    alias ',
419         'el' => '                ãíùóôü óáí ',
420         'eo' => '            alinome ',
421         'es' => '                alias ',
422         'et' => '                 ka ',
423         'fr' => '                alias « ',
424         'gl' => '               alias ',
425         'hu' => '               azaz ',
426         'id' => '              alias ',
427         'it' => '                alias ',
428         'ja' => '                ÊÌ̾¡È',
429         'pl' => '                        alias ',
430         'pt' => '                   ou ',
431         'pt_BR' => '                   ou ',
432         'sk' => '                alias ',
433         'sv' => '      även känd som ',
434         'tr' => '                den ',
435         'zh_CN' => '              亦即“',
436         'zh_TW' => '                ¥ç§Y '
437 );
438 my %gpg_bad = (
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 ',
454         'ja' => '¡È',
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* ªºÃ±³¹¨Ó¦Û©ó '
465 );
466 my %gpg_expired = (
467         'be' => '',
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'
493 );
494 my %gpg_good = (
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 ',
510         'ja' => '¡È',
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ªºÃ±³¹¨Ó¦Û©ó '
521 );
522 my %gpg_bug = (
523         'be' => '',
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­Ó·å²« ('
549 );
550 # }}}
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: ';
556 $gpg_aka                = '                aka ';
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 (';
562
563
564 # help(): print help text and exit with appropriate exit code
565 sub help {
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
586                   footers as signature
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'
594                   for no output at all
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
603   -s              delete signature
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";
609     exit(EX_USAGE);
610 }
611
612 # version(): print version info and exit with appropriate exit code
613 sub version {
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";
616     exit(EX_OK);
617 }
618
619 # sigint_handler(): what to do if we receive a single SIGINT
620 sub sigint_handler {
621     $sigint = 1;
622 }
623
624 # esc(): escapes a scalar reference for use in perl regexp
625 sub esc { ${$_[0]} =~ s/([\[\]\(\)\*\.\-\^\$\@])/\\$1/go; }
626
627 # remove_footers(): remove any trailing appearance of footers contained
628 # in the given directory.
629 sub remove_footers {
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
635     my $off;
636
637     if (!defined $V) {
638         for ($off = 0; $#$L>=$off && $$L[$#$L-$off] =~ /^\s*$/; $off++) {;};
639     }
640
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;
644         closedir DIR;
645
646         foreach my $f (@feet) {
647             if (!open(IN, "$F/$f")) { print STDERR "Could not open $F/$f: $!\n"; exit(EX_IOERR); }
648             my @l = <IN>;
649             close IN;
650
651             if (!scalar(@l)) { next; }
652             for (my $z=0; $z<=$#l; $z++) { chomp($l[$z]); }
653
654             if (defined $V) {
655                 WIPE: for (my $z=scalar(@$L)-scalar(@l); $z>=0; $z--)
656                 {
657                     if (scalar(@l)+$z<=scalar(@$L)) {
658                         my $y = 0;
659                         for(my $x=1; $x<=scalar(@l); $x++) {
660                             if (index($$L[scalar(@$L)-$x-$z], $l[scalar(@l)-$x])!=0) {
661                                 $y = 1;
662                             }
663                         }
664                         if (!$y) {
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));
669                             }
670                             if ($O) { last; } else { goto WIPE; }
671                         }
672                     }
673                 }
674             }
675             else {
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) { 
679                             goto FINISH;
680                         }
681                     }
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));
686                     }
687                     if ($O) { last; }
688                 }
689                 FINISH:
690             }
691         }
692     }
693 }
694
695 # decomb(): Try to detect and fix zig-zag shaped quoting (a.k.a. German
696 # "Kammquoting").
697 sub decomb {
698     my $L = shift;        # array of message lines
699     my $V = shift;        # array with verbatim list
700     my $max = 0;        # plausible wraparound pos
701
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]); }
706     }
707
708     # Next we see if there are plausible wraparounds.    
709     for (my $x=0; $x+1<$#$L; $x++) {
710
711         # OK, 
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^]/) &&
731             ($$L[$x] !~ /-$/) &&
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*$/))
739         {
740             $$L[$x] =~ s/\s*$/' ' . $$L[$x+1]/e;
741             splice(@$L, $x+1, 1);
742             splice(@$V, $x+1, 1);
743         }
744     }
745 }
746
747 # debigq(): Finds big quotes (more than $n lines quoted) and deletes all
748 # but $x lines of them.
749 sub debigq {
750     my $L = shift;        # array of message lines
751     my $V = shift;        # array with verbatim list
752     my $k = 0;
753
754     for (my $i=0; $i<=$#$L; $i++) {
755
756         if ($$V[$i]) { 
757             $k = 0;
758             next;
759         }
760
761         if (index($$L[$i], $indent)==0) { $k++; } else { 
762             if ($k>$bigqn) {
763                 my $x = $k-$bigqx;
764                 $i -= $k;
765
766                 $$L[$i] = "[---=| Quote block shrinked by $0: " .
767                     "$x lines snipped |=---]\n";
768                 $i++;
769                 splice(@$L, $i, $x-1);
770                 splice(@$V, $i, $x-1);
771
772                 $i++;
773             }
774             $k = 0;
775         }
776     }
777 }
778
779 # pgp(): treat mutt(1)'s pgp/gpg output contained in signed or encrypted
780 # messages
781 sub pgp {
782
783     sub verified {
784         my $L = shift;    # message body
785         my $X = shift;    # start line
786         my $Z = shift;    # end line
787
788                 my $ok = 0;
789
790         while ($X<$Z) {
791             if ($$L[$X] =~ /^gpg:\s(?:$gpg_WARNING|$gpg_Warning|$gpg_bad|$gpg_Cantcheck|$gpg_expired)/o)
792                 { return 0; }
793             if ($$L[$X] =~ /^gpg:\s$gpg_bug/o)
794                 { return 0; }
795             if ($$L[$X] =~ /^gpg:\s$gpg_good/o)
796                 { $ok = 1; }
797             $X++;
798         }
799
800         return $ok;
801     }
802
803     my $L = shift;        # message body
804     my $V = shift;        # verbatim list
805     my $H = shift;        # headers
806
807     my @tmp = ();
808     my $tmp = 0;
809
810     for (my $x=0; $x<scalar(@$L); $x++) {
811         if ($$V[$x]) { next; }
812
813         if ($$L[$x]=~/^(?:\e.+?\a)?(?:$mutt_pgpoutstart)/o)
814         {
815             my $from;
816             for (my $m=0; $m<scalar(@$H); $m++) {
817                 if ($$H[$m] =~ /^From:/) {
818                     $from = $$H[$m];
819                     $m++;
820                     while ($$H[$m] =~ /^\s/) { $from .= $$H[$m]; $m++; }
821                     last;
822                 }
823             }
824             ($from) = $from=~m/([a-z\d][a-z_\d\+-\.]*\@(?:[a-z_\d\+-\.]+\.)+[a-z]{2,})/i;
825             esc(\$from);
826
827             my $uid = 1;
828
829             for (my $i=$x+1; $i<scalar(@$L); $i++) {
830                 if ($pgpshort && $$L[$i] =~ /^gpg:\s$gpg_aka/o) { $uid++; }
831
832                 if ($pgpshort && $uid>1 &&
833                     $$L[$i] =~ /^gpg:\s$gpg_aka/o && $$L[$i] !~ /$from/)
834                 { 
835                     splice(@$L, $i, 1);
836                     splice(@$V, $i, 1);
837                     $i--;
838                 }
839                 elsif ($$L[$i]=~/^(?:\e.+?\a)?(?:$mutt_pgpoutend)/o)
840                 {
841                     if ($pgpmove ||
842                         ($pgpmovevrf && (!$sigint) && verified($L, $x+1, $i)))
843                     {
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;
848                     }
849                     $x = $i;
850                     last;
851                 }
852             }
853         }
854         elsif ($tmp &&
855             $$L[$x]=~/^(?:\e.+?\a)?(?:$mutt_pgpencrypted|$mutt_pgpclearsigned|$mutt_pgpsigned)/o)
856         {
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));
860             }
861             $x += scalar(@{$tmp[$tmp--]});
862             pop(@tmp);
863         }
864     }
865
866     while ($tmp>0) {
867         push(@$L, @{$tmp[$tmp--]});
868         pop(@tmp);
869         for (my $i=$#$V; $i<$#$L; $i++) { push(@$V, 0); }
870     }
871 }
872
873 # write_msg(): output
874 sub write_msg {
875     my $O = shift;
876     my $l;
877
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);
881         }
882     }
883     elsif (!open(OUT, $O)) { 
884         print STDERR "Could not open $O: $!\n"; exit(EX_IOERR);
885     }
886     while (scalar(@_)) {
887         $l = shift;
888         if (defined $l) {
889             $^W = 0;
890             print OUT @$l;
891             $^W = 1;
892         }
893     }
894     close OUT;
895 }
896
897 # process_msg(): This one proc does *everything* what has to be done with
898 # the lines of the message
899 sub process_msg {
900     my $lines = shift;
901
902     my ($j, $x, $verb) = (0, 0, 0);
903     my (@ads, @hdr, @bo1, @bo2, @ftr, @sig, @vrb, @att) = 
904         ((), (), (), (), (), (), (), (), ());
905
906     # First, remove and store lines we might need later...
907     # Remove headers:
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);
913
914
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
918     # business).
919     if ($mua ne 'mutt') { 
920         for ($x=0; $x<scalar(@hdr); $x++) {
921             if ($hdr[$x] =~ /^Content-Type:\s+(.*)$/i) {
922                 my $foo = $1;
923
924                 if ($foo =~ /^multipart\//i) {
925                     undef $foo;
926
927                     if ($hdr[$x] =~ /\Wboundary="([^"]+)"/i) { $foo = $1; }
928                     else { 
929                         for (my $z=1; $x+$z<@hdr && $hdr[$x+$z]=~/^\s/; $z++) {
930                             if ($hdr[$x] =~ /\Wboundary="?([^"\s]+)"?$/i) { 
931                                 $foo = $1;
932                                 last;
933                             }
934                         }
935                     }
936
937                     if (defined $foo) {
938                         for (my $x=0; $x<scalar(@$lines); $x++) {
939                             if (index($$lines[$x], '--'.$foo)!=0) { next; }
940
941                             my $bar = 'text/plain';
942                             for ($x++; $x<@$lines && $$lines[$x]!~/^$/; $x++)
943                             {
944                                 if ($$lines[$x] =~ /^Content-Type:\s+(.*)/i) { 
945                                     $bar = $1;
946                                 }
947                             }
948                             if ($x>=scalar(@$lines)) { exit(EX_DATAERR); }
949
950                             if ($bar =~ /^text\/plain/i) {
951                                 my $z;
952                                 for ($z=1; $x+$z<@$lines; $z++) {
953                                     if (index($$lines[$x+$z], '--'.$foo)==0) {
954                                         last;
955                                     }
956                                 }
957                                 if ($x+$z>=scalar(@$lines)) { exit(EX_DATAERR); }
958
959                                 @bo2 = @$lines[$x+$z..$#$lines];
960                                 splice(@$lines, $x+$z);
961                                 if ($$lines[$#$lines] =~ /^\s*$/) {
962                                     unshift(@bo2, pop @$lines);
963                                 }
964                                 @bo1 = @$lines[0..$x];
965                                 splice(@$lines, 0, $x+1);
966                                 last;
967                             }
968                             else { 
969                                 write_msg(($mda?'|'.SENDMAIL." $mda":">$ofile"),
970                                     ($hdrs?undef:\@hdr), $lines);
971                                 exit;
972                             }
973                         }
974                     }
975                 }
976                 last;
977             }
978         } 
979     }
980
981
982     # Protect verbatims:
983     $verb = 0;
984     for ($x=0; $x<scalar(@$lines); $x++) {
985         if ($$lines[$x] =~ /^\s*#v([+-])$/) { 
986             $verb = $1 eq '+' ? 1 : 0;
987             $vrb[$x] = 1;
988         } else { $vrb[$x] = $verb; }
989     }
990
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++) {
995             if (!$vrb[$x]) {
996                 $z++;
997                 if ($$lines[$x] =~ /^$indent/) { $y++; }
998             }
999         }
1000         $y = $y/$z;
1001
1002         if ($y>=$check_ratio) {
1003             print $msg_ratio;
1004             exit EX_UNAVAILABLE;
1005         }
1006     }
1007
1008     # Remove ML footers:
1009     remove_footers($lines, \@ftr, $footers, undef, $ftr_ml);
1010
1011     # Remove ad footers:
1012     remove_footers($lines, \@ads, $ads, undef, $ftr_ad);
1013
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); }
1018
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 
1022         # mutt(1) itself...
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 &&
1028                     (($1 ne '1') ||
1029                     ($x<$#$lines &&
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))
1032             { 
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));
1039                 }
1040
1041                 # Remove ML and ad footers within attachments:
1042                 my @tmp;
1043                 if ($ml) { remove_footers($lines, \@tmp, $footers, undef); }
1044                 if ($ad) { remove_footers($lines, \@tmp, $ads,     undef); }
1045                 $x = scalar(@$lines);
1046             }
1047         }
1048
1049         # care about the rest
1050         if (scalar(@att)) {
1051             for ($x=0; $x<$#att; $x++) {
1052                 if ($vrb[scalar(@$lines)+$x]) { next; }
1053
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
1061                 # situations.
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)
1066                 {
1067                     $x += 2;
1068                     while ($att[$x] !~ /^\s*$/) { $x++; }
1069                     $x++;
1070
1071                     my @tmp = @att[$x..$#att];
1072                     process_msg(\@tmp);
1073                     splice(@att, $x, scalar(@att)-$x, @tmp);
1074                     $x += scalar(@tmp);
1075                 }
1076             }
1077         }
1078     }
1079
1080     # Remove signature:
1081     if (scalar(@$lines)) { 
1082         my $sn = 0;
1083         for ($x = $#$lines; $x>=0; $x--) {
1084             if ((!$vrb[$x]) && $$lines[$x] =~ /^-- $/) {
1085                 if ($diff) {
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/)
1089                         {
1090                             $sig = 0;
1091                             unshift(@sig, @$lines[$x..$#$lines]);
1092                             splice(@$lines, $x);
1093                             last;
1094                         }
1095                     }
1096                     if (scalar(@sig)) {
1097                         if (defined($sign) && ++$sn==$sign) { last; } else { next; }
1098                     }
1099                 }
1100
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");
1105                     }
1106                     splice(@$lines, $x);
1107                 }
1108                 else {
1109                     unshift(@sig, @$lines[$x..$#$lines]);
1110                     splice(@$lines, $x);
1111                 }
1112                 if (defined($sign) && ++$sn==$sign) { last; } else { next; }
1113             }
1114         }
1115     }
1116
1117     # See if there is some Kammquoting to fix:
1118     if ($kamm) { decomb($lines, \@vrb); }
1119
1120     # Now care about TOFU.
1121     # One common mispractice is M$ style TOFU:
1122     if ($ms) {
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
1135
1136         DONE: for ($x=0; $x<scalar(@$lines); $x++) { 
1137             if (!$vrb[$x]) {
1138                 foreach my $tmp (@tofu) {
1139                     if ($$lines[$x] =~ /^-+\s?$tmp\s?-+/) { 
1140                         $x++;
1141                         $trad = 0;
1142                         $bigqn = 0;
1143                         last DONE; 
1144                     }
1145                 }
1146
1147                 if ((!$k) && $$lines[$x] !~ /^\s*$/o &&
1148                     ((!$mua) ||
1149                      ($mua eq 'mutt' &&
1150                          $$lines[$x] !~ /^(?:\e.+?\a)?(?:$mutt_attachment)/o &&
1151                          $$lines[$x] !~ /^(?:\e.+?\a)?(?:$mutt_contenttype)/o)) &&
1152                     ((!$spass) || $$lines[$x]!~/^$spass_prefix/o))
1153                 {
1154                     if ($mua eq 'mutt' && (!$tmp) &&
1155                         $$lines[$x] =~ /^(?:\e.+?\a)?(?:$mutt_pgpoutstart)/o) {
1156                         $tmp = 1; 
1157                     } elsif ($mua eq 'mutt' && $tmp && 
1158                         ($$lines[$x] =~ /^(?:\e.+?\a)?(?:$mutt_beginsigned)/o ||
1159                          $$lines[$x] =~ /^(?:\e.+?\a)?(?:$mutt_pgpclearsigstart)/o)) {
1160                         $tmp = 0;
1161                     } elsif (!$tmp) {
1162                         $k = 1;
1163                     }
1164                 }
1165             }
1166         }
1167
1168         # try to avoid false positives and only delete m$ style tofu if
1169         # there is text above
1170         if ($k) {
1171             if (!$ms_smart) { goto CLEAN; }
1172
1173             # first, see if there is pgp stuff inside the tofu:
1174             my $p = 0;    # levels of pgp signed parts
1175
1176             for (my $i=$x+1; $i<scalar(@$lines); $i++) {
1177                 if ($$lines[$i] =~ /^(?:\e.+?\a)?(?:$mutt_pgpclearsigstart)/o) {
1178                     $p++;
1179                 }
1180             }
1181             if ($p) {
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");
1186                         goto CLEAN;
1187                     } elsif ($att[$i] =~ /^(?:\e.+?\a)?(?:$mutt_pgpclearsigned)/o) {
1188                         splice(@att, 0, $i+1);
1189                         $p--;
1190                         goto STAIRS;
1191                     }
1192                 }
1193                 splice(@att);
1194             }
1195
1196             # now removing is safe:
1197             CLEAN: $j = scalar(@$lines)-$x;
1198             splice(@$lines, $x);
1199         }
1200     }
1201
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
1204     # did find some):
1205     if ($trad && (!$j) && !$vrb[$#$lines]) {
1206         if (scalar(@$lines) && $$lines[$#$lines] =~ /^\s*$/) { 
1207             unshift(@sig, pop(@$lines));
1208         }
1209
1210         my $k;
1211         my $x = 1;
1212
1213         for (my $i=$#$lines; $i>=0; $i--) {
1214             if ($$lines[$i] =~ /^$indent/o) {
1215                 $j++;
1216                 $k = $i;
1217             }
1218             elsif ($$lines[$i] !~ /^\s*$/) { last; }
1219         }
1220
1221         if ($j) {
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) {
1226                    $x = 0;
1227                    last;
1228                 }
1229             }
1230             if ($x) {
1231                 $j = 0;
1232             } else {
1233                 splice(@$lines, $k);
1234             }
1235         }
1236     }
1237
1238     # OK, if we found TOFU, we will leave a message that we were here...
1239     if ($j) { 
1240         # make sendmail bounce if we shall be picky 
1241         # and indeed found something:
1242         if ($mda) { 
1243             if ($mda ne '1') { 
1244                 print STDERR $boun;
1245
1246                 if ($sysl) {
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();
1253                     }
1254                 }
1255             }
1256
1257             exit EX_BOUNCE;
1258         }
1259
1260         # if we were invoked just for checking and indeed found something,
1261         # print out the error message and quit:
1262         if ($check) {
1263             print $msg_quote;
1264             exit EX_UNAVAILABLE;
1265         }
1266
1267         push(@$lines, "[---=| TOFU protection by $0: " .
1268             "$j lines snipped |=---]\n");
1269     }
1270     elsif ($mda eq '1') { exit EX_OK; }
1271
1272     # Care for huge blocks of quoted original message:
1273     if ($bigqn) { debigq($lines, \@vrb); }
1274
1275     # Care for trailing whitespaces:
1276     if ($trsp) {
1277         for ($x=0; $x<scalar(@$lines); $x++) { 
1278             if (!$vrb[$x]) { $$lines[$x] =~ s/[\ \t]+$//; }
1279         }
1280     }
1281
1282     # Care for punctuation abuse:
1283     if ($elli) {
1284         for ($x=0; $x<scalar(@$lines); $x++) { 
1285             if (!$vrb[$x]) { $$lines[$x] =~ s/(([.?!])\2\2)\2+/$1/eg; }
1286         }
1287     }
1288
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
1291     # list)
1292     if ($cr) {
1293         my $t = 0;
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); }
1297             }
1298             else { $t = 0; }
1299         }
1300     }
1301
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++) {
1310             if ($hdr[$x] =~ 
1311                 s/^(Lines:\s+)(\d+)/$1.($2-$linecount+$l)/e)
1312             { 
1313                 $hdr[$#hdr] = "X-Old-Lines: $2\n";
1314                 push(@hdr, "\n");
1315             }
1316         }
1317     }
1318
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,
1322         @bo2);
1323 }
1324
1325
1326 # environment
1327 my $locale = $ENV{'LC_ALL'}?$ENV{'LC_ALL'}:($ENV{'LC_MESSAGES'}?$ENV{'LC_MESSAGES'}:$ENV{'LANG'});
1328
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
1335
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(); }
1346         $bigqn = $1?$1:30; 
1347         $bigqx = $2?$2:10;
1348         if ($bigqn<=0 || $bigqx<=0 || $bigqn<=$bigqx) { help(); }
1349     }
1350     elsif ($opt eq 'c')     { $cr = 1; }
1351     elsif ($opt eq 'check') {
1352         $check = 1;
1353         while ($val && $val =~ s/^([^,\s]+)(?:,(\S+))?$/$2/) {
1354             my $foo = $1;
1355
1356             if ($foo =~ /^ratio=(0?\.\d+)$/) {
1357                 $check_ratio = $1?$1:1;
1358             }
1359         }
1360     }
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') {
1378         $mua = lc($val);
1379
1380         if ($mua eq 'mutt') {
1381             # mutt still displays the message when ^C'ing pgp verification:
1382             $SIG{'INT'} = 'sigint_handler';
1383         }
1384     }
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; }
1399     else                    { help(); }
1400 }
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
1406 { help(); }
1407
1408
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}; }
1431                 last;
1432             }
1433         }
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}; }
1442                 if ($gpg_aka{$key})
1443                     { $gpg_aka = $gpg_aka{$key}; }
1444                 if ($gpg_bad{$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}; }
1450                 last;
1451             }
1452         }
1453     }
1454
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);
1464
1465     esc(\$gpg_WARNING);
1466     esc(\$gpg_Warning);
1467     esc(\$gpg_Cantcheck);
1468     esc(\$gpg_aka);
1469     esc(\$gpg_bad);
1470     esc(\$gpg_expired);
1471     esc(\$gpg_good);
1472     esc(\$gpg_bug);
1473 }
1474 else {
1475     if ($ms_smart || $pgpshort || $pgpmove || $pgpmovevrf) { help(); }
1476 }
1477
1478 esc(\$spass_prefix);
1479
1480
1481 # Read message:
1482 if (!open(IN, $ifile)) { print STDERR "Could not open $ifile: $!\n"; exit(EX_IOERR); }
1483 my @message = <IN>;
1484 close IN;
1485
1486 # this should be self-explanatory:
1487 process_msg(\@message);
1488
1489 # Finally, print clean lines:
1490 if ($ofile ne 'NONE') {
1491     write_msg(($mda?'|'.SENDMAIL." $mda":">$ofile"), \@message);
1492 }
1493
1494 # vim600:set foldmethod=marker:
1495 # eof