+2010-02-15 20:13 Jochen Striepe
+
+ * t-prot: Release as v2.15.
+
+2010-02-15 20:08 Jochen Striepe
+
+ * t-prot.1: Describe --sani more precisely.
+
+2010-02-15 19:21 Jochen Striepe
+
+ * t-prot: Fine-tune some regex.
+
+2010-02-15 19:20 Jochen Striepe
+
+ * t-prot: Fix merging of multiple blank lines within pgp output
+ using -Mmutt.
+
+2010-02-15 19:02 Jochen Striepe
+
+ * t-prot: Simplify expression.
+
+2010-02-15 18:34 Jochen Striepe
+
+ * t-prot, t-prot.1: Add --reply and --sani for fixing annoying
+ headers. Add documentation for both. Many thanks to Matthias
+ Kilian and Martin Neitzel for suggesting and providing some script
+ invoked by procmail rules.
+
+2010-02-14 12:03 Jochen Striepe
+
+ * t-prot.1: Suggest reading about -p when using -P.
+
+2010-02-14 12:00 Jochen Striepe
+
+ * t-prot.1: Sort options in a consistent, alphabetical way.
+
+2010-02-11 20:59 Jochen Striepe
+
+ * t-prot.1: Fix hyphenation. Thanks to Gerfried Fuchs for noticing!
+
+2010-02-11 12:55 Jochen Striepe
+
+ * t-prot.1: Jeff Covey's article should not be missing under SEE
+ ALSO.
+
2010-02-11 11:10 Jochen Striepe
* t-prot: Release as v2.14.
--------
* Support for gpg2. Please send an email to <t-prot@tolot.escape.de>
if you want this feature in vanilla t-prot.
+ * Now Quoted-printable and the lot in Subject, To and From header
+fields is done by --sani, but UTF-8 is still out there.
Rejected issues
+++ /dev/null
---- t-prot 2010-02-11 12:10:47.000000000 +0100
-+++ t-prot-gol 2010-02-11 12:13:49.000000000 +0100
-@@ -4,7 +4,7 @@
- require 5.006;
- use strict;
- use Fcntl qw(O_EXCL O_WRONLY O_CREAT);
--use Getopt::Mixed qw(nextOption);
-+use Getopt::Long qw(:config gnu_getopt no_ignore_case);
- use constant VER => '2.14';
- use constant REV => '';
- use constant REL => q$Revision: 1.280 $=~m/(\d+(?:\.\d+)+)/;
-@@ -913,84 +913,83 @@
- (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- my $ifile = '-'; # use STDIN if nothing specified
-
-+# temp vals:
-+my ($_t1, $_t2, $_t3, $_t4, $_t5, $_t6, $_t7, $_t8, $_t9, $_ta, $_tb) = undef;
-+
- # get command line params:
--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'.
-- ' s t v w bigq:s body check:s debug>d diff ftr-ad ftr-ml groupwise'.
-- ' help>h kminl=i kmaxl=i kdiff=i lax-security locale=s max-lines=i'.
-- ' ms-smart mua>M pgp-short pgp-move pgp-move-vrf sigsmax:i spass'.
-- ' version>v');
--while (my ($opt, $val, $pretty) = nextOption()) {
-- if ($opt eq 'a') { $ad = 1; }
-- elsif ($opt eq 'A') { $ads = $val; }
-- elsif ($opt eq 'bigq') {
-- if ($val !~ /^(?:(\d+)(?:,(\d+))?)?$/) { help(); }
-- $bigqn = $1?$1:30;
-- $bigqx = $2?$2:10;
-- if ($bigqn<=0 || $bigqx<=0 || $bigqn<=$bigqx) { help(); }
-- }
-- elsif ($opt eq 'body') { $nohdr = 1; $hdrs = 1; }
-- elsif ($opt eq 'c') { $cr = 1; }
-- elsif ($opt eq 'check') {
-- $check = 1;
-- while ($val && $val =~ /^([^,\s]+)(?:,(\S+))?$/) {
-- my $foo = $1;
-- $val = $2;
--
-- if ($foo =~ /^ratio(?:=(0?\.\d+))?$/) {
-- $check_ratio = $1?$1:0.75;
-- }
-- }
-- }
-- elsif ($opt eq 'd') { $sysl = 1; }
-- elsif ($opt eq 'diff') { $diff = 1; }
-- elsif ($opt eq 'e') { $elli = 1; }
-- elsif ($opt eq 'ftr-ad') { $ftr_ad = 1; $ad = 1; }
-- elsif ($opt eq 'ftr-ml') { $ftr_ml = 1; $ml = 1; }
-- elsif ($opt eq 'groupwise') { $gw = 1; }
-- elsif ($opt eq 'i') { $ifile = $val; }
-- elsif ($opt eq 'k') { $kamm = 1; }
-- elsif ($opt eq 'kminl') { $kminl = $val; $kamm = 1; }
-- elsif ($opt eq 'kmaxl') { $kmaxl = $val; $kamm = 1; }
-- elsif ($opt eq 'kdiff') { $kdiff = $val; $kamm = 1; }
-- elsif ($opt eq 'L') { $footers = $val; }
-- elsif ($opt eq 'l') { $ml = 1; }
-- elsif ($opt eq 'lax-security') { $lax = 1; }
-- elsif ($opt eq 'locale') { $locale = $val; }
-- elsif ($opt eq 'm') { $ms = 1; }
-- elsif ($opt eq 'max-lines') { $maxlines = $val; }
-- elsif ($opt eq 'ms-smart') { $ms_smart = 1; $ms = 1; }
-- elsif ($opt eq 'M') {
-- $mua = lc($val);
-+if (!Getopt::Long::GetOptions(
-+ 'a' => \$ad,
-+ 'A=s' => \$ads,
-+ 'bigq:s' => \$_t1,
-+ 'c' => \$cr,
-+ 'check:s' => \$_t9,
-+ 'debug|d' => \$sysl,
-+ 'diff' => \$diff,
-+ 'e' => \$elli,
-+ 'ftr-ad' => \$ftr_ad,
-+ 'ftr-ml' => \$ftr_ml,
-+ 'groupwise' => \$gw,
-+ 'help|h' => \$_t2,
-+ 'i=s' => \$ifile,
-+ 'k' => \$kamm,
-+ 'kminl=i' => \$_t3,
-+ 'kmaxl=i' => \$_t4,
-+ 'kdiff=i' => \$_t5,
-+ 'L=s' => \$footers,
-+ 'l' => \$ml,
-+ 'lax-security' => \$lax,
-+ 'locale=s' => \$locale,
-+ 'max-lines=i' => \$maxlines,
-+ 'ms-smart' => \$ms_smart,
-+ 'mua|M=s' => \$_t7,
-+ 'm' => \$ms,
-+ 'o=s' => \$ofile,
-+ 'P=s' => \$boun,
-+ 'p:s' => \$_t8,
-+ 'pgp-short' => \$pgpshort,
-+ 'pgp-move' => \$pgpmove,
-+ 'pgp-move-vrf' => \$pgpmovevrf,
-+ 'r' => \$hdrs,
-+ 'S:i' => \$_t6,
-+ 's' => \$sig,
-+ 'sigsmax:i' => \$_ta,
-+ 'spass' => \$spass,
-+ 't' => \$trad,
-+ 'version|v' => \$_tb,
-+ 'w' => \$trsp
-+ )) {
-+ help();
-+}
-
-- if ($mua eq 'mutt') {
-- # mutt still displays the message when ^C'ing pgp verification:
-- $SIG{'INT'} = 'sigint_handler';
-- }
-+# clean up temp vals:
-+if (defined $_t1) {
-+ if ($_t1 !~ /^(?:(\d+)(?:,(\d+))?)?$/) { help(); }
-+ $bigqn = $1?$1:30;
-+ $bigqx = $2?$2:10;
-+ if ($bigqn<=0 || $bigqx<=0 || $bigqn<=$bigqx) { help(); }
-+}
-+if (defined $_t2) { help(); }
-+if (defined $_t3) { $kminl = $_t3; $kamm = 1; }
-+if (defined $_t4) { $kmaxl = $_t4; $kamm = 1; }
-+if (defined $_t5) { $kdiff = $_t5; $kamm = 1; }
-+if (defined $_t6) { $lsig = $_t6 ? $_t6 : $maxsig; }
-+if (defined $_t7) {
-+ $mua = lc($_t7);
-+ # mutt still displays the message when ^C'ing pgp verification:
-+ if ($mua eq 'mutt') { $SIG{'INT'} = 'sigint_handler'; }
-+}
-+if (defined $_t8) { $mda = $_t8 ? $_t8 : '1'; }
-+if (defined $_t9) {
-+ $check = 1;
-+ while ($_t9 && $_t9 =~ /^([^,\s]+)(?:,(\S+))?$/) {
-+ my $foo = $1;
-+ $_t9 = $2;
-+ if ($foo =~ /^ratio(?:=(0?\.\d+))?$/) { $check_ratio = $1?$1:0.75; }
- }
-- elsif ($opt eq 'o') { $ofile = $val; }
-- elsif ($opt eq 'P') { $boun = $val; }
-- elsif ($opt eq 'p') { $mda = $val ? $val : '1'; }
-- elsif ($opt eq 'pgp-short') { $pgpshort = 1; }
-- elsif ($opt eq 'pgp-move') { $pgpmove = 1; }
-- elsif ($opt eq 'pgp-move-vrf') { $pgpmovevrf = 1; }
-- elsif ($opt eq 'r') { $hdrs = 1; }
-- elsif ($opt eq 'S') { $lsig = $val ? $val : $maxsig; }
-- elsif ($opt eq 's') { $sig = 1; }
-- elsif ($opt eq 'sigsmax') { $sign = $val ? $val : undef; }
-- elsif ($opt eq 'spass') { $spass = 1; }
-- elsif ($opt eq 't') { $trad = 1; }
-- elsif ($opt eq 'v') { version(); }
-- elsif ($opt eq 'w') { $trsp = 1; }
-- else { help(); }
- }
--Getopt::Mixed::cleanup();
--if (($ml && $footers eq '')|| # no -l without -L
-- ($ad && $ads eq '')|| # no -a without -A
-- ($nohdr && $pgpshort)|| # --body and --pgp-short are like oil and water
-- ($ifile eq '')|| # no empty -i
-- ($ofile eq '')) # no empty -o
--{ help(); }
--
-+if (defined $_ta) { $sign = $_ta ? $_ta : undef; }
-+if (defined $_tb) { version(); }
-+if ($ms_smart) { $ms = 1; }
-
- if ($mua eq 'mutt') {
- if (defined $locale && $locale ne '' && $locale ne 'C' && $locale ne 'POSIX') {
-@@ -1055,6 +1054,13 @@
-
- }
- elsif ($ms_smart || $pgpshort || $pgpmove || $pgpmovevrf) { help(); }
-+
-+if (($ml && $footers eq '')|| # no -l without -L
-+ ($ad && $ads eq '')|| # no -a without -A
-+ ($nohdr && $pgpshort)|| # --body and --pgp-short are like oil and water
-+ ($ifile eq '')|| # no empty -i
-+ ($ofile eq '')) # no empty -o
-+{ help(); }
-
-
- # Read message:
--- /dev/null
+--- t-prot 2010-02-15 21:13:00.000000000 +0100
++++ t-prot-gol 2010-02-15 21:20:35.000000000 +0100
+@@ -4,7 +4,7 @@
+ require 5.006;
+ use strict;
+ use Fcntl qw(O_EXCL O_WRONLY O_CREAT);
+-use Getopt::Mixed qw(nextOption);
++use Getopt::Long qw(:config gnu_getopt no_ignore_case);
+ use constant VER => '2.15';
+ use constant REV => '';
+ use constant REL => q$Revision: 1.285 $=~m/(\d+(?:\.\d+)+)/;
+@@ -986,87 +986,87 @@
+ (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ my $ifile = '-'; # use STDIN if nothing specified
+
++# temp vals:
++my ($_t1, $_t2, $_t3, $_t4, $_t5, $_t6, $_t7, $_t8, $_t9, $_ta, $_tb, $_tc) = undef;
++
+ # get command line params:
+-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'.
+- ' s t v w bigq:s body check:s debug>d diff ftr-ad ftr-ml groupwise'.
+- ' help>h kminl=i kmaxl=i kdiff=i lax-security locale=s max-lines=i'.
+- ' ms-smart mua>M pgp-short pgp-move pgp-move-vrf reply sani sigsmax:i'.
+- ' spass version>v');
+-while (my ($opt, $val, $pretty) = nextOption()) {
+- if ($opt eq 'a') { $ad = 1; }
+- elsif ($opt eq 'A') { $ads = $val; }
+- elsif ($opt eq 'bigq') {
+- if ($val !~ /^(?:(\d+)(?:,(\d+))?)?$/) { help(); }
+- $bigqn = $1?$1:30;
+- $bigqx = $2?$2:10;
+- if ($bigqn<=0 || $bigqx<=0 || $bigqn<=$bigqx) { help(); }
+- }
+- elsif ($opt eq 'body') { $nohdr = 1; $hdrs = 1; }
+- elsif ($opt eq 'c') { $cr = 1; }
+- elsif ($opt eq 'check') {
+- $check = 1;
+- while ($val && $val =~ /^([^,\s]+)(?:,(\S+))?$/) {
+- my $foo = $1;
+- $val = $2;
+-
+- if ($foo =~ /^ratio(?:=(0?\.\d+))?$/) {
+- $check_ratio = $1?$1:0.75;
+- }
+- }
+- }
+- elsif ($opt eq 'd') { $sysl = 1; }
+- elsif ($opt eq 'diff') { $diff = 1; }
+- elsif ($opt eq 'e') { $elli = 1; }
+- elsif ($opt eq 'ftr-ad') { $ftr_ad = 1; $ad = 1; }
+- elsif ($opt eq 'ftr-ml') { $ftr_ml = 1; $ml = 1; }
+- elsif ($opt eq 'groupwise') { $gw = 1; }
+- elsif ($opt eq 'i') { $ifile = $val; }
+- elsif ($opt eq 'k') { $kamm = 1; }
+- elsif ($opt eq 'kminl') { $kminl = $val; $kamm = 1; }
+- elsif ($opt eq 'kmaxl') { $kmaxl = $val; $kamm = 1; }
+- elsif ($opt eq 'kdiff') { $kdiff = $val; $kamm = 1; }
+- elsif ($opt eq 'L') { $footers = $val; }
+- elsif ($opt eq 'l') { $ml = 1; }
+- elsif ($opt eq 'lax-security') { $lax = 1; }
+- elsif ($opt eq 'locale') { $locale = $val; }
+- elsif ($opt eq 'm') { $ms = 1; }
+- elsif ($opt eq 'max-lines') { $maxlines = $val; }
+- elsif ($opt eq 'ms-smart') { $ms_smart = 1; $ms = 1; }
+- elsif ($opt eq 'M') {
+- $mua = lc($val);
++if (!Getopt::Long::GetOptions(
++ 'a' => \$ad,
++ 'A=s' => \$ads,
++ 'bigq:s' => \$_t1,
++ 'body' => \$_tc,
++ 'c' => \$cr,
++ 'check:s' => \$_t9,
++ 'debug|d' => \$sysl,
++ 'diff' => \$diff,
++ 'e' => \$elli,
++ 'ftr-ad' => \$ftr_ad,
++ 'ftr-ml' => \$ftr_ml,
++ 'groupwise' => \$gw,
++ 'help|h' => \$_t2,
++ 'i=s' => \$ifile,
++ 'k' => \$kamm,
++ 'kminl=i' => \$_t3,
++ 'kmaxl=i' => \$_t4,
++ 'kdiff=i' => \$_t5,
++ 'L=s' => \$footers,
++ 'l' => \$ml,
++ 'lax-security' => \$lax,
++ 'locale=s' => \$locale,
++ 'max-lines=i' => \$maxlines,
++ 'ms-smart' => \$ms_smart,
++ 'mua|M=s' => \$_t7,
++ 'm' => \$ms,
++ 'o=s' => \$ofile,
++ 'P=s' => \$boun,
++ 'p:s' => \$_t8,
++ 'pgp-short' => \$pgpshort,
++ 'pgp-move' => \$pgpmove,
++ 'pgp-move-vrf' => \$pgpmovevrf,
++ 'r' => \$hdrs,
++ 'reply' => \$reply,
++ 'S:i' => \$_t6,
++ 's' => \$sig,
++ 'sani' => \$sani,
++ 'sigsmax:i' => \$_ta,
++ 'spass' => \$spass,
++ 't' => \$trad,
++ 'version|v' => \$_tb,
++ 'w' => \$trsp
++ )) {
++ help();
++}
+
+- if ($mua eq 'mutt') {
+- # mutt still displays the message when ^C'ing pgp verification:
+- $SIG{'INT'} = 'sigint_handler';
+- }
++# clean up temp vals:
++if (defined $_t1) {
++ if ($_t1 !~ /^(?:(\d+)(?:,(\d+))?)?$/) { help(); }
++ $bigqn = $1?$1:30;
++ $bigqx = $2?$2:10;
++ if ($bigqn<=0 || $bigqx<=0 || $bigqn<=$bigqx) { help(); }
++}
++if (defined $_t2) { help(); }
++if (defined $_t3) { $kminl = $_t3; $kamm = 1; }
++if (defined $_t4) { $kmaxl = $_t4; $kamm = 1; }
++if (defined $_t5) { $kdiff = $_t5; $kamm = 1; }
++if (defined $_t6) { $lsig = $_t6 ? $_t6 : $maxsig; }
++if (defined $_t7) {
++ $mua = lc($_t7);
++ # mutt still displays the message when ^C'ing pgp verification:
++ if ($mua eq 'mutt') { $SIG{'INT'} = 'sigint_handler'; }
++}
++if (defined $_t8) { $mda = $_t8 ? $_t8 : '1'; }
++if (defined $_t9) {
++ $check = 1;
++ while ($_t9 && $_t9 =~ /^([^,\s]+)(?:,(\S+))?$/) {
++ my $foo = $1;
++ $_t9 = $2;
++ if ($foo =~ /^ratio(?:=(0?\.\d+))?$/) { $check_ratio = $1?$1:0.75; }
+ }
+- elsif ($opt eq 'o') { $ofile = $val; }
+- elsif ($opt eq 'P') { $boun = $val; }
+- elsif ($opt eq 'p') { $mda = $val ? $val : '1'; }
+- elsif ($opt eq 'pgp-short') { $pgpshort = 1; }
+- elsif ($opt eq 'pgp-move') { $pgpmove = 1; }
+- elsif ($opt eq 'pgp-move-vrf') { $pgpmovevrf = 1; }
+- elsif ($opt eq 'r') { $hdrs = 1; }
+- elsif ($opt eq 'reply') { $reply = 1; }
+- elsif ($opt eq 'S') { $lsig = $val ? $val : $maxsig; }
+- elsif ($opt eq 's') { $sig = 1; }
+- elsif ($opt eq 'sani') { $sani = 1; }
+- elsif ($opt eq 'sigsmax') { $sign = $val ? $val : undef; }
+- elsif ($opt eq 'spass') { $spass = 1; }
+- elsif ($opt eq 't') { $trad = 1; }
+- elsif ($opt eq 'v') { version(); }
+- elsif ($opt eq 'w') { $trsp = 1; }
+- else { help(); }
+ }
+-Getopt::Mixed::cleanup();
+-if (($ml && $footers eq '')|| # no -l without -L
+- ($ad && $ads eq '')|| # no -a without -A
+- ($nohdr && $pgpshort)|| # --body and --pgp-short are oil and water
+- (($nohdr||$hdrs) && ($sani||$reply))|| # no sanitazing without headers :)
+- ($ifile eq '')|| # no empty -i
+- ($ofile eq '')) # no empty -o
+-{ help(); }
+-
++if (defined $_ta) { $sign = $_ta ? $_ta : undef; }
++if (defined $_tb) { version(); }
++if (defined $_tc) { $nohdr=1; $hdrs=1; }
++if ($ms_smart) { $ms = 1; }
+
+ if ($mua eq 'mutt') {
+ if (defined $locale && $locale ne '' && $locale ne 'C' && $locale ne 'POSIX') {
+@@ -1131,6 +1131,14 @@
+
+ }
+ elsif ($ms_smart || $pgpshort || $pgpmove || $pgpmovevrf) { help(); }
++
++if (($ml && $footers eq '')|| # no -l without -L
++ ($ad && $ads eq '')|| # no -a without -A
++ ($nohdr && $pgpshort)|| # --body and --pgp-short are like oil and water
++ (($nohdr||$hdrs) || ($sani||$reply))|| # no sanitizing without headers :)
++ ($ifile eq '')|| # no empty -i
++ ($ofile eq '')) # no empty -o
++{ help(); }
+
+
+ # Read message:
#!/usr/bin/perl -w
-# $Id: t-prot,v 1.280 2010/02/11 11:10:47 jochen Exp $
+# $Id: t-prot,v 1.285 2010/02/15 20:13:00 jochen Exp $
require 5.006;
use strict;
use Fcntl qw(O_EXCL O_WRONLY O_CREAT);
use Getopt::Mixed qw(nextOption);
-use constant VER => '2.14';
+use constant VER => '2.15';
use constant REV => '';
-use constant REL => q$Revision: 1.280 $=~m/(\d+(?:\.\d+)+)/;
+use constant REL => q$Revision: 1.285 $=~m/(\d+(?:\.\d+)+)/;
# MTA expecting mail on STDIN
# (you might have to adjust this if using a different MTA)
use constant SENDMAIL => '/usr/sbin/sendmail -oi';
$ad $ads $bigqn $bigqx $boun $check $check_ratio $cr $diff $elli
$footers $ftr_ad $ftr_ml $hdrs $indent $kamm $kdiff $kminl $kmaxl
$lax $lsig $maxsig $maxlines $mda $ml $gw $ms $ms_smart $msg_quote
- $msg_ratio $mua $nohdr $ofile $pgpshort $pgpmove $pgpmovevrf $sig
- $sigint $sign $spass $spass_prefix $sysl $trad $trsp
+ $msg_ratio $mua $nohdr $ofile $pgpshort $pgpmove $pgpmovevrf $reply
+ $sani $sig $sigint $sign $spass $spass_prefix $sysl $trad $trsp
$gpg_WARNING $gpg_Warning $gpg_Cantcheck $gpg_aka $gpg_bad
$gpg_expired $gpg_good $gpg_bug
--pgp-move-vrf move pgp output if verified and good; requires -Mmutt
--pgp-short hide non-relevant pgp key uids; requires -Mmutt
-r delete mail header lines
+ --reply squeeze multiple reply prefixes in subject line
-S[=n] supress signatures with more than n lines (default $maxsig)
-s delete signature
+ --sani sanitize some header fields
--sigsmax[=n] max number of sigs tolerated, no value for unlimited
--spass enable SpamAssassin workaround
-t delete traditional style TOFU
$sigint = 1;
}
+sub sanitize_hdr {
+ # Undoes MIME quoted-printable word encoding.
+ sub qp_decode {
+ my $word = shift;
+ $word =~ tr/_/\x20/;
+ $word =~ s/=DF/ss/og;
+ $word =~ s/=C4/Ae/og;
+ $word =~ s/=D6/Oe/og;
+ $word =~ s/=DC/Ue/og;
+ $word =~ s/=E4/ae/og;
+ $word =~ s/=F6/oe/og;
+ $word =~ s/=FC/ue/og;
+ $word =~ s/=([0-9A-F]{2})/chr(hex $1)/ioge;
+ $word;
+ }
+
+ sub umlauts {
+ my $word = shift;
+ $word =~ s/ä/ae/og;
+ $word =~ s/Ä/Ae/og;
+ $word =~ s/ö/oe/og;
+ $word =~ s/Ö/Oe/og;
+ $word =~ s/ü/ue/og;
+ $word =~ s/Ü/Ue/og;
+ $word =~ s/ß/ss/og;
+ $word;
+ }
+
+ my $H = shift; # array of header lines
+ my $i;
+
+ for ($i=0; $i<$#$H; $i++) {
+ if ($$H[$i] =~ /^subject: /io) {
+ if ($sani) {
+ $$H[$i] =~ s/=\?iso-8859-15?\?q\?([^?]*)\?=/qp_decode($1)/ioge;
+ $$H[$i] =~ s/^subject: *(.*)/"Subject: " . umlauts($1)/ioe;
+ }
+ if ($reply) {
+ $$H[$i] =~ s/^subject: *(?:(?:Re|Antw(?:ort)?|AW|WG): *)+/Subject: Re: /io;
+ }
+
+ $i++;
+ while ($i<$#$H && $$H[$i] =~ /^\s/) {
+ if ($sani) {
+ $$H[$i] =~ s/=\?iso-8859-15?\?q\?([^?]*)\?=/qp_decode($1)/ioge;
+ $$H[$i] =~ s/^\s+(\S.*)/" " . umlauts($1)/ioe;
+ }
+ if ($reply) {
+ $$H[$i] =~ s/^\s+(?:(?:Re|Antw(?:ort)?|AW|WG): *)+/ /io;
+ }
+ $i++;
+ }
+ }
+ elsif ($sani && $$H[$i] =~ /^(?:from|to): /io) {
+ $$H[$i] =~ s/=\?iso-8859-15?\?q\?([^?]*)\?=/qp_decode($1)/ioge;
+
+ $i++;
+ while ($i<$#$H && $$H[$i] =~ /^\s/) {
+ $$H[$i] =~ s/=\?iso-8859-15?\?q\?([^?]*)\?=/qp_decode($1)/ioge;
+ $i++;
+ }
+ }
+ }
+}
+
# remove_footers(): remove any trailing appearance of footers contained
# in the given directory.
sub remove_footers {
# remember the original body lines count
my $linecount = scalar(@$lines);
+ # Sanitize header fields:
+ if ($reply || $sani) { sanitize_hdr(\@hdr); }
+
# Remove ML footers:
remove_footers($lines, \@ftr, $footers, undef, $ftr_ml);
# Care for trailing whitespaces:
if ($trsp) {
for ($x=0; $x<scalar(@$lines); $x++) {
- if (!$vrb[$x]) { $$lines[$x] =~ s/[\ \t]+$//; }
+ if (!$vrb[$x]) { $$lines[$x] =~ s/[\ \t]+$//o; }
}
}
# Care for punctuation abuse:
if ($elli) {
for ($x=0; $x<scalar(@$lines); $x++) {
- if (!$vrb[$x]) { $$lines[$x] =~ s/(([.?!])\2\2)\2+/$1/g; }
+ if (!$vrb[$x]) { $$lines[$x] =~ s/(([.?!])\2\2)\2+/$1/go; }
}
}
if ($cr) {
my $t = 0;
for ($x=scalar(@$lines)-1; $x>=0; $x--) {
- if ((!$vrb[$x]) && $$lines[$x] =~ /^\s*$/) {
+ if ((!$vrb[$x]) &&
+ (($mua eq 'mutt' && $$lines[$x] =~ /^\e[^\a]+\a\s*$/o) ||
+ $$lines[$x] =~ /^\s*$/o))
+ {
if ($t<2) { $t++; } else { splice(@$lines, $x, 1); }
}
else { $t = 0; }
# command line switches
($ad, $ads, $bigqn, $bigqx, $check, $cr, $sysl, $diff, $elli, $footers, $lax,
- $ml, $gw, $ms, $ms_smart, $mda, $mua, $hdrs, $kamm, $lsig, $nohdr, $sig,
- $sigint, $spass, $trad, $trsp) =
- (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ $ml, $gw, $ms, $ms_smart, $mda, $mua, $hdrs, $kamm, $lsig, $nohdr, $reply,
+ $sani, $sig, $sigint, $spass, $trad, $trsp) =
+ (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
my $ifile = '-'; # use STDIN if nothing specified
# get command line params:
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'.
' s t v w bigq:s body check:s debug>d diff ftr-ad ftr-ml groupwise'.
' help>h kminl=i kmaxl=i kdiff=i lax-security locale=s max-lines=i'.
- ' ms-smart mua>M pgp-short pgp-move pgp-move-vrf sigsmax:i spass'.
- ' version>v');
+ ' ms-smart mua>M pgp-short pgp-move pgp-move-vrf reply sani sigsmax:i'.
+ ' spass version>v');
while (my ($opt, $val, $pretty) = nextOption()) {
if ($opt eq 'a') { $ad = 1; }
elsif ($opt eq 'A') { $ads = $val; }
elsif ($opt eq 'pgp-move') { $pgpmove = 1; }
elsif ($opt eq 'pgp-move-vrf') { $pgpmovevrf = 1; }
elsif ($opt eq 'r') { $hdrs = 1; }
+ elsif ($opt eq 'reply') { $reply = 1; }
elsif ($opt eq 'S') { $lsig = $val ? $val : $maxsig; }
elsif ($opt eq 's') { $sig = 1; }
+ elsif ($opt eq 'sani') { $sani = 1; }
elsif ($opt eq 'sigsmax') { $sign = $val ? $val : undef; }
elsif ($opt eq 'spass') { $spass = 1; }
elsif ($opt eq 't') { $trad = 1; }
else { help(); }
}
Getopt::Mixed::cleanup();
-if (($ml && $footers eq '')|| # no -l without -L
- ($ad && $ads eq '')|| # no -a without -A
- ($nohdr && $pgpshort)|| # --body and --pgp-short are like oil and water
- ($ifile eq '')|| # no empty -i
- ($ofile eq '')) # no empty -o
+if (($ml && $footers eq '')|| # no -l without -L
+ ($ad && $ads eq '')|| # no -a without -A
+ ($nohdr && $pgpshort)|| # --body and --pgp-short are oil and water
+ (($nohdr||$hdrs) && ($sani||$reply))|| # no sanitazing without headers :)
+ ($ifile eq '')|| # no empty -i
+ ($ofile eq '')) # no empty -o
{ help(); }
-.\" $Id: t-prot.1,v 1.151 2010/02/07 22:10:06 jochen Exp $
+.\" $Id: t-prot.1,v 1.157 2010/02/15 20:08:19 jochen Exp $
.\"
.TH T-PROT "1" "February 2010" "T-PROT"
.SH NAME
.IP
Please also note that enabling this option is quite a performance hit.
.TP
-.BR "\-\-kminl" =n
-Minimum line length for wrapped line detection on Kammquotes. For
-details, please see the source code.
+.BR "\-\-kdiff" =n
+Minimum length difference between two lines for wrapped line detection on
+Kammquotes. For details, please see the source code.
.br
Anyway, lower values make the algorithm more aggressive, higher values
-make Kammquotes harder to detect. Default is 65.
+make Kammquotes harder to detect. Default is 20.
.sp
Requires
.BR "\-k" .
Requires
.BR "\-k" .
.TP
-.BR "\-\-kdiff" =n
-Minimum length difference between two lines for wrapped line detection on
-Kammquotes. For details, please see the source code.
+.BR "\-\-kminl" =n
+Minimum line length for wrapped line detection on Kammquotes. For
+details, please see the source code.
.br
Anyway, lower values make the algorithm more aggressive, higher values
-make Kammquotes harder to detect. Default is 20.
+make Kammquotes harder to detect. Default is 65.
.sp
Requires
.BR "\-k" .
.br
and some header lines...)
.TP
+.BR "\-\-max\-lines" =x
+Maximum number of lines a message may count (with headers). If the message
+is longer than x lines, the message will not be processed but printed
+unmodified. Exit status will be EX_DATAERR except when called with \-Mmutt.
+.TP
.B "\-\-ms\-smart"
Burn CPU cycles trying to be smart with MS style TOFU.
.sp
.BR "\-Mmutt" " and"
.BR "\-m" .
.TP
-.BR "\-\-max\-lines" =x
-Maximum number of lines a message may count (with headers). If the message
-is longer than x lines, the message will not be processed but printed
-unmodified. Exit status will be EX_DATAERR except when called with -Mmutt.
-.TP
.BR "\-o" =FILE
"output file":
Define the file to be written *to*; the default output is to STDOUT.
if all you need is t-prot's exit code). Use something like "./NONE" if you
really want to write to a file of this name.
.TP
+.BR "\-P" =MESSAGE
+"user defined bounce message for picky delivery":
+You may specify your own bounce message to be returned when we try to deliver
+an email and bounce it because there is TOFU inside. See
+.BR "\-p" .
+.TP
.BR "\-p" [=ADDRESS]
"picky delivery":
If we really find some TOFU, abort with exit code
.sp
.B PLEASE be careful not to bounce messages to mailing lists!
.TP
-.BR "\-P" =MESSAGE
-"user defined bounce message for picky delivery":
-You may specify your own bounce message to be returned when we try to deliver
-an email and bounce it because there is TOFU inside.
-.TP
.B \-\-pgp\-move
Move PGP verification output to bottom; requires
.BR "\-Mmutt" .
"rip header off":
Hides all mail header lines.
.TP
+.B "\-\-reply"
+Subject lines with multiple reply prefixes (Re: and translations into other
+languages) get squeezed to only one prefix.
+.TP
.BR "\-S" [=n]
"supression of overlong signatures":
Signatures are to be n lines (not including the one containing dash-dash-space)
Hides signatures, i.e. all lines after a "signature dashes" line,
i.e. a line with three characters: dash-dash-space (no more, no less).
.TP
+.B "\-\-sani"
+Sanitize headers "To:", "From:" and "Subject:": Quoted-printable gets
+fixed to the corresponding chars. German Umlauts are translated to their
+"ae", "oe", "ue" pendants.
+.br
+Useful e.g. for searching by subject within MUAs like Berkeley mailx.
+.TP
.BR "\-\-sigsmax" [=n]
"maximum number of tolerated signatures":
Here you can define how many signatures you accept to be treated as such.
.sp
RFCs 2045-2049 and 5322,
.sp
+.I http://freshmeat.net/articles/t\-prot/
+(a nice, solid introduction),
+.br
.I http://got.to/quote/
(German language),
.br