File Coverage

blib/lib/Mail/Mailer.pm
Criterion Covered Total %
statement 43 90 47.7
branch 8 46 17.3
condition 5 20 25.0
subroutine 10 20 50.0
pod 3 11 27.2
total 69 187 36.9


line stmt bran cond sub pod time code
1             # Copyrights 1995-2017 by [Mark Overmeer ].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.02.
5             package Mail::Mailer;
6 3     3   574 use vars '$VERSION';
  3         6  
  3         151  
7             $VERSION = '2.19';
8              
9 3     3   15 use base 'IO::Handle';
  3         4  
  3         999  
10              
11 3     3   13795 use strict;
  3         7  
  3         73  
12 3     3   913 use POSIX qw/_exit/;
  3         15155  
  3         12  
13              
14 3     3   3445 use Carp;
  3         7  
  3         139  
15 3     3   14 use Config;
  3         5  
  3         3660  
16              
17             #--------------
18              
19              
20             sub is_exe($);
21              
22 0     0 1 0 sub Version { our $VERSION }
23              
24             our @Mailers =
25             ( sendmail => '/usr/lib/sendmail;/usr/sbin/sendmail;/usr/ucblib/sendmail'
26             , smtp => undef
27             , smtps => undef
28             , qmail => '/usr/sbin/qmail-inject;/var/qmail/bin/qmail-inject'
29             , testfile => undef
30             );
31              
32             push @Mailers, map { split /\:/, $_, 2 }
33             split /$Config{path_sep}/, $ENV{PERL_MAILERS}
34             if $ENV{PERL_MAILERS};
35              
36             our %Mailers = @Mailers;
37             our $MailerType;
38             our $MailerBinary;
39              
40             # does this really need to be done? or should a default mailer be specified?
41              
42             $Mailers{sendmail} = 'sendmail'
43             if $^O eq 'os2' && ! is_exe $Mailers{sendmail};
44              
45             if($^O =~ m/MacOS|VMS|MSWin|os2|NetWare/i )
46             { $MailerType = 'smtp';
47             $MailerBinary = $Mailers{$MailerType};
48             }
49             else
50             { for(my $i = 0 ; $i < @Mailers ; $i += 2)
51             { $MailerType = $Mailers[$i];
52             if(my $binary = is_exe $Mailers{$MailerType})
53             { $MailerBinary = $binary;
54             last;
55             }
56             }
57             }
58              
59             sub import
60 1     1   9 { shift; # class
61 1 50       1056 @_ or return;
62              
63 0         0 my $type = shift;
64 0   0     0 my $exe = shift || $Mailers{$type};
65              
66 0 0       0 is_exe $exe
67             or carp "Cannot locate '$exe'";
68              
69 0         0 $MailerType = $type;
70 0         0 $Mailers{$MailerType} = $exe;
71             }
72              
73             sub to_array($)
74 0     0 0 0 { my ($self, $thing) = @_;
75 0 0       0 ref $thing ? @$thing : $thing;
76             }
77              
78             sub is_exe($)
79 15   100 15 0 40 { my $exe = shift || '';
80              
81 15         32 foreach my $cmd (split /\;/, $exe)
82 15         31 { $cmd =~ s/^\s+//;
83              
84             # remove any options
85 15         48 my $name = ($cmd =~ /^(\S+)/)[0];
86              
87             # check for absolute or relative path
88 15 0 33     173 return $cmd
      33        
89             if -x $name && ! -d $name && $name =~ m![\\/]!;
90              
91 15 50       32 if(defined $ENV{PATH})
92 15         147 { foreach my $dir (split /$Config{path_sep}/, $ENV{PATH})
93 135 50 33     595 { return "$dir/$cmd"
94             if -x "$dir/$name" && ! -d "$dir/$name";
95             }
96             }
97             }
98 15         45 0;
99             }
100              
101              
102             sub new($@)
103 1     1 1 29 { my ($class, $type, @args) = @_;
104              
105 1 50       6 unless($type)
106 1 50       6 { $MailerType or croak "No MailerType specified";
107              
108 1 50       69 warn "No real MTA found, using '$MailerType'"
109             if $MailerType eq 'testfile';
110              
111 1         8 $type = $MailerType;
112             }
113              
114 1         6 my $exe = $Mailers{$type};
115              
116 1 50       6 if(defined $exe)
117 0 0       0 { $exe = is_exe $exe
118             if defined $type;
119              
120 0 0 0     0 $exe ||= $MailerBinary
121             or croak "No mailer type specified (and no default available), thus can not find executable program.";
122             }
123              
124 1         5 $class = "Mail::Mailer::$type";
125 1 50       79 eval "require $class" or die $@;
126              
127 1         18 my $glob = $class->SUPER::new; # object is a GLOB!
128 1         43 %{*$glob} = (Exe => $exe, Args => [ @args ]);
  1         19  
129 1         6 $glob;
130             }
131              
132              
133             sub open($)
134 0     0 1 0 { my ($self, $hdrs) = @_;
135 0         0 my $exe = *$self->{Exe}; # no exe, then direct smtp
136 0         0 my $args = *$self->{Args};
137              
138 0         0 my @to = $self->who_to($hdrs);
139 0         0 my $sender = $self->who_sender($hdrs);
140            
141 0         0 $self->close; # just in case;
142              
143 0 0       0 if(defined $exe)
144             { # Fork and start a mailer
145 0         0 my $child = open $self, '|-';
146 0 0       0 defined $child or die "Failed to send: $!";
147              
148 0 0       0 if($child==0)
149             { # Child process will handle sending, but this is not real exec()
150             # this is a setup!!!
151 0 0       0 unless($self->exec($exe, $args, \@to, $sender))
152 0         0 { warn $!; # setup failed
153 0         0 _exit(1); # no DESTROY(), keep it for parent
154             }
155             }
156             }
157             else
158             { # Sending is handled by a subclass
159 0 0       0 $self->exec(undef, $args, \@to)
160             or die $!;
161             }
162              
163 0         0 $self->set_headers($hdrs);
164 0         0 $self;
165             }
166              
167             sub _cleanup_hdrs($)
168 0     0   0 { foreach my $h (values %{(shift)})
  0         0  
169 0 0       0 { foreach (ref $h ? @$h : $h)
170 0         0 { s/\n\s*/ /g;
171 0         0 s/\s+$//;
172             }
173             }
174             }
175              
176             sub exec($$$$)
177 0     0 0 0 { my($self, $exe, $args, $to, $sender) = @_;
178              
179             # Fork and exec the mailer (no shell involved to avoid risks)
180 0         0 my @exe = split /\s+/, $exe;
181 0         0 exec @exe, @$args, @$to;
182             }
183              
184 0     0 0 0 sub can_cc { 1 } # overridden in subclass for mailer that can't
185              
186             sub who_to($)
187 0     0 0 0 { my($self, $hdrs) = @_;
188 0         0 my @to = $self->to_array($hdrs->{To});
189 0 0       0 unless($self->can_cc) # Can't cc/bcc so add them to @to
190 0 0       0 { push @to, $self->to_array($hdrs->{Cc} ) if $hdrs->{Cc};
191 0 0       0 push @to, $self->to_array($hdrs->{Bcc}) if $hdrs->{Bcc};
192             }
193 0         0 @to;
194             }
195              
196             sub who_sender($)
197 0     0 0 0 { my ($self, $hdrs) = @_;
198 0   0     0 ($self->to_array($hdrs->{Sender} || $hdrs->{From}))[0];
199             }
200              
201       0 0   sub epilogue {
202             # This could send a .signature, also see ::smtp subclass
203             }
204              
205             sub close(@)
206 0     0 0 0 { my $self = shift;
207 0 0       0 fileno $self or return;
208              
209 0         0 $self->epilogue;
210 0         0 CORE::close $self;
211             }
212              
213 1     1   15 sub DESTROY { shift->close }
214              
215             #--------------
216              
217             1;