use strict;
use warnings;
+use File::Basename;
+BEGIN {
+ use lib $ENV{"PERLMAIL_BASEDIR"} || File::Basename::dirname($0);
+ use PerlMail::Config;
+ }
+
require Getopt::Long;
use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG WIFSTOPPED WSTOPSIG);
-require Mail::Header;
+require MIME::Head; # inherits Mail::Header
require Mail::Address;
-require File::Basename;
-my $sendmail_orig=(-x ($_="/usr/sbin/sendmail-orig") ? $_ : "/usr/sbin/sendmail");
-my $HOME="/home/lace";
-my $opt_F;
-sub FromAddress
-{
-my($rcpt,$iserror)=@_;
- return Mail::Address->new(
- (defined $opt_F ? $opt_F : "Jan Kratochvil"),
- (!$iserror ? 'rcpt' : 'rcpterr')
- .'-'
- .(defined($rcpt->user()) ? $rcpt->user() : "NOUSER")
- .".AT."
- .(defined($rcpt->host()) ? $rcpt->host() : "LOCAL")
- .'@jankratochvil.net',
- );
-}
-
-# RedHat sendmail-8.9.3-20/src/conf.c/HdrInfo[]/\Q/* destination fields */\E
-# FIXME: Recognize "Resent-$_" headers for -t but when we are in 'resent' mode?
-my @h_rcpt=( # case in-sensitive!
- "To",
- "Cc",
- "Bcc",
- "Apparently-To",
- );
-
-# ordering matters; first header found is substituted
-# last header is subsituted if no one is found
-my @h_from=(
- "Resent-From",
- "From",
- );
-
-
-# FIXME: modularized unification with 'lacemail-accept'
-# BEGIN lacemail-accept
+# FIXME: modularized unification with 'perlmail-accept'
+# BEGIN perlmail-accept
our %muttrc_pending=();
sub muttrc
{
}
return wantarray() ? %r : $r{$r[0]};
}
-# END lacemail-accept
+# END perlmail-accept
sub sendmail_show { return "\"$sendmail_orig\" ".join(",",map("\"$_\"",@ARGV)); }
my $opt_q;
my $opt_t;
our $opt_f;
-#my $opt_F; # declared before &FromAddress already
-my $opt_lacemail_dry_run;
+our $opt_F; # from PerlMail::Config;
+my $opt_perlmail_dry_run;
my @ARGV_save=@ARGV; # for non-bm mode
die if !Getopt::Long::GetOptions(
"b=s" ,\$opt_b,
"t" ,\$opt_t,
"f=s" ,\$opt_f,
"F=s" ,\$opt_F,
- "lacemail-dry-run+",\$opt_lacemail_dry_run,
+ "perlmail-dry-run+",\$opt_perlmail_dry_run,
);
if (0
# RedHat sendmail-8.12.5-7/sendmail/main.c/\QDo a quick prescan of the argument list.\E
# RedHat sendmail-8.9.3-20/src/main.c/main()/\Qif (FullName != NULL)\E
# for $opt_F is implemented by Mail::Address in our &FromAddress
-my $head=Mail::Header->new(\*STDIN);
-# We may (=will) change the contents and send it multiple times
-if (defined(my $msgid=$head->get("Message-ID"))) {
- $head->delete("Message-ID");
- $head->replace("X-LaceMail-sendmail-Message-ID",$msgid);
- }
+my $head=MIME::Head->new(\*STDIN);
# options leave in @ARGV, addresses to @addr:
my @args=@ARGV; # temporary
@ARGV=(); # options
my $muttrc_From=parseone(scalar muttrc_get("from")); # may get undef()!; parseone() may be redundant
$muttrc_From=$muttrc_From->address() if $muttrc_From;
$opt_f=undef() if defined($opt_f) && $muttrc_From && lc($opt_f) eq lc($muttrc_From);
- my @from_val;
for (@h_from) {
$from_headername=$_; # leave last item in $from_headername
- last if @from_val=$head->get($from_headername);
- }
- @from_val=map({ ($_->address()); } map({ (Mail::Address->parse($_)); } @from_val));
- $from_headername=undef() if !(1==@from_val && $muttrc_From && lc($from_val[0]) eq lc($muttrc_From));
+ next if !(my @from_val=$head->get($from_headername));
+ @from_val=map({ ($_->address()); } map({ (Mail::Address->parse($_)); } @from_val));
+ $from_headername=undef() if !(1==@from_val && $muttrc_From && lc($from_val[0]) eq lc($muttrc_From));
+ last;
+ } # fallthru with $from_headername remaining set if last headername did not exist
# now $from_headername contains the header name to be replaced w/substituted value
}
+# to be utilized later by &FromAddress
+our $is_pgp; # from PerlMail::Config;
+$is_pgp=(1
+ && do { local $_=$head->mime_attr("Content-Type"); $_ && ~m#^multipart/(?:signed|encrypted)$#; }
+ && do { local $_=$head->mime_attr("Content-Type.protocol"); $_ && ~m#^application/pgp\b#; }
+ );
+
my $exitcode=0;
-my @rcpts=(@addr ? @addr : (undef())); # !defined($rcpt) if we have no recipients
+# !defined($rcpt) if we have no recipients
+# make the list unique to prevent dupes being normally filtered by sendmail(8)
+# one '{' is block-wrapper, another '{' is hash-indirection!
+# hash keys are just strings, never refs!
+# unify the list as Mail::Address instances
+my @rcpts=(!@addr ? (undef()) : values(%{{ map({
+ my $obj=$_;
+ $obj=parseone $obj if !ref $obj;
+ (!defined $obj ? () : (lc($obj->address())=>$obj));
+ } @addr) }}));
+
my $stdin_body=(@rcpts<=1 ? undef() : do { # store input data only if it will be used multiple times
local $/=undef();
<STDIN>;
if (defined $rcpt) { # !defined($rcpt) if we have no recipients
local $_;
- if (!ref $rcpt) {
- $rcpt=parseone $rcpt;
- next if !defined $rcpt;
- }
$opt_f=FromAddress($rcpt,1)->address() if !defined $opt_f;
$head->replace($from_headername,FromAddress($rcpt,0)->format()) if $from_headername;
}
# "From/Resent-From" should be handled by our &FromAddress
push @ARGV,"-F",$opt_F if defined $opt_F;
push @ARGV,$rcpt->address() if defined $rcpt;
+ push @ARGV,@addr_addon;
local $SIG{"PIPE"}=sub { die "Got SIGPIPE from ".sendmail_show(); };
local *SENDMAIL;
- if ($opt_lacemail_dry_run) {
+ if ($opt_perlmail_dry_run) {
print sendmail_show()."\n";
*SENDMAIL=\*STDOUT;
}
sendmail_orig_exec() if !$pid; # child
}
$head->print(\*SENDMAIL);
- print "\n"; # Mail::Header->print() eats the empty line but it doesn't print it
+ print SENDMAIL "\n"; # MIME::Head->print() eats the empty line but it doesn't print it
if (defined($stdin_body)) {
print SENDMAIL $stdin_body;
}
}
}
- next if $opt_lacemail_dry_run; # don't close our STDOUT as it is aliased to *SENDMAIL
+ next if $opt_perlmail_dry_run; # don't close our STDOUT as it is aliased to *SENDMAIL
close SENDMAIL or warn "close(".sendmail_show()."): $?=".join(",",
(!WIFEXITED($?) ? () : ("EXITSTATUS(".WEXITSTATUS($?).")")),
(!WIFSIGNALED($?) ? () : ("TERMSIG(" .WTERMSIG($?) .")")),