File Coverage

blib/lib/Mail/Sender.pm
Criterion Covered Total %
statement 285 1262 22.5
branch 72 734 9.8
condition 58 360 16.1
subroutine 58 100 58.0
pod 27 38 71.0
total 500 2494 20.0


line stmt bran cond sub pod time code
1             package Mail::Sender;
2              
3 2     2   30420 use strict;
  2         6  
  2         101  
4 2     2   15 use warnings;
  2         5  
  2         99  
5 2     2   14 use base 'Exporter';
  2         8  
  2         358  
6              
7 2     2   15 no warnings 'uninitialized';
  2         6  
  2         116  
8 2     2   15 use Carp ();
  2         4  
  2         49  
9 2     2   2548 use Encode ();
  2         36267  
  2         111  
10 2     2   28 use File::Basename ();
  2         4  
  2         68  
11 2     2   1628 use IO::Socket::INET ();
  2         74998  
  2         62  
12 2     2   1381 use MIME::Base64 ();
  2         1422  
  2         57  
13 2     2   1169 use MIME::QuotedPrint ();
  2         464  
  2         40  
14 2     2   12 use Socket ();
  2         2  
  2         28  
15 2     2   1265 use Time::Local ();
  2         3361  
  2         484  
16              
17             our @EXPORT = qw();
18             our @EXPORT_OK = qw(GuessCType);
19              
20             our $VERSION = '0.903'; # VERSION
21             $VERSION = eval $VERSION;
22              
23             warnings::warnif('deprecated', 'Mail::Sender is deprecated and you should look to Email::Sender instead');
24              
25             our $GMTdiff;
26             our $Error;
27             our %default; # loaded in from our config files
28             our $MD5_loaded = 0;
29             our $debug = 0;
30             our %CTypes = (
31             GIF => 'image/gif',
32             JPE => 'image/jpeg',
33             JPEG => 'image/jpeg',
34             SHTML => 'text/html',
35             SHTM => 'text/html',
36             HTML => 'text/html',
37             HTM => 'text/html',
38             TXT => 'text/plain',
39             INI => 'text/plain',
40             DOC => 'application/x-msword',
41             EML => 'message/rfc822',
42             );
43             our @Errors = (
44             'OK',
45             'Unknown encoding',
46             'TLS unsupported by server',
47             'TLS unsupported by script',
48             'IO::SOCKET::SSL failed',
49             'STARTTLS failed',
50             'debug file cannot be opened',
51             'file cannot be read',
52             'all recipients have been rejected',
53             'authentication protocol is not implemented',
54             'login not accepted',
55             'authentication protocol not accepted by the server',
56             'no From: address specified',
57             'no SMTP server specified',
58             'connection not established. Did you mean MailFile instead of SendFile?',
59             'site specific error',
60             'not available in singlepart mode',
61             'file not found',
62             'no file name specified in call to MailFile or SendFile',
63             'no message specified in call to MailMsg or MailFile',
64             'argument $to empty',
65             'transmission of message failed',
66             'local user $to unknown on host $smtp',
67             'unspecified communication error',
68             'service not available',
69             'connect() failed',
70             'socket() failed',
71             '$smtphost unknown'
72             );
73              
74             # if you do not use MailFile or SendFile and only send 7BIT or 8BIT "encoded"
75             # messages you may comment out these lines.
76             #MIME::Base64 and MIME::QuotedPrint may be found at CPAN.
77              
78             my $TLS_notsupported;
79              
80             BEGIN {
81             eval <<'END'
82             use IO::Socket::SSL;# qw(debug4);
83             use Net::SSLeay;
84             1;
85             END
86 2 50   2   170 or $TLS_notsupported = $@;
  2     2   2345  
  2     2   205830  
  2         57  
  2         822  
  2         8  
  2         120  
87             }
88              
89             # include config file and libraries when packaging the script
90             if (0) {
91             require 'Mail/Sender.config'; # local configuration
92             require 'Symbol.pm'; # for debuging and GetHandle() method
93             require 'Tie/Handle.pm'; # for debuging and GetHandle() method
94             require 'IO/Handle.pm'; # for debuging and GetHandle() method
95             require 'Digest/HMAC_MD5.pm'; # for CRAM-MD5 authentication only
96             require 'Authen/NTLM.pm'; # for NTLM authentication only
97             } # this block above is there to let PAR, PerlApp, PerlCtrl, PerlSvc and Perl2Exe know I may need those files.
98              
99             BEGIN {
100 2     2   12 my $config = $INC{'Mail/Sender.pm'};
101 2 50       17 die
102             "Wrong case in use statement or Mail::Sender module renamed. Perl is case sensitive!!!\n"
103             unless $config;
104 2         119 my $compiled = !(-e $config)
105             ; # if the module was not read from disk => the script has been "compiled"
106 2         24 $config =~ s/\.pm$/.config/;
107 2 50 33     7461 if ($compiled or -e $config) {
108              
109             # in a Perl2Exe or PerlApp created executable or PerlCtrl generated COM object
110             # or the config is known to exist
111 0         0 eval { require $config };
  0         0  
112 0 0 0     0 if ($@ and $@ !~ /Can't locate /) {
113 0         0 print STDERR "Error in Mail::Sender.config : $@";
114             }
115             }
116             }
117              
118             #local IP address and name
119             my $local_name
120             = $ENV{HOSTNAME} || $ENV{HTTP_HOST} || (gethostbyname 'localhost')[0];
121             $local_name
122             =~ s/:.*$//; # the HTTP_HOST may be set to something like "foo.bar.com:1000"
123             my $local_IP = join('.', unpack('CCCC', (gethostbyname $local_name)[4]));
124              
125             #time diference to GMT - Windows will not set $ENV{'TZ'}, if you know a better way ...
126              
127             sub ResetGMTdiff {
128 3     3 1 453 my $local = time;
129 3         41 my $gm = Time::Local::timelocal(gmtime $local);
130 3         293 my $sign = qw( + + - ) [$local <=> $gm];
131 3         28 $GMTdiff = sprintf "%s%02d%02d", $sign, (gmtime abs($local - $gm))[2, 1];
132 3         10 return $GMTdiff;
133             }
134             ResetGMTdiff();
135              
136             #
137             my @priority
138             = ('', '1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');
139              
140             #data encoding
141             my $chunksize = 1024 * 4;
142             my $chunksize64 = 71 * 57; # must be divisible by 57 !
143             my $enc_base64_chunk = 57;
144              
145             sub enc_base64 {
146 2 100   2 0 1226 if ($_[0]) {
147 1         3 my $charset = $_[0];
148             return sub {
149 0     0   0 my $s
150             = MIME::Base64::encode_base64(Encode::encode($charset, $_[0]));
151 0         0 $s =~ s/\x0A/\x0D\x0A/sg;
152 0         0 return $s;
153             }
154 1         6 }
155             else {
156             return sub {
157 0     0   0 my $s = MIME::Base64::encode_base64($_[0]);
158 0         0 $s =~ s/\x0A/\x0D\x0A/sg;
159 0         0 return $s;
160             }
161 1         9 }
162             }
163              
164             sub enc_qp {
165 2 100   2 0 8 if ($_[0]) {
166 1         2 my $charset = $_[0];
167             return sub {
168 0     0   0 my $s = Encode::encode($charset, $_[0]);
169 0         0 $s =~ s/\x0D\x0A/\n/g;
170 0         0 $s = MIME::QuotedPrint::encode_qp($s);
171 0         0 $s =~ s/^\./../gm;
172 0         0 $s =~ s/\x0A/\x0D\x0A/sg;
173 0         0 return $s;
174             }
175 1         6 }
176             else {
177             return sub {
178 0     0   0 my $s = $_[0];
179 0         0 $s =~ s/\x0D\x0A/\n/g;
180 0         0 $s = MIME::QuotedPrint::encode_qp($s);
181 0         0 $s =~ s/^\./../gm;
182 0         0 $s =~ s/\x0A/\x0D\x0A/sg;
183 0         0 return $s;
184             }
185 1         6 }
186             }
187              
188             sub enc_plain {
189 2 100   2 0 8 if ($_[0]) {
190 1         2 my $charset = $_[0];
191             return sub {
192 0     0   0 my $s = Encode::encode($charset, $_[0]);
193 0         0 $s =~ s/^\./../gm;
194 0         0 $s =~ s/(?:\x0D\x0A?|\x0A)/\x0D\x0A/sg;
195 0         0 return $s;
196             }
197 1         9 }
198             else {
199             return sub {
200 0     0   0 my $s = $_[0];
201 0         0 $s =~ s/^\./../gm;
202 0         0 $s =~ s/(?:\x0D\x0A?|\x0A)/\x0D\x0A/sg;
203 0         0 return $s;
204             }
205 1         7 }
206             }
207              
208             sub enc_xtext {
209 9     9 0 13 my $input = shift;
210 9         33 $input =~ s/([^!-*,-<>-~])/'+'.uc(unpack('H*', $1))/eg;
  0         0  
211 9         25 return $input;
212             }
213              
214             {
215             my $username;
216              
217             sub getusername () {
218 2 100   2 0 800 return $username if defined($username);
219 1   33     2 return $username = eval { getlogin || getpwuid($<) } || $ENV{USERNAME};
220             }
221             }
222              
223             #IO
224              
225             #reads the whole SMTP response
226             # converts
227             # nnn-very
228             # nnn-long
229             # nnn message
230             # to
231             # nnn very
232             # long
233             # message
234             sub get_response ($) {
235 0     0 0 0 my $s = shift;
236 0         0 my $res = <$s>;
237 0 0       0 if ($res =~ s/^(\d\d\d)-/$1 /) {
238 0         0 my $nextline = <$s>;
239 0         0 while ($nextline =~ s/^\d\d\d-//) {
240 0         0 $res .= $nextline;
241 0         0 $nextline = <$s>;
242             }
243 0         0 $nextline =~ s/^\d\d\d //;
244 0         0 $res .= $nextline;
245             }
246 0         0 $Mail::Sender::LastResponse = $res;
247 0         0 return $res;
248             }
249              
250             sub send_cmd ($$) {
251 0     0 0 0 my ($s, $cmd) = @_;
252 0         0 chomp $cmd;
253 0 0       0 if ($s->opened()) {
254 0         0 print $s "$cmd\x0D\x0A";
255 0         0 get_response($s);
256             }
257             else {
258 0         0 return '400 connection lost';
259             }
260             }
261              
262             sub _print_hdr {
263 0     0   0 my ($s, $hdr, $str, $charset) = @_;
264 0 0 0     0 return if !defined $str or $str eq '';
265 0         0 $str =~ s/[\x0D\x0A\s]+$//;
266              
267 0 0 0     0 if ($charset && $str =~ /[^[:ascii:]]/) {
268 0         0 $str = Encode::encode($charset, $str);
269 0         0 my @parts = split /(\s*[,;<> ]\s*)/, $str;
270 0         0 $str = '';
271 0         0 for (my $i = 0; $i < @parts; $i++) {
272 0         0 my $part = $parts[$i];
273 0 0 0     0 $part .= $parts[++$i]
274             if ($i < $#parts && $parts[$i + 1] =~ /^\s+$/);
275 0 0 0     0 if ($part =~ /[^[:ascii:]]/ || $part =~ /[\r\n\t]/) {
276 0         0 $part = MIME::QuotedPrint::encode_qp($part, '');
277 0         0 $part =~ s/([\s\?])/'=' . sprintf '%02x',ord($1)/ge;
  0         0  
278 0         0 $str .= "=?$charset?Q?$part?=";
279             }
280             else {
281 0         0 $str .= $part;
282             }
283             }
284             }
285              
286 0         0 $str =~ s/(?:\x0D\x0A?|\x0A)/\x0D\x0A/sg; # \n or \r => \r\n
287 0         0 $str =~ s/\x0D\x0A([^\t])/\x0D\x0A\t$1/sg;
288 0 0       0 if (length($str) + length($hdr) > 997) { # header too long, max 1000 chars
289 0         0 $str =~ s/(.{1,980}[;,])\s+(\S)/$1\x0D\x0A\t$2/g;
290             }
291 0         0 print $s "$hdr: $str\x0D\x0A";
292             }
293              
294              
295             sub _say_helo {
296 0     0   0 my ($self, $s) = @_;
297 0         0 my $res = send_cmd $s, "EHLO $self->{'client'}";
298 0 0       0 if ($res !~ /^[123]/) {
299 0         0 $res = send_cmd $s, "HELO $self->{'client'}";
300 0 0       0 if ($res !~ /^[123]/) { return $self->Error(_COMMERROR($_)); }
  0         0  
301 0         0 return;
302             }
303              
304 0         0 $res =~ s/^.*\n//;
305 0         0 $self->{'supports'} = {map { split /(?:\s+|=)/, $_, 2 } split /\n/, $res};
  0         0  
306              
307 0 0       0 if (exists $self->{'supports'}{AUTH}) {
308 0         0 my @auth = split /\s+/, uc($self->{'supports'}{AUTH});
309 0         0 $self->{'auth_protocols'} = {map { $_, 1 } @auth};
  0         0  
310              
311             # create a hash with accepted authentication protocols
312             }
313              
314 0         0 $self->{esmtp}{_MAIL_FROM} = '';
315 0         0 $self->{esmtp}{_RCPT_TO} = '';
316 0 0 0     0 if (exists $self->{'supports'}{DSN} and exists $self->{esmtp}) {
317 0         0 for (qw(RET ENVID)) {
318             $self->{esmtp}{_MAIL_FROM} .= " $_=$self->{esmtp}{$_}"
319 0 0       0 if $self->{esmtp}{$_} ne '';
320             }
321 0         0 for (qw(NOTIFY ORCPT)) {
322             $self->{esmtp}{_RCPT_TO} .= " $_=$self->{esmtp}{$_}"
323 0 0       0 if $self->{esmtp}{$_} ne '';
324             }
325             }
326 0         0 return;
327             }
328              
329             sub login {
330 0     0 0 0 my $self = shift();
331 0   0     0 my $auth = uc($self->{'auth'}) || 'LOGIN';
332 0 0       0 if (!$self->{'auth_protocols'}->{$auth}) {
333 0         0 return $self->Error(_INVALIDAUTH($auth));
334             }
335              
336             $self->{'authid'} = $self->{'username'}
337 0 0 0     0 if (exists $self->{'username'} and !exists $self->{'authid'});
338              
339             $self->{'authpwd'} = $self->{'password'}
340 0 0 0     0 if (exists $self->{'password'} and !exists $self->{'authpwd'});
341              
342             # change all characters except letters, numbers and underscores to underscores
343 0         0 $auth =~ tr/a-zA-Z0-9_/_/c;
344 2     2   36 no strict qw'subs refs';
  2         4  
  2         37759  
345 0         0 my $method = "Mail::Sender::Auth::$auth";
346 0         0 $method->($self);
347             }
348              
349             # authentication code stolen from http://support.zeitform.de/techinfo/e-mail_prot.html
350             sub Mail::Sender::Auth::LOGIN {
351 0     0   0 my $self = shift();
352 0         0 my $s = $self->{'socket'};
353              
354 0         0 $_ = send_cmd $s, 'AUTH LOGIN';
355 0 0       0 if (!/^[123]/) { return $self->Error(_INVALIDAUTH('LOGIN', $_)); }
  0         0  
356              
357 0 0       0 if ($self->{auth_encoded}) {
358              
359             # I assume the username and password had been base64 encoded already!
360 0         0 $_ = send_cmd $s, $self->{'authid'};
361 0 0       0 if (!/^[123]/) { return $self->Error(_LOGINERROR($_)); }
  0         0  
362              
363 0         0 $_ = send_cmd $s, $self->{'authpwd'};
364 0 0       0 if (!/^[123]/) { return $self->Error(_LOGINERROR($_)); }
  0         0  
365             }
366             else {
367 0         0 $_ = send_cmd $s, MIME::Base64::encode_base64($self->{'authid'}, '');
368 0 0       0 if (!/^[123]/) { return $self->Error(_LOGINERROR($_)); }
  0         0  
369              
370 0         0 $_ = send_cmd $s, MIME::Base64::encode_base64($self->{'authpwd'}, '');
371 0 0       0 if (!/^[123]/) { return $self->Error(_LOGINERROR($_)); }
  0         0  
372             }
373 0         0 return;
374             }
375              
376             sub Mail::Sender::Auth::CRAM_MD5 {
377 0     0   0 my $self = shift();
378 0         0 my $s = $self->{'socket'};
379              
380 0         0 $_ = send_cmd $s, "AUTH CRAM-MD5";
381 0 0       0 if (!/^[123]/) { return $self->Error(_INVALIDAUTH('CRAM-MD5', $_)); }
  0         0  
382 0 0       0 my $stamp = $1 if /^\d{3}\s+(.*)$/;
383              
384 0 0       0 unless ($MD5_loaded) {
385 0         0 eval 'use Digest::HMAC_MD5 qw(hmac_md5_hex)';
386 0 0       0 die "$@\n" if $@;
387 0         0 $MD5_loaded = 1;
388             }
389              
390 0         0 my $user = $self->{'authid'};
391 0         0 my $secret = $self->{'authpwd'};
392              
393 0         0 my $decoded_stamp = MIME::Base64::decode_base64($stamp);
394 0         0 my $hmac = hmac_md5_hex($decoded_stamp, $secret);
395 0         0 my $answer = MIME::Base64::encode_base64($user . ' ' . $hmac, '');
396 0         0 $_ = send_cmd $s, $answer;
397 0 0       0 if (!/^[123]/) { return $self->Error(_LOGINERROR($_)); }
  0         0  
398 0         0 return;
399             }
400              
401             sub Mail::Sender::Auth::PLAIN {
402 0     0   0 my $self = shift();
403 0         0 my $s = $self->{'socket'};
404              
405 0         0 $_ = send_cmd $s, "AUTH PLAIN";
406 0 0       0 if (!/^[123]/) { return $self->Error(_INVALIDAUTH('PLAIN', $_)); }
  0         0  
407              
408             $_ = send_cmd $s,
409             MIME::Base64::encode_base64(
410 0         0 "\000" . $self->{'authid'} . "\000" . $self->{'authpwd'}, '');
411 0 0       0 if (!/^[123]/) { return $self->Error(_LOGINERROR($_)); }
  0         0  
412 0         0 return;
413             }
414              
415             {
416             my $NTLM_loaded = 0;
417              
418             sub Mail::Sender::Auth::NTLM {
419 0 0   0   0 unless ($NTLM_loaded) {
420 0         0 eval "use Authen::NTLM qw();";
421 0 0       0 die "$@\n" if $@;
422 0         0 $NTLM_loaded = 1;
423             }
424 0         0 my $self = shift();
425 0         0 my $s = $self->{'socket'};
426              
427 0         0 $_ = send_cmd $s, "AUTH NTLM";
428 0 0       0 if (!/^[123]/) { return $self->Error(_INVALIDAUTH('NTLM', $_)); }
  0         0  
429              
430 0         0 Authen::NTLM::ntlm_reset();
431 0         0 Authen::NTLM::ntlm_user($self->{'authid'});
432 0         0 Authen::NTLM::ntlm_password($self->{'authpwd'});
433             Authen::NTLM::ntlm_domain($self->{'authdomain'})
434 0 0       0 if defined $self->{'authdomain'};
435              
436 0         0 $_ = send_cmd $s, Authen::NTLM::ntlm();
437 0 0       0 if (!/^3\d\d (.*)$/s) { return $self->Error(_LOGINERROR($_)); }
  0         0  
438 0         0 my $response = $1;
439 0         0 $_ = send_cmd $s, Authen::NTLM::ntlm($response);
440 0 0       0 if (!/^[123]/) { return $self->Error(_LOGINERROR($_)); }
  0         0  
441 0         0 return;
442             }
443             }
444              
445             sub Mail::Sender::Auth::AUTOLOAD {
446 0     0   0 (my $auth = $Mail::Sender::Auth::AUTOLOAD) =~ s/.*:://;
447 0         0 my $self = shift();
448 0         0 my $s = $self->{'socket'};
449 0         0 send_cmd $s, "QUIT";
450 0         0 close $s;
451 0         0 delete $self->{'socket'};
452 0         0 return $self->Error(_UNKNOWNAUTH($auth));
453             }
454              
455             my $debug_code;
456              
457             sub __Debug {
458 0     0   0 my ($socket, $file) = @_;
459 0 0       0 if (defined $file) {
460 0 0       0 unless (@Mail::Sender::DBIO::ISA) {
461 0         0 eval "use Symbol;";
462 0         0 eval $debug_code;
463 0 0       0 die $@ if $@;
464             }
465 0         0 my $handle = gensym();
466 0         0 *$handle = \$socket;
467 0 0       0 if (!ref $file) {
468 0 0       0 open my $DEBUG, '>', $file
469             or die "Cannot open the debug file '$file': $^E\n";
470 0         0 binmode $DEBUG;
471 0         0 $DEBUG->autoflush();
472 0         0 tie *$handle, 'Mail::Sender::DBIO', $socket, $DEBUG, 1;
473             }
474             else {
475 0         0 my $DEBUG = $file;
476 0         0 tie *$handle, 'Mail::Sender::DBIO', $socket, $DEBUG, 0;
477             }
478 0         0 bless $handle, 'Mail::Sender::DBIO';
479 0         0 return $handle;
480             }
481             else {
482 0         0 return $socket;
483             }
484             }
485              
486             #internale
487              
488             sub _HOSTNOTFOUND {
489 3   100 3   1259 my $msg = shift || '';
490 3         10 $! = 2;
491 3         15 $Error = "The SMTP server $msg was not found";
492 3         19 return -1, $Error;
493             }
494              
495             sub _CONNFAILED {
496 1     1   801 $! = 5;
497 1         9 $Error = "connect() failed: $^E";
498 1         3 return -3, $Error;
499             }
500              
501             sub _SERVNOTAVAIL {
502 2   100 2   1800 my $msg = shift || '';
503 2         6 $! = 40;
504 2 100       9 $Error = "Service not available. "
505             . ($msg ? "Reply: $msg" : "Server closed the connection unexpectedly");
506 2         7 return -4, $Error;
507             }
508              
509             sub _COMMERROR {
510 2   100 2   2407 my $msg = shift || '';
511 2         6 $! = 5;
512 2 100       7 if ($msg eq '') {
513 1         3 $Error = "No response from server";
514             }
515             else {
516 1         6 $Error = "Server error: $msg";
517             }
518 2         8 return -5, $Error;
519             }
520              
521             sub _USERUNKNOWN {
522 5   100 5   5448 my $user = shift || '';
523 5   100     14 my $host = shift || '';
524 5   100     16 my $err = shift || '';
525 5         12 $! = 2;
526 5 100 100     31 if ($err and $err !~ /Local user/i) {
527 2         9 $err =~ s/^\d+\s*//;
528 2         10 $err =~ s/\s*$//s;
529 2   100     10 $err ||= "Error";
530 2         8 $Error = "$err for \"$user\" on host \"$host\"";
531             }
532             else {
533 3         12 $Error = "Local user \"$user\" unknown on host \"$host\"";
534             }
535 5         15 return -6, $Error;
536             }
537              
538             sub _TRANSFAILED {
539 2   100 2   1768 my $msg = shift || '';
540 2         5 $! = 5;
541 2         7 $Error = "Transmission of message failed ($msg)";
542 2         6 return -7, $Error;
543             }
544              
545             sub _TOEMPTY {
546 1     1   817 $! = 14;
547 1         3 $Error = "Argument \$to empty";
548 1         4 return -8, $Error;
549             }
550              
551             sub _NOMSG {
552 1     1   801 $! = 22;
553 1         3 $Error = "No message specified";
554 1         4 return -9, $Error;
555             }
556              
557             sub _NOFILE {
558 1     1   862 $! = 22;
559 1         2 $Error = "No file name specified";
560 1         3 return -10, $Error;
561             }
562              
563             sub _FILENOTFOUND {
564 2   100 2   1836 my $msg = shift || '';
565 2         4 $! = 2;
566 2         6 $Error = "File \"$msg\" not found";
567 2         7 return -11, $Error;
568             }
569              
570             sub _NOTMULTIPART {
571 2   100 2   2067 my $msg = shift || '';
572 2         6 $! = 40;
573 2         7 $Error = "$msg not available in singlepart mode";
574 2         8 return -12, $Error;
575             }
576              
577             sub _SITEERROR {
578 1     1   819 $! = 15;
579 1         3 $Error = "Site specific error";
580 1         3 return -13, $Error;
581             }
582              
583             sub _NOTCONNECTED {
584 1     1   808 $! = 1;
585 1         2 $Error = "Connection not established";
586 1         4 return -14, $Error;
587             }
588              
589             sub _NOSERVER {
590 1     1   809 $! = 22;
591 1         2 $Error = "No SMTP server specified";
592 1         3 return -15, $Error;
593             }
594              
595             sub _NOFROMSPECIFIED {
596 1     1   798 $! = 22;
597 1         3 $Error = "No From: address specified";
598 1         3 return -16, $Error;
599             }
600              
601             sub _INVALIDAUTH {
602 3   100 3   2488 my $proto = shift || '';
603 3   100     15 my $res = shift || '';
604 3         5 $! = 22;
605 3         9 $Error = "Authentication protocol $proto is not accepted by the server";
606 3 100       8 $Error .= ",\nresponse: $res" if $res;
607 3         8 return -17, $Error;
608             }
609              
610             sub _LOGINERROR {
611 1     1   799 $! = 22;
612 1         3 $Error = "Login not accepted";
613 1         3 return -18, $Error;
614             }
615              
616             sub _UNKNOWNAUTH {
617 2   100 2   1668 my $msg = shift || '';
618 2         5 $! = 22;
619 2         6 $Error = "Authentication protocol $msg is not implemented by Mail::Sender";
620 2         6 return -19, $Error;
621             }
622              
623             sub _ALLRECIPIENTSBAD {
624 1     1   804 $! = 2;
625 1         3 $Error = "All recipients are bad";
626 1         3 return -20, $Error;
627             }
628              
629             sub _FILECANTREAD {
630 2   100 2   1656 my $msg = shift || '';
631 2         17 $Error = "File \"$msg\" cannot be read: $^E";
632 2         5 return -21, $Error;
633             }
634              
635             sub _DEBUGFILE {
636 2     2   1605 $Error = shift;
637 2         6 return -22, $Error;
638             }
639              
640             sub _STARTTLS {
641 3   100 3   2461 my $msg = shift || '';
642 3   100     13 my $two = shift || '';
643 3         7 $! = 5;
644 3         7 $Error = "STARTTLS failed: $msg $two";
645 3         9 return -23, $Error;
646             }
647              
648             sub _IO_SOCKET_SSL {
649 2   100 2   1670 my $msg = shift || '';
650 2         4 $! = 5;
651 2         5 $Error = "IO::Socket::SSL->start_SSL failed: $msg";
652 2         6 return -24, $Error;
653             }
654              
655             sub _TLS_UNSUPPORTED_BY_ME {
656 2   100 2   1596 my $msg = shift || '';
657 2         5 $! = 5;
658 2         6 $Error = "TLS unsupported by the script: $msg";
659 2         5 return -25, $Error;
660             }
661              
662             sub _TLS_UNSUPPORTED_BY_SERVER {
663 1     1   810 $! = 5;
664 1         4 $Error = "TLS unsupported by server";
665 1         3 return -26, $Error;
666             }
667              
668             sub _UNKNOWNENCODING {
669 2   100 2   1675 my $msg = shift || '';
670 2         4 $! = 5;
671 2         5 $Error = "Unknown encoding '$msg'";
672 2         7 return -27, $Error;
673             }
674              
675             sub new {
676 19     19 1 9449 my $this = shift;
677 19         32 my $self = {};
678 19         25 my $class;
679 19 100       42 if (ref($this)) {
680 2         3 $class = ref($this);
681 2         33 %$self = %$this;
682             }
683             else {
684 17         58 $class = $this;
685             }
686 19         31 bless $self, $class;
687 19         82 return $self->_initialize(@_);
688             }
689              
690             sub _initialize {
691 19     19   40 undef $Error;
692 19         41 my $self = shift;
693              
694 19         36 delete $self->{'_buffer'};
695 19         56 $self->{'debug'} = 0;
696 19         1706 $self->{'proto'} = (getprotobyname('tcp'))[2];
697              
698             $self->{'port'} = getservbyname('smtp', 'tcp') || 25
699 19 100 50     1401 unless $self->{'port'};
700              
701 19         95 $self->{'boundary'} = 'Message-Boundary-by-Mail-Sender-' . time();
702 19         48 $self->{'multipart'} = 'mixed'; # default is multipart/mixed
703 19         41 $self->{'tls_allowed'} = 1;
704              
705 19         40 $self->{'client'} = $local_name;
706              
707             # Copy defaults from %default
708 19         83 foreach my $key (keys %default) {
709 36         98 $self->{lc $key} = $default{$key};
710             }
711              
712 19 100       80 if (@_ != 0) {
713 18 100       71 if (ref $_[0] eq 'HASH') {
714 17         23 my $hash = $_[0];
715 17         48 foreach my $key (keys %$hash) {
716 5         27 $self->{lc $key} = $hash->{$key};
717             }
718             $self->{'reply'} = $self->{'replyto'}
719 17 100 100     81 if ($self->{'replyto'} and !$self->{'reply'});
720             }
721             else {
722             (
723             $self->{'from'}, $self->{'reply'}, $self->{'to'},
724             $self->{'smtp'}, $self->{'subject'}, $self->{'headers'},
725 1         11 $self->{'boundary'}
726             ) = @_;
727             }
728             }
729              
730 19         49 $self->{'fromaddr'} = $self->{'from'};
731 19         32 $self->{'replyaddr'} = $self->{'reply'};
732              
733 19 100       55 $self->_prepare_addresses('to') if $self->{'to'};
734 19 100       58 $self->_prepare_addresses('cc') if $self->{'cc'};
735 19 100       88 $self->_prepare_addresses('bcc') if $self->{'bcc'};
736              
737 19 100       45 $self->_prepare_ESMTP() if defined $self->{'esmtp'};
738              
739             # get from email address
740 19 100       44 $self->{'fromaddr'} =~ s/.*<([^\s]*?)>/$1/ if ($self->{'fromaddr'});
741              
742 19 100       37 if ($self->{'replyaddr'}) {
743 4         60 $self->{'replyaddr'} =~ s/.*<([^\s]*?)>/$1/; # get reply email address
744 4         29 $self->{'replyaddr'} =~ s/^([^\s]+).*/$1/; # use first address
745             }
746              
747 19 100       74 if ($self->{'smtp'}) {
748 3         15 $self->{'smtp'} =~ s/^\s+//g; # remove spaces around $smtp
749 3         13 $self->{'smtp'} =~ s/\s+$//g;
750              
751 3 100       12671 unless ($self->{'smtpaddr'} = Socket::inet_aton($self->{'smtp'})) {
752 1         24 return $self->Error(_HOSTNOTFOUND($self->{'smtp'}));
753             }
754 2 50       25 $self->{'smtpaddr'} = $1 if ($self->{'smtpaddr'} =~ /(.*)/s); # Untaint
755             }
756              
757 18 100       65 $self->{'boundary'} =~ tr/=/-/ if defined $self->{'boundary'};
758              
759 18 100       72 $self->_prepare_headers() if defined $self->{'headers'};
760              
761 18         68 return $self;
762             }
763              
764             sub GuessCType {
765 7     7 1 3569 my $file = shift;
766 7 100 100     55 if (defined $file && $file =~ /\.(.*)$/) {
767 5   100     36 return $CTypes{uc($1)} || 'application/octet-stream';
768             }
769 2         4 return 'application/octet-stream';
770             }
771              
772             sub Connect {
773 0     0 1 0 my $self = shift();
774              
775             my $s = IO::Socket::INET->new(
776             PeerHost => $self->{'smtp'},
777             PeerPort => $self->{'port'},
778             Proto => "tcp",
779 0 0 0     0 Timeout => ($self->{'timeout'} || 120),
780             ) or return $self->Error(_CONNFAILED);
781              
782 0         0 $s->autoflush(1);
783 0         0 binmode($s);
784              
785 0 0       0 if ($self->{'debug'}) {
786 0 0       0 eval { $s = __Debug($s, $self->{'debug'}); }
  0         0  
787             or return $self->Error(_DEBUGFILE($@));
788 0 0       0 $self->{'debug_level'} = 4 unless defined $self->{'debug_level'};
789             }
790              
791 0         0 $_ = get_response($s);
792 0 0 0     0 if (not $_ or !/^[123]/) { return $self->Error(_SERVNOTAVAIL($_)); }
  0         0  
793 0         0 $self->{'server'} = substr $_, 4;
794 0         0 $self->{'!greeting'} = $_;
795              
796             {
797 0         0 my $res = $self->_say_helo($s);
  0         0  
798 0 0       0 return $res if $res;
799             }
800              
801 0 0 0     0 if (
    0 0        
      0        
      0        
802             ($self->{tls_required} or $self->{tls_allowed})
803             and !$TLS_notsupported
804             and ( defined($self->{'supports'}{STARTTLS})
805             or defined($self->{'supports'}{TLS}))
806             )
807             {
808 0         0 Net::SSLeay::load_error_strings();
809 0         0 Net::SSLeay::SSLeay_add_ssl_algorithms();
810 0 0       0 $Net::SSLeay::random_device = $0 if (!-s $Net::SSLeay::random_device);
811 0         0 Net::SSLeay::randomize();
812              
813 0         0 my $res = send_cmd $s, "STARTTLS";
814 0         0 my ($code, $text) = split(/\s/, $res, 2);
815              
816 0 0       0 return $self->Error(_STARTTLS($code, $text)) if ($code != 220);
817              
818 0         0 my %ssl_options = (
819             SSL_version => 'TLSv1',
820             SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE(),
821             );
822 0 0       0 if (exists $self->{ssl_version}) {
823 0         0 $ssl_options{SSL_version} = $self->{ssl_version};
824             }
825 0 0       0 if (exists $self->{ssl_verify_mode}) {
826 0         0 $ssl_options{SSL_verify_mode} = $self->{ssl_verify_mode};
827             }
828 0 0       0 if (exists $self->{ssl_ca_path}) {
829 0         0 $ssl_options{SSL_ca_path} = $self->{ssl_ca_path};
830             }
831 0 0       0 if (exists $self->{ssl_ca_file}) {
832 0         0 $ssl_options{SSL_ca_file} = $self->{ssl_ca_file};
833             }
834 0 0       0 if (exists $self->{ssl_verifycb_name}) {
835 0         0 $ssl_options{SSL_verifycb_name} = $self->{ssl_verifycb_name};
836             }
837 0 0       0 if (exists $self->{ssl_verifycn_schema}) {
838 0         0 $ssl_options{ssl_verifycn_schema} = $self->{ssl_verifycn_schema};
839             }
840 0 0       0 if (exists $self->{ssl_hostname}) {
841 0         0 $ssl_options{SSL_hostname} = $self->{ssl_hostname};
842             }
843              
844 0 0       0 if ($self->{'debug'}) {
845 0         0 $res = IO::Socket::SSL->start_SSL(tied(*$s)->[0], %ssl_options);
846             }
847             else {
848 0         0 $res = IO::Socket::SSL->start_SSL($s, %ssl_options);
849             }
850 0 0       0 if (!$res) {
851 0         0 return $self->Error(_IO_SOCKET_SSL(IO::Socket::SSL::errstr()));
852             }
853              
854             {
855 0         0 my $res = $self->_say_helo($s);
  0         0  
856 0 0       0 return $res if $res;
857             }
858             }
859             elsif ($self->{tls_required}) {
860 0 0       0 if ($TLS_notsupported) {
861 0         0 return $self->Error(_TLS_UNSUPPORTED_BY_ME($TLS_notsupported));
862             }
863             else {
864 0         0 return $self->Error(_TLS_UNSUPPORTED_BY_SERVER());
865             }
866             }
867              
868 0 0 0     0 if ($self->{'auth'} or $self->{'username'}) {
869 0         0 $self->{'socket'} = $s;
870 0         0 my $res = $self->login();
871 0 0       0 return $res if $res;
872 0         0 delete $self->{'socket'}; # it's supposed to be added later
873             }
874              
875 0         0 return $s;
876             }
877              
878             sub Error {
879 1     1 0 15 my $self = shift();
880 1 50       8 if (@_) {
881 1 50       37 if (defined $self->{'socket'}) {
882 0         0 my $s = $self->{'socket'};
883 0         0 print $s "quit\x0D\x0A";
884 0         0 close $s;
885 0         0 delete $self->{'socket'};
886             }
887 1         2 delete $self->{'_data'};
888 1         6 ($self->{'error'}, $self->{'error_msg'}) = @_;
889             }
890 1 50 33     18 if ($self->{'die_on_errors'} or ($self->{on_errors} && $self->{'on_errors'} eq 'die')) {
    50 33        
      0        
      33        
891 0         0 die $self->{'error_msg'} . "\n";
892             }
893             elsif (exists $self->{'on_errors'}
894             and (!defined($self->{'on_errors'}) or $self->{'on_errors'} eq 'undef'))
895             {
896 0         0 return;
897             }
898 1         9 return $self->{'error'};
899             }
900              
901             sub ClearErrors {
902 1     1 1 666 my $self = shift();
903 1         4 delete $self->{'error'};
904 1         3 delete $self->{'error_msg'};
905 1         4 undef $Error;
906             }
907              
908             sub _prepare_addresses {
909 17     17   2168 my ($self, $type) = @_;
910 17 100       39 if (ref $self->{$type}) {
911             $self->{$type . '_list'}
912 1         3 = [map { s/\s+$//; s/^\s+//; $_ } @{$self->{$type}}];
  2         4  
  2         4  
  2         8  
  1         4  
913 1         2 $self->{$type} = join ', ', @{$self->{$type . '_list'}};
  1         7  
914             }
915             else {
916 16         50 $self->{$type} =~ s/\s+/ /g;
917 16         27 $self->{$type} =~ s/, ?,/,/g;
918 16         26 $self->{$type . '_list'} = [map { s/\s+$//; $_ }
  16         83  
919 16         94 $self->{$type} =~ /((?:[^",]+|"[^"]*")+)(?:,\s*|\s*$)/g ];
920             }
921             }
922              
923             sub _prepare_ESMTP {
924 4     4   2133 my $self = shift;
925             $self->{esmtp}
926 4         8 = {%{$self->{esmtp}}}; # make a copy of the hash. Just in case
  4         28  
927              
928             $self->{esmtp}{ORCPT} = 'rfc822;' . $self->{esmtp}{ORCPT}
929 4 100 100     67 if $self->{esmtp}{ORCPT} ne '' and $self->{esmtp}{ORCPT} !~ /;/;
930 4         13 for (qw(ENVID ORCPT)) {
931 8         19 $self->{esmtp}{$_} = enc_xtext($self->{esmtp}{$_});
932             }
933             }
934              
935             sub _prepare_headers {
936 10     10   7310 my $self = shift;
937 10 100       42 return unless exists $self->{'headers'};
938 9 100       41 if ($self->{'headers'} eq '') {
939 5         11 delete $self->{'headers'};
940 5         11 delete $self->{'_headers'};
941 5         15 return;
942             }
943 4 100       29 if (ref($self->{'headers'}) eq 'HASH') {
    100          
944 2         5 my $headers = '';
945 2         4 while (my ($hdr, $value) = each %{$self->{'headers'}}) {
  4         29  
946 2         9 for ($hdr, $value) {
947 4         22 s/(?:\x0D\x0A?|\x0A)/\x0D\x0A/sg
948             ; # convert all end-of-lines to CRLF
949 4         7 s/^(?:\x0D\x0A)+//; # strip leading
950 4         10 s/(?:\x0D\x0A)+$//; # and trailing end-of-lines
951 4         8 s/\x0D\x0A(\S)/\x0D\x0A\t$1/sg;
952 4 100       19 if (length($_) > 997) { # header too long, max 1000 chars
953 1         647 s/(.{1,980}[;,])\s+(\S)/$1\x0D\x0A\t$2/g;
954             }
955             }
956 2         26 $headers .= "$hdr: $value\x0D\x0A";
957             }
958 2         20 $headers =~ s/(?:\x0D\x0A)+$//; # and trailing end-of-lines
959 2         13 $self->{'_headers'} = $headers;
960             }
961             elsif (ref($self->{'headers'})) {
962             }
963             else {
964 1         5 $self->{'_headers'} = $self->{'headers'};
965 1         18 for ($self->{'_headers'}) {
966 1         6 s/(?:\x0D\x0A?|\x0A)/\x0D\x0A/sg; # convert all end-of-lines to CRLF
967 1         2 s/^(?:\x0D\x0A)+//; # strip leading
968 1         4 s/(?:\x0D\x0A)+$//; # and trailing end-of-lines
969             }
970             }
971             }
972              
973             sub Open {
974 0     0 1 0 undef $Error;
975 0         0 my $self = shift;
976 0         0 local $_;
977 0 0 0     0 if (!$self->{'keepconnection'} and $self->{'_data'})
978             { # the user did not Close() or Cancel() the previous mail
979 0 0       0 if ($self->{'error'}) {
980 0         0 $self->Cancel;
981             }
982             else {
983 0         0 $self->Close;
984             }
985             }
986              
987 0         0 delete $self->{'error'};
988 0         0 delete $self->{'encoding'};
989 0         0 delete $self->{'messageid'};
990 0         0 my %changed;
991 0         0 $self->{'multipart'} = 0;
992 0         0 $self->{'_had_newline'} = 1;
993              
994 0 0       0 if (ref $_[0] eq 'HASH') {
995 0         0 my $key;
996 0         0 my $hash = $_[0];
997             $hash->{'reply'} = $hash->{'replyto'}
998 0 0 0     0 if (defined $hash->{'replyto'} and !defined $hash->{'reply'});
999 0         0 foreach $key (keys %$hash) {
1000 0 0 0     0 if (ref($hash->{$key}) eq 'HASH' and exists $self->{lc $key}) {
1001 0 0       0 if (ref($self->{lc $key}) eq 'HASH') {
1002 0         0 $self->{lc $key} = {%{$self->{lc $key}}, %{$hash->{$key}}};
  0         0  
  0         0  
1003             }
1004             else {
1005 0         0 $self->{lc $key} = {%{$hash->{$key}}}; # make a shallow copy
  0         0  
1006             }
1007             }
1008             else {
1009 0         0 $self->{lc $key} = $hash->{$key};
1010             }
1011 0         0 $changed{lc $key} = 1;
1012             }
1013             }
1014             else {
1015 0         0 my ($from, $reply, $to, $smtp, $subject, $headers) = @_;
1016              
1017 0 0       0 if ($from) { $self->{'from'} = $from; $changed{'from'} = 1; }
  0         0  
  0         0  
1018 0 0       0 if ($reply) { $self->{'reply'} = $reply; $changed{'reply'} = 1; }
  0         0  
  0         0  
1019 0 0       0 if ($to) { $self->{'to'} = $to; $changed{'to'} = 1; }
  0         0  
  0         0  
1020 0 0       0 if ($smtp) { $self->{'smtp'} = $smtp; $changed{'smtp'} = 1; }
  0         0  
  0         0  
1021 0 0       0 if ($subject) {
1022 0         0 $self->{'subject'} = $subject;
1023 0         0 $changed{'subject'} = 1;
1024             }
1025 0 0       0 if ($headers) {
1026 0         0 $self->{'headers'} = $headers;
1027 0         0 $changed{'headers'} = 1;
1028             }
1029             }
1030              
1031 0 0       0 $self->_prepare_addresses('to') if $changed{'to'};
1032 0 0       0 $self->_prepare_addresses('cc') if $changed{'cc'};
1033 0 0       0 $self->_prepare_addresses('bcc') if $changed{'bcc'};
1034              
1035 0 0       0 $self->_prepare_ESMTP() if defined $changed{'esmtp'};
1036              
1037 0 0       0 $self->{'boundary'} =~ tr/=/-/ if defined $changed{'boundary'};
1038              
1039 0 0       0 return $self->Error(_NOFROMSPECIFIED) unless defined $self->{'from'};
1040              
1041 0 0       0 if ($changed{'from'}) {
1042 0         0 $self->{'fromaddr'} = $self->{'from'};
1043 0         0 $self->{'fromaddr'} =~ s/.*<([^\s]*?)>/$1/; # get from email address
1044             }
1045              
1046 0 0       0 if ($changed{'reply'}) {
1047 0         0 $self->{'replyaddr'} = $self->{'reply'};
1048 0         0 $self->{'replyaddr'} =~ s/.*<([^\s]*?)>/$1/; # get reply email address
1049 0         0 $self->{'replyaddr'} =~ s/^([^\s]+).*/$1/; # use first address
1050             }
1051              
1052 0 0       0 if ($changed{'smtp'}) {
1053 0         0 $self->{'smtp'} =~ s/^\s+//g; # remove spaces around $smtp
1054 0         0 $self->{'smtp'} =~ s/\s+$//g;
1055 0         0 $self->{'smtpaddr'} = Socket::inet_aton($self->{'smtp'});
1056 0 0       0 if (!defined($self->{'smtpaddr'})) {
1057 0         0 return $self->Error(_HOSTNOTFOUND($self->{'smtp'}));
1058             }
1059 0 0       0 $self->{'smtpaddr'} = $1 if ($self->{'smtpaddr'} =~ /(.*)/s); # Untaint
1060 0 0       0 if (exists $self->{'socket'}) {
1061 0         0 my $s = $self->{'socket'};
1062 0         0 close $s;
1063 0         0 delete $self->{'socket'};
1064             }
1065             }
1066              
1067 0 0       0 $self->_prepare_headers() if ($changed{'headers'});
1068              
1069 0 0       0 if (!$self->{'to'}) { return $self->Error(_TOEMPTY); }
  0         0  
1070              
1071 0 0       0 return $self->Error(_NOSERVER) unless defined $self->{'smtp'};
1072              
1073 0 0 0     0 if ($Mail::Sender::{'SiteHook'} and !$self->SiteHook()) {
1074 0 0       0 return defined $self->{'error'} ? $self->{'error'} : $self->{'error'}
1075             = _SITEERROR();
1076             }
1077              
1078 0   0     0 my $s = $self->{'socket'} || $self->Connect();
1079 0 0       0 return $s
1080             unless ref $s; # return the error number if we did not get a socket
1081 0         0 $self->{'socket'} = $s;
1082              
1083             $_ = send_cmd $s,
1084 0   0     0 "MAIL FROM:<".($self->{'fromaddr'}||'').">".($self->{esmtp}{_MAIL_FROM}||'');
      0        
1085 0 0       0 if (!/^[123]/) { return $self->Error(_COMMERROR($_)); }
  0         0  
1086              
1087             {
1088 0         0 local $^W;
  0         0  
1089 0 0       0 if ($self->{'skip_bad_recipients'}) {
1090 0         0 my $good_count = 0;
1091 0         0 my %failed;
1092 0         0 foreach my $addr (
1093 0         0 @{$self->{'to_list'}},
1094 0         0 @{$self->{'cc_list'}},
1095 0         0 @{$self->{'bcc_list'}}
1096             )
1097             {
1098 0 0       0 if ($addr =~ /<(.*)>/) {
1099 0         0 $_ = send_cmd $s, "RCPT TO:<$1>$self->{esmtp}{_RCPT_TO}";
1100             }
1101             else {
1102 0         0 $_ = send_cmd $s, "RCPT TO:<$addr>$self->{esmtp}{_RCPT_TO}";
1103             }
1104 0 0       0 if (!/^[123]/) {
1105 0         0 chomp;
1106 0         0 s/^\d{3} //;
1107 0         0 $failed{$addr} = $_;
1108             }
1109             else {
1110 0         0 $good_count++;
1111             }
1112             }
1113 0 0       0 $self->{'skipped_recipients'} = \%failed if %failed;
1114 0 0       0 if ($good_count == 0) {
1115 0         0 return $self->Error(_ALLRECIPIENTSBAD);
1116             }
1117             }
1118             else {
1119 0         0 foreach my $addr (
1120 0         0 @{$self->{'to_list'}},
1121 0         0 @{$self->{'cc_list'}},
1122 0         0 @{$self->{'bcc_list'}}
1123             )
1124             {
1125 0 0       0 if ($addr =~ /<(.*)>/) {
1126 0         0 $_ = send_cmd $s, "RCPT TO:<$1>$self->{esmtp}{_RCPT_TO}";
1127             }
1128             else {
1129 0   0     0 $_ = send_cmd $s, "RCPT TO:<".($addr||'').">".($self->{esmtp}{_RCPT_TO}||'');
      0        
1130             }
1131 0 0       0 if (!/^[123]/) {
1132             return $self->Error(
1133 0         0 _USERUNKNOWN($addr, $self->{'smtp'}, $_));
1134             }
1135             }
1136             }
1137             }
1138              
1139 0         0 $_ = send_cmd $s, "DATA";
1140 0 0       0 if (!/^[123]/) { return $self->Error(_COMMERROR($_)); }
  0         0  
1141              
1142             $self->{'socket'}
1143             ->stop_logging("\x0D\x0A... message headers and data skipped ...")
1144 0 0 0     0 if ($self->{'debug'} and $self->{'debug_level'} <= 1);
1145 0         0 $self->{'_data'} = 1;
1146              
1147             $self->{'ctype'} = 'text/plain'
1148 0 0 0     0 if (defined $self->{'charset'} and !defined $self->{'ctype'});
1149              
1150 0         0 my $headers;
1151 0 0 0     0 if (defined $self->{'encoding'} or defined $self->{'ctype'}) {
1152 0         0 $headers = 'MIME-Version: 1.0';
1153             $headers .= "\r\nContent-Type: $self->{'ctype'}"
1154 0 0       0 if defined $self->{'ctype'};
1155             $headers .= "; charset=$self->{'charset'}"
1156 0 0       0 if defined $self->{'charset'};
1157              
1158 0         0 undef $self->{'chunk_size'};
1159 0 0       0 if (defined $self->{'encoding'}) {
1160 0         0 $headers .= "\r\nContent-Transfer-Encoding: $self->{'encoding'}";
1161 0 0       0 if ($self->{'encoding'} =~ /Base64/i) {
    0          
    0          
1162 0         0 $self->{'code'} = enc_base64($self->{'charset'});
1163 0         0 $self->{'chunk_size'} = $enc_base64_chunk;
1164             }
1165             elsif ($self->{'encoding'} =~ /Quoted[_\-]print/i) {
1166 0         0 $self->{'code'} = enc_qp($self->{'charset'});
1167             }
1168             elsif ($self->{'encoding'} =~ /^[78]bit$/i) {
1169 0         0 $self->{'code'} = enc_plain($self->{charset});
1170             }
1171             else {
1172 0         0 return $self->Error(_UNKNOWNENCODING($self->{'encoding'}));
1173             }
1174             }
1175             }
1176              
1177 0 0       0 $self->{'code'} = enc_plain($self->{charset}) unless $self->{'code'};
1178              
1179             _print_hdr $s,
1180             "To" =>
1181             (defined $self->{'fake_to'} ? $self->{'fake_to'} : $self->{'to'}),
1182 0 0       0 $self->{'charset'};
1183             _print_hdr $s,
1184             "From" =>
1185             (defined $self->{'fake_from'} ? $self->{'fake_from'} : $self->{'from'}),
1186 0 0       0 $self->{'charset'};
1187 0 0 0     0 if (defined $self->{'fake_cc'} and $self->{'fake_cc'}) {
    0 0        
1188 0         0 _print_hdr $s, "Cc" => $self->{'fake_cc'}, $self->{'charset'};
1189             }
1190             elsif (defined $self->{'cc'} and $self->{'cc'}) {
1191 0         0 _print_hdr $s, "Cc" => $self->{'cc'}, $self->{'charset'};
1192             }
1193             _print_hdr $s, "Reply-To", $self->{'reply'}, $self->{'charset'}
1194 0 0       0 if defined $self->{'reply'};
1195              
1196 0 0       0 $self->{'subject'} = "" unless defined $self->{'subject'};
1197 0         0 _print_hdr $s, "Subject" => $self->{'subject'}, $self->{'charset'};
1198              
1199 0 0 0     0 unless (defined $Mail::Sender::NO_DATE and $Mail::Sender::NO_DATE
      0        
      0        
      0        
      0        
1200             or defined $self->{'_headers'} and $self->{'_headers'} =~ /^Date:/m
1201             or defined $Mail::Sender::SITE_HEADERS
1202             && $Mail::Sender::SITE_HEADERS =~ /^Date:/m)
1203             {
1204 0         0 my $date = localtime();
1205 0         0 $date
1206             =~ s/^(\w+)\s+(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+(\d+)$/$1, $3 $2 $5 $4/;
1207 0         0 _print_hdr $s, "Date" => "$date $GMTdiff";
1208             }
1209              
1210 0 0       0 if ($self->{'priority'}) {
1211             $self->{'priority'} = $priority[$self->{'priority'}]
1212 0 0       0 if ($self->{'priority'} + 0 eq $self->{'priority'});
1213 0         0 _print_hdr $s, "X-Priority" => $self->{'priority'};
1214             }
1215              
1216 0 0       0 if ($self->{'confirm'}) {
1217 0         0 for my $confirm (split /\s*,\s*/, $self->{'confirm'}) {
1218 0 0       0 if ($confirm =~ /^\s*reading\s*(?:\:\s*(.*))?/i) {
    0          
1219             _print_hdr $s,
1220             "X-Confirm-Reading-To" => ($1 || $self->{'from'}),
1221 0   0     0 $self->{'charset'};
1222             }
1223             elsif ($confirm =~ /^\s*delivery\s*(?:\:\s*(.*))?/i) {
1224             _print_hdr $s,
1225             "Return-Receipt-To" => ($1 || $self->{'fromaddr'}),
1226 0   0     0 $self->{'charset'};
1227             _print_hdr $s,
1228             "Disposition-Notification-To" =>
1229             ($1 || $self->{'fromaddr'}),
1230 0   0     0 $self->{'charset'};
1231             }
1232             }
1233             }
1234              
1235 0 0       0 unless (defined $Mail::Sender::NO_X_MAILER) {
1236 0         0 my $script = File::Basename::basename($0);
1237 0         0 _print_hdr $s,
1238             "X-Mailer" =>
1239             qq{Perl script "$script"\r\n\tusing Mail::Sender $VERSION by Jenda Krynicky, Czechlands\r\n\trunning on $local_name ($local_IP)\r\n\tunder account "}
1240             . getusername()
1241             . qq{"\r\n};
1242             }
1243              
1244 0 0 0     0 unless (defined $Mail::Sender::NO_MESSAGE_ID
1245             and $Mail::Sender::NO_MESSAGE_ID)
1246             {
1247 0 0 0     0 if (!defined $self->{'messageid'} or $self->{'messageid'} eq '') {
1248 0 0 0     0 if (defined $self->{'createmessageid'}
1249             and ref $self->{'createmessageid'} eq 'CODE')
1250             {
1251             $self->{'messageid'}
1252 0         0 = $self->{'createmessageid'}->($self->{'fromaddr'});
1253             }
1254             else {
1255 0         0 $self->{'messageid'} = MessageID($self->{'fromaddr'});
1256             }
1257             }
1258 0         0 _print_hdr $s, "Message-ID" => $self->{'messageid'};
1259             }
1260              
1261 0 0       0 print $s $Mail::Sender::SITE_HEADERS,
1262             "\x0D\x0A" # should handle \r\n at the end of the headers
1263             if (defined $Mail::Sender::SITE_HEADERS);
1264              
1265             print $s $self->{'_headers'}, "\x0D\x0A"
1266 0 0 0     0 if defined $self->{'_headers'} and $self->{'_headers'};
1267 0 0       0 print $s $headers, "\r\n" if defined $headers;
1268              
1269 0         0 print $s "\r\n";
1270              
1271             $self->{'socket'}->stop_logging("... message data skipped ...")
1272 0 0 0     0 if ($self->{'debug'} and $self->{'debug_level'} <= 2);
1273              
1274 0         0 return $self;
1275             }
1276              
1277             sub OpenMultipart {
1278 0     0 1 0 undef $Error;
1279 0         0 my $self = shift;
1280              
1281 0         0 local $_;
1282 0 0 0     0 if (!$self->{'keepconnection'} and $self->{'_data'})
1283             { # the user did not Close() or Cancel() the previous mail
1284 0 0       0 if ($self->{'error'}) {
1285 0         0 $self->Cancel;
1286             }
1287             else {
1288 0         0 $self->Close;
1289             }
1290             }
1291              
1292 0         0 delete $self->{'error'};
1293 0         0 delete $self->{'encoding'};
1294 0         0 delete $self->{'messageid'};
1295 0         0 $self->{'_part'} = 0;
1296              
1297 0         0 my %changed;
1298 0 0 0     0 if (defined $self->{'type'} and $self->{'type'}) {
1299 0 0       0 $self->{'multipart'} = $1 if $self->{'type'} =~ m{^multipart/(.*)}i;
1300             }
1301 0 0       0 $self->{'multipart'} = 'Mixed' unless $self->{'multipart'};
1302 0         0 $self->{'idcounter'} = 0;
1303              
1304 0 0       0 if (ref $_[0] eq 'HASH') {
1305 0         0 my $key;
1306 0         0 my $hash = $_[0];
1307 0 0       0 $hash->{'multipart'} = $hash->{'subtype'} if defined $hash->{'subtype'};
1308             $hash->{'reply'} = $hash->{'replyto'}
1309 0 0 0     0 if (defined $hash->{'replyto'} and !defined $hash->{'reply'});
1310 0         0 foreach $key (keys %$hash) {
1311 0 0 0     0 if ((ref($hash->{$key}) eq 'HASH') and exists($self->{lc $key})) {
1312 0 0       0 if (ref($self->{lc $key}) eq 'HASH') {
1313 0         0 $self->{lc $key} = {%{$self->{lc $key}}, %{$hash->{$key}}};
  0         0  
  0         0  
1314             }
1315             else {
1316 0         0 $self->{lc $key} = {%{$hash->{$key}}}; # make a shallow copy
  0         0  
1317             }
1318             }
1319             else {
1320 0         0 $self->{lc $key} = $hash->{$key};
1321             }
1322 0         0 $changed{lc $key} = 1;
1323             }
1324             }
1325             else {
1326 0         0 my ($from, $reply, $to, $smtp, $subject, $headers, $boundary) = @_;
1327              
1328 0 0       0 if ($from) { $self->{'from'} = $from; $changed{'from'} = 1; }
  0         0  
  0         0  
1329 0 0       0 if ($reply) { $self->{'reply'} = $reply; $changed{'reply'} = 1; }
  0         0  
  0         0  
1330 0 0       0 if ($to) { $self->{'to'} = $to; $changed{'to'} = 1; }
  0         0  
  0         0  
1331 0 0       0 if ($smtp) { $self->{'smtp'} = $smtp; $changed{'smtp'} = 1; }
  0         0  
  0         0  
1332 0 0       0 if ($subject) {
1333 0         0 $self->{'subject'} = $subject;
1334 0         0 $changed{'subject'} = 1;
1335             }
1336 0 0       0 if ($headers) {
1337 0         0 $self->{'headers'} = $headers;
1338 0         0 $changed{'headers'} = 1;
1339             }
1340 0 0       0 if ($boundary) { $self->{'boundary'} = $boundary; }
  0         0  
1341             }
1342              
1343 0 0       0 $self->_prepare_addresses('to') if $changed{'to'};
1344 0 0       0 $self->_prepare_addresses('cc') if $changed{'cc'};
1345 0 0       0 $self->_prepare_addresses('bcc') if $changed{'bcc'};
1346              
1347 0 0       0 $self->_prepare_ESMTP() if defined $changed{'esmtp'};
1348              
1349 0 0       0 $self->{'boundary'} =~ tr/=/-/ if $changed{'boundary'};
1350              
1351 0 0       0 $self->_prepare_headers() if ($changed{'headers'});
1352              
1353 0 0       0 return $self->Error(_NOFROMSPECIFIED) unless defined $self->{'from'};
1354 0 0       0 if ($changed{'from'}) {
1355 0         0 $self->{'fromaddr'} = $self->{'from'};
1356 0         0 $self->{'fromaddr'} =~ s/.*<([^\s]*?)>/$1/; # get from email address
1357             }
1358              
1359 0 0       0 if ($changed{'reply'}) {
1360 0         0 $self->{'replyaddr'} = $self->{'reply'};
1361 0         0 $self->{'replyaddr'} =~ s/.*<([^\s]*?)>/$1/; # get reply email address
1362 0         0 $self->{'replyaddr'} =~ s/^([^\s]+).*/$1/; # use first address
1363             }
1364              
1365 0 0       0 if ($changed{'smtp'}) {
1366 0         0 $self->{'smtp'} =~ s/^\s+//g; # remove spaces around $smtp
1367 0         0 $self->{'smtp'} =~ s/\s+$//g;
1368 0         0 $self->{'smtpaddr'} = Socket::inet_aton($self->{'smtp'});
1369 0 0       0 if (!defined($self->{'smtpaddr'})) {
1370 0         0 return $self->Error(_HOSTNOTFOUND($self->{'smtp'}));
1371             }
1372 0 0       0 $self->{'smtpaddr'} = $1 if ($self->{'smtpaddr'} =~ /(.*)/s); # Untaint
1373 0 0       0 if (exists $self->{'socket'}) {
1374 0         0 my $s = $self->{'socket'};
1375 0         0 close $s;
1376 0         0 delete $self->{'socket'};
1377             }
1378             }
1379              
1380 0 0       0 if (!$self->{'to'}) { return $self->Error(_TOEMPTY); }
  0         0  
1381              
1382 0 0       0 return $self->Error(_NOSERVER) unless defined $self->{'smtp'};
1383              
1384             # if (!defined($self->{'smtpaddr'})) { return $self->Error(_HOSTNOTFOUND($self->{'smtp'})); }
1385              
1386 0 0 0     0 if ($Mail::Sender::{'SiteHook'} and !$self->SiteHook()) {
1387 0 0       0 return defined $self->{'error'} ? $self->{'error'} : $self->{'error'}
1388             = _SITEERROR();
1389             }
1390              
1391 0   0     0 my $s = $self->{'socket'} || $self->Connect();
1392 0 0       0 return $s
1393             unless ref $s; # return the error number if we did not get a socket
1394 0         0 $self->{'socket'} = $s;
1395              
1396 0         0 $_ = send_cmd $s,
1397             "MAIL FROM:<$self->{'fromaddr'}>$self->{esmtp}{_MAIL_FROM}";
1398 0 0       0 if (!/^[123]/) { return $self->Error(_COMMERROR($_)); }
  0         0  
1399              
1400             {
1401 0         0 local $^W;
  0         0  
1402 0 0       0 if ($self->{'skip_bad_recipients'}) {
1403 0         0 my $good_count = 0;
1404 0         0 my %failed;
1405 0         0 foreach my $addr (
1406 0         0 @{$self->{'to_list'}},
1407 0         0 @{$self->{'cc_list'}},
1408 0         0 @{$self->{'bcc_list'}}
1409             )
1410             {
1411 0 0       0 if ($addr =~ /<(.*)>/) {
1412 0         0 $_ = send_cmd $s, "RCPT TO:<$1>$self->{esmtp}{_RCPT_TO}";
1413             }
1414             else {
1415 0         0 $_ = send_cmd $s, "RCPT TO:<$addr>$self->{esmtp}{_RCPT_TO}";
1416             }
1417 0 0       0 if (!/^[123]/) {
1418 0         0 s/^\d{3} //;
1419 0         0 $failed{$addr} = $_;
1420             }
1421             else {
1422 0         0 $good_count++;
1423             }
1424             }
1425 0 0       0 $self->{'skipped_recipients'} = \%failed if %failed;
1426 0 0       0 if ($good_count == 0) {
1427 0         0 return $self->Error(_ALLRECIPIENTSBAD);
1428             }
1429             }
1430             else {
1431 0         0 foreach my $addr (
1432 0         0 @{$self->{'to_list'}},
1433 0         0 @{$self->{'cc_list'}},
1434 0         0 @{$self->{'bcc_list'}}
1435             )
1436             {
1437 0 0       0 if ($addr =~ /<(.*)>/) {
1438 0         0 $_ = send_cmd $s, "RCPT TO:<$1>$self->{esmtp}{_RCPT_TO}";
1439             }
1440             else {
1441 0         0 $_ = send_cmd $s, "RCPT TO:<$addr>$self->{esmtp}{_RCPT_TO}";
1442             }
1443 0 0       0 if (!/^[123]/) {
1444             return $self->Error(
1445 0         0 _USERUNKNOWN($addr, $self->{'smtp'}, $_));
1446             }
1447             }
1448             }
1449             }
1450              
1451 0         0 $_ = send_cmd $s, "DATA";
1452 0 0       0 if (!/^[123]/) { return $self->Error(_COMMERROR($_)); }
  0         0  
1453              
1454             $self->{'socket'}
1455             ->stop_logging("\x0D\x0A... message headers and data skipped ...")
1456 0 0 0     0 if ($self->{'debug'} and $self->{'debug_level'} <= 1);
1457 0         0 $self->{'_data'} = 1;
1458              
1459             _print_hdr $s,
1460             "To" =>
1461             (defined $self->{'fake_to'} ? $self->{'fake_to'} : $self->{'to'}),
1462 0 0       0 $self->{'charset'};
1463             _print_hdr $s,
1464             "From" =>
1465             (defined $self->{'fake_from'} ? $self->{'fake_from'} : $self->{'from'}),
1466 0 0       0 $self->{'charset'};
1467 0 0 0     0 if (defined $self->{'fake_cc'} and $self->{'fake_cc'}) {
    0 0        
1468 0         0 _print_hdr $s, "Cc" => $self->{'fake_cc'}, $self->{'charset'};
1469             }
1470             elsif (defined $self->{'cc'} and $self->{'cc'}) {
1471 0         0 _print_hdr $s, "Cc" => $self->{'cc'}, $self->{'charset'};
1472             }
1473             _print_hdr $s,
1474             "Reply-To" => $self->{'reply'},
1475             $self->{'charset'}
1476 0 0       0 if defined $self->{'reply'};
1477              
1478 0 0       0 $self->{'subject'} = "" unless defined $self->{'subject'};
1479 0         0 _print_hdr $s, "Subject" => $self->{'subject'}, $self->{'charset'};
1480              
1481 0 0 0     0 unless (defined $Mail::Sender::NO_DATE and $Mail::Sender::NO_DATE
      0        
      0        
      0        
      0        
1482             or defined $self->{'_headers'} and $self->{'_headers'} =~ /^Date:/m
1483             or defined $Mail::Sender::SITE_HEADERS
1484             && $Mail::Sender::SITE_HEADERS =~ /^Date:/m)
1485             {
1486 0         0 my $date = localtime();
1487 0         0 $date
1488             =~ s/^(\w+)\s+(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+(\d+)$/$1, $3 $2 $5 $4/;
1489 0         0 _print_hdr $s, "Date" => "$date $GMTdiff";
1490             }
1491              
1492 0 0       0 if ($self->{'priority'}) {
1493             $self->{'priority'} = $priority[$self->{'priority'}]
1494 0 0       0 if ($self->{'priority'} + 0 eq $self->{'priority'});
1495 0         0 _print_hdr $s, "X-Priority" => $self->{'priority'};
1496             }
1497              
1498 0 0       0 if ($self->{'confirm'}) {
1499 0         0 for my $confirm (split /\s*,\s*/, $self->{'confirm'}) {
1500 0 0       0 if ($confirm =~ /^\s*reading\s*(?:\:\s*(.*))?/i) {
    0          
1501             _print_hdr $s,
1502             "X-Confirm-Reading-To" => ($1 || $self->{'from'}),
1503 0   0     0 $self->{'charset'};
1504             }
1505             elsif ($confirm =~ /^\s*delivery\s*(?:\:\s*(.*))?/i) {
1506             _print_hdr $s,
1507             "Return-Receipt-To" => ($1 || $self->{'fromaddr'}),
1508 0   0     0 $self->{'charset'};
1509             _print_hdr $s,
1510             "Disposition-Notification-To" =>
1511             ($1 || $self->{'fromaddr'}),
1512 0   0     0 $self->{'charset'};
1513             }
1514             }
1515             }
1516              
1517 0 0 0     0 unless (defined $Mail::Sender::NO_X_MAILER and $Mail::Sender::NO_X_MAILER) {
1518 0         0 my $script = File::Basename::basename($0);
1519 0         0 _print_hdr $s,
1520             "X-Mailer" =>
1521             qq{Perl script "$script"\r\n\tusing Mail::Sender $VERSION by Jenda Krynicky, Czechlands\r\n\trunning on $local_name ($local_IP)\r\n\tunder account "}
1522             . getusername()
1523             . qq{"\r\n};
1524             }
1525              
1526 0 0       0 print $s $Mail::Sender::SITE_HEADERS, "\r\n"
1527             if (defined $Mail::Sender::SITE_HEADERS);
1528              
1529 0 0 0     0 unless (defined $Mail::Sender::NO_MESSAGE_ID
1530             and $Mail::Sender::NO_MESSAGE_ID)
1531             {
1532 0 0 0     0 if (!defined $self->{'messageid'} or $self->{'messageid'} eq '') {
1533 0 0 0     0 if (defined $self->{'createmessageid'}
1534             and ref $self->{'createmessageid'} eq 'CODE')
1535             {
1536             $self->{'messageid'}
1537 0         0 = $self->{'createmessageid'}->($self->{'fromaddr'});
1538             }
1539             else {
1540 0         0 $self->{'messageid'} = MessageID($self->{'fromaddr'});
1541             }
1542             }
1543 0         0 _print_hdr $s, "Message-ID" => $self->{'messageid'};
1544             }
1545              
1546             print $s $self->{'_headers'}, "\r\n"
1547 0 0 0     0 if defined $self->{'_headers'} and $self->{'_headers'};
1548 0         0 print $s "MIME-Version: 1.0\r\n";
1549 0         0 _print_hdr $s, "Content-Type",
1550             qq{multipart/$self->{'multipart'};\r\n\tboundary="$self->{'boundary'}"};
1551              
1552 0         0 print $s "\r\n";
1553             $self->{'socket'}->stop_logging("... message data skipped ...")
1554 0 0 0     0 if ($self->{'debug'} and $self->{'debug_level'} <= 2);
1555              
1556 0         0 print $s
1557             "This message is in MIME format. Since your mail reader does not understand\r\n"
1558             . "this format, some or all of this message may not be legible.\r\n"
1559             . "\r\n--$self->{'boundary'}\r\n";
1560              
1561 0         0 return $self;
1562             }
1563              
1564             sub Connected {
1565 0     0 1 0 my $self = shift();
1566 0 0 0     0 return unless exists $self->{'socket'} and $self->{'socket'};
1567 0         0 my $s = $self->{'socket'};
1568 0         0 return $s->opened();
1569             }
1570              
1571             sub MailMsg {
1572 0     0 1 0 my $self = shift;
1573 0         0 my $msg;
1574 0         0 local $_;
1575 0 0       0 if (ref $_[0] eq 'HASH') {
1576 0         0 my $hash = $_[0];
1577 0         0 $msg = $hash->{'msg'};
1578             }
1579             else {
1580 0         0 $msg = pop;
1581             }
1582 0 0       0 return $self->Error(_NOMSG) unless $msg;
1583              
1584 0 0 0     0 if (ref $self->Open(@_) and ref $self->SendEnc($msg) and ref $self->Close())
      0        
1585             {
1586 0         0 return $self;
1587             }
1588             else {
1589 0         0 return $self->{'error'};
1590             }
1591             }
1592              
1593             sub MailFile {
1594 0     0 1 0 my $self = shift;
1595 0         0 my $msg;
1596 0         0 local $_;
1597 0         0 my ($file, $desc, $haddesc, $ctype, $charset, $encoding);
1598 0         0 my @files;
1599 0         0 my $hash;
1600 0 0       0 if (ref $_[0] eq 'HASH') {
1601 0         0 $hash = {%{$_[0]}}; # make a copy
  0         0  
1602              
1603 0         0 $msg = delete $hash->{'msg'};
1604              
1605 0         0 $file = delete $hash->{'file'};
1606              
1607 0         0 $desc = delete $hash->{'description'};
1608 0 0       0 $haddesc = 1 if defined $desc;
1609              
1610 0         0 $ctype = delete $hash->{'ctype'};
1611              
1612 0         0 $charset = delete $hash->{'charset'};
1613              
1614 0         0 $encoding = delete $hash->{'encoding'};
1615             }
1616             else {
1617 0 0       0 $desc = pop if ($#_ >= 2);
1618 0 0       0 $haddesc = 1 if defined $desc;
1619 0         0 $file = pop;
1620 0         0 $msg = pop;
1621             }
1622 0 0       0 return $self->Error(_NOMSG) unless $msg;
1623 0 0       0 return $self->Error(_NOFILE) unless $file;
1624              
1625 0 0       0 if (ref $file eq 'ARRAY') {
    0          
1626 0         0 @files = @$file;
1627             }
1628             elsif ($file =~ /,/) {
1629 0         0 @files = split / *, */, $file;
1630             }
1631             else {
1632 0         0 @files = ($file);
1633             }
1634 0         0 foreach $file (@files) {
1635 0 0 0     0 return $self->Error(_FILENOTFOUND($file))
1636             unless ($file =~ /^&/ or -e $file);
1637             }
1638              
1639             ref $self->OpenMultipart($hash ? $hash : @_)
1640             and ref $self->Body($self->{'b_charset'} || $self->{'charset'},
1641             $self->{'b_encoding'}, $self->{'b_ctype'})
1642             and $self->SendEnc($msg)
1643 0 0 0     0 or return $self->{'error'};
    0 0        
      0        
1644              
1645 0         0 $Error = '';
1646 0         0 foreach $file (@files) {
1647 0         0 my $cnt;
1648 0         0 my $filename = File::Basename::basename $file;
1649 0   0     0 my $ctype = $ctype || GuessCType $filename, $file;
1650 0   0     0 my $encoding = $encoding
1651             || ($ctype =~ m#^text/#i ? 'Quoted-printable' : 'Base64');
1652              
1653 0 0       0 $desc = $filename unless (defined $haddesc);
1654              
1655             $self->Part(
1656             {
1657             encoding => $encoding,
1658             disposition => (
1659 0 0       0 defined $self->{'disposition'} ? $self->{'disposition'}
    0          
    0          
1660             : "attachment; filename=\"$filename\""
1661             ),
1662             ctype => (
1663             $ctype =~ /;\s*name(?:\*(?:0\*?)?)?=/ ? $ctype
1664             : "$ctype; name=\"$filename\""
1665             )
1666             . (defined $charset ? "; charset=$charset" : ''),
1667             description => $desc
1668             }
1669             );
1670              
1671 0         0 my $code = $self->{'code'};
1672              
1673 0 0       0 open my $FH, "<", $file or return $self->Error(_FILECANTREAD($file));
1674 0 0 0     0 binmode $FH
1675             unless $ctype =~ m#^text/#i
1676             and $encoding =~ /Quoted[_\-]print|Base64/i;
1677 0         0 my $s;
1678 0         0 $s = $self->{'socket'};
1679 0         0 my $mychunksize = $chunksize;
1680 0 0       0 $mychunksize = $chunksize64 if defined $self->{'chunk_size'};
1681 0         0 while (read $FH, $cnt, $mychunksize) {
1682 0         0 $cnt = $code->($cnt);
1683 0 0       0 $cnt =~ s/^\.\././ unless $self->{'_had_newline'};
1684 0         0 print $s $cnt;
1685 0         0 $self->{'_had_newline'} = ($cnt =~ /[\n\r]$/);
1686             }
1687 0         0 close $FH;
1688             }
1689              
1690 0 0       0 if ($Error eq '') {
1691 0         0 undef $Error;
1692             }
1693             else {
1694 0         0 chomp $Error;
1695             }
1696 0         0 return $self->Close;
1697             }
1698              
1699             sub Send {
1700 0     0 1 0 my $self = shift;
1701 0         0 my $s;
1702 0         0 $s = $self->{'socket'};
1703 0         0 print $s @_;
1704 0         0 return $self;
1705             }
1706              
1707             sub SendLine {
1708 0     0 1 0 my $self = shift;
1709 0         0 my $s = $self->{'socket'};
1710 0         0 print $s (@_, "\x0D\x0A");
1711 0         0 return $self;
1712             }
1713              
1714 0     0 1 0 sub print { return shift->SendEnc(@_) }
1715 0     0 1 0 sub SendLineEnc { push @_, "\r\n"; return shift->SendEnc(@_) }
  0         0  
1716              
1717             sub SendEnc {
1718 0     0 1 0 my $self = shift;
1719 0         0 local $_;
1720 0         0 my $code = $self->{'code'};
1721 0 0       0 $self->{'code'} = $code = enc_plain($self->{'charset'})
1722             unless defined $code;
1723 0         0 my $s;
1724 0 0       0 $s = $self->{'socket'} or return $self->Error(_NOTCONNECTED);
1725 0 0       0 if (defined $self->{'chunk_size'}) {
1726 0         0 my $str;
1727 0         0 my $chunk = $self->{'chunk_size'};
1728 0 0       0 if (defined $self->{'_buffer'}) {
1729 0         0 $str = (join '', ($self->{'_buffer'}, @_));
1730             }
1731             else {
1732 0         0 $str = join '', @_;
1733             }
1734 0         0 my ($len, $blen);
1735 0         0 $len = length $str;
1736 0 0       0 if (($blen = ($len % $chunk)) > 0) {
1737 0         0 $self->{'_buffer'} = substr($str, ($len - $blen));
1738 0         0 print $s ($code->(substr($str, 0, $len - $blen)));
1739             }
1740             else {
1741 0         0 delete $self->{'_buffer'};
1742 0         0 print $s ($code->($str));
1743             }
1744             }
1745             else {
1746 0         0 my $encoded = $code->(join('', @_));
1747 0 0       0 $encoded =~ s/^\.\././ unless $self->{'_had_newline'};
1748 0         0 print $s $encoded;
1749 0         0 $self->{'_had_newline'} = ($_[-1] =~ /[\n\r]$/);
1750             }
1751 0         0 return $self;
1752             }
1753              
1754 0     0 1 0 sub SendLineEx { push @_, "\r\n"; shift->SendEx(@_) }
  0         0  
1755              
1756             sub SendEx {
1757 0     0 1 0 my $self = shift;
1758 0         0 my $s;
1759 0 0       0 $s = $self->{'socket'} or return $self->Error(_NOTCONNECTED);
1760 0         0 my $str;
1761 0         0 my @data = @_;
1762 0         0 foreach $str (@data) {
1763 0         0 $str =~ s/(?:\x0D\x0A?|\x0A)/\x0D\x0A/sg;
1764 0         0 $str =~ s/^\./../mg;
1765             }
1766 0         0 print $s @data;
1767 0         0 return $self;
1768             }
1769              
1770             sub Part {
1771 0     0 1 0 my $self = shift;
1772 0         0 local $_;
1773 0 0       0 if (!$self->{'multipart'}) {
1774 0         0 return $self->Error(_NOTMULTIPART("\$sender->Part()"));
1775             }
1776 0         0 $self->EndPart();
1777              
1778 0         0 my ($description, $ctype, $encoding, $disposition, $content_id, $msg,
1779             $charset);
1780 0 0       0 if (ref $_[0] eq 'HASH') {
1781 0         0 my $hash = $_[0];
1782 0         0 $description = $hash->{'description'};
1783 0         0 $ctype = $hash->{'ctype'};
1784 0         0 $encoding = $hash->{'encoding'};
1785 0         0 $disposition = $hash->{'disposition'};
1786 0         0 $content_id = $hash->{'content_id'};
1787 0         0 $msg = $hash->{'msg'};
1788 0         0 $charset = $hash->{'charset'};
1789             }
1790             else {
1791 0         0 ($description, $ctype, $encoding, $disposition, $content_id, $msg) = @_;
1792             }
1793              
1794 0 0       0 $ctype = "application/octet-stream" unless defined $ctype;
1795 0 0       0 $disposition = "attachment" unless defined $disposition;
1796 0 0       0 $encoding = "7BIT" unless defined $encoding;
1797 0         0 $self->{'encoding'} = $encoding;
1798 0 0 0     0 if (defined $charset and $charset and $ctype !~ /charset=/i) {
    0 0        
      0        
1799 0         0 $ctype .= qq{; charset="$charset"};
1800             }
1801             elsif (!defined $charset and $ctype =~ /charset="([^"]+)"/) {
1802 0         0 $charset = $1;
1803             }
1804              
1805 0         0 my $s;
1806 0 0       0 $s = $self->{'socket'} or return $self->Error(_NOTCONNECTED);
1807              
1808 0         0 undef $self->{'chunk_size'};
1809 0 0       0 if ($encoding =~ /Base64/i) {
    0          
1810 0         0 $self->{'code'} = enc_base64($charset);
1811 0         0 $self->{'chunk_size'} = $enc_base64_chunk;
1812             }
1813             elsif ($encoding =~ /Quoted[_\-]print/i) {
1814 0         0 $self->{'code'} = enc_qp($charset);
1815             }
1816             else {
1817 0         0 $self->{'code'} = enc_plain($charset);
1818             }
1819              
1820             $self->{'socket'}->start_logging()
1821 0 0 0     0 if ($self->{'debug'} and $self->{'debug_level'} == 3);
1822              
1823 0 0       0 if ($ctype =~ m{^multipart/}i) {
1824 0         0 $self->{'_part'} += 2;
1825 0         0 print $s
1826             "Content-Type: $ctype; boundary=\"Part-$self->{'boundary'}_$self->{'_part'}\"\r\n\r\n";
1827             }
1828             else {
1829 0         0 $self->{'_part'}++;
1830 0         0 print $s "Content-Type: $ctype\r\n";
1831 0 0       0 if ($description) { print $s "Content-Description: $description\r\n"; }
  0         0  
1832 0         0 print $s "Content-Transfer-Encoding: $encoding\r\n";
1833 0 0 0     0 print $s "Content-Disposition: $disposition\r\n"
1834             unless $disposition eq ''
1835             or uc($disposition) eq 'NONE';
1836 0 0       0 print $s "Content-ID: <$content_id>\r\n" if (defined $content_id);
1837 0         0 print $s "\r\n";
1838              
1839             $self->{'socket'}->stop_logging("... data skipped ...")
1840 0 0 0     0 if ($self->{'debug'} and $self->{'debug_level'} == 3);
1841 0 0       0 $self->SendEnc($msg) if defined $msg;
1842             }
1843              
1844             #$self->{'_had_newline'} = 1;
1845 0         0 return $self;
1846             }
1847              
1848             sub Body {
1849 0     0 1 0 my $self = shift;
1850 0 0       0 if (!$self->{'multipart'}) {
1851              
1852             # ->Body() has no meanin in singlepart messages
1853 0 0       0 if (@_) {
1854              
1855             # they called it with some parameters? Too late for them, let's scream.
1856 0         0 return $self->Error(_NOTMULTIPART("\$sender->Body()"));
1857             }
1858             else {
1859             # $sender->Body() ... OK, let's ignore it.
1860 0         0 return $self;
1861             }
1862             }
1863 0         0 my $hash;
1864 0 0       0 $hash = shift() if (ref $_[0] eq 'HASH');
1865 0   0     0 my $charset = shift || $hash->{'charset'} || 'US-ASCII';
1866             my $encoding
1867 0   0     0 = shift || $hash->{'encoding'} || $self->{'encoding'} || '7BIT';
1868 0   0     0 my $ctype = shift || $hash->{'ctype'} || $self->{'ctype'} || 'text/plain';
1869              
1870 0 0       0 $ctype .= qq{; charset="$charset"} unless $ctype =~ /charset=/i;
1871              
1872 0         0 $self->{'encoding'} = $encoding;
1873 0         0 $self->{'ctype'} = $ctype;
1874              
1875             $self->Part("Mail message body",
1876 0         0 $ctype, $encoding, 'inline', undef, $hash->{'msg'});
1877 0         0 return $self;
1878             }
1879              
1880 0     0 1 0 sub Attach { shift->SendFile(@_) }
1881              
1882             sub SendFile {
1883 0     0 1 0 my $self = shift;
1884 0         0 local $_;
1885 0 0       0 if (!$self->{'multipart'}) {
1886 0         0 return $self->Error(_NOTMULTIPART("\$sender->SendFile()"));
1887             }
1888 0 0       0 if (!$self->{'socket'}) { return $self->Error(_NOTCONNECTED); }
  0         0  
1889              
1890 0         0 my ($description, $ctype, $encoding, $disposition, $file, $content_id,
1891             @files);
1892 0 0       0 if (ref $_[0] eq 'HASH') {
1893 0         0 my $hash = $_[0];
1894 0         0 $description = $hash->{'description'};
1895 0         0 $ctype = $hash->{'ctype'};
1896 0         0 $encoding = $hash->{'encoding'};
1897 0         0 $disposition = $hash->{'disposition'};
1898 0         0 $file = $hash->{'file'};
1899 0         0 $content_id = $hash->{'content_id'};
1900             }
1901             else {
1902 0         0 ($description, $ctype, $encoding, $disposition, $file, $content_id)
1903             = @_;
1904             }
1905 0 0       0 return ($self->{'error'} = _NOFILE) unless $file;
1906              
1907 0 0       0 if (ref $file eq 'ARRAY') {
    0          
1908 0         0 @files = @$file;
1909             }
1910             elsif ($file =~ /,/) {
1911 0         0 @files = split / *, */, $file;
1912             }
1913             else {
1914 0         0 @files = ($file);
1915             }
1916 0         0 foreach $file (@files) {
1917 0 0 0     0 return $self->Error(_FILENOTFOUND($file))
1918             unless ($file =~ /^&/ or -e $file);
1919             }
1920              
1921 0 0       0 $disposition = "attachment; filename=*" unless defined $disposition;
1922 0 0       0 $encoding = 'Base64' unless $encoding;
1923              
1924 0         0 my $s = $self->{'socket'};
1925              
1926 0 0       0 if ($self->{'_buffer'}) {
1927 0         0 my $code = $self->{'code'};
1928 0         0 print $s ($code->($self->{'_buffer'}));
1929 0         0 delete $self->{'_buffer'};
1930             }
1931              
1932 0         0 my $code;
1933 0 0       0 if ($encoding =~ /Base64/i) {
    0          
1934 0         0 $code = enc_base64();
1935             }
1936             elsif ($encoding =~ /Quoted[_\-]print/i) {
1937 0         0 $code = enc_qp();
1938             }
1939             else {
1940 0         0 $code = enc_plain();
1941             }
1942 0         0 $self->{'code'} = $code;
1943              
1944 0         0 foreach $file (@files) {
1945 0         0 $self->EndPart();
1946 0         0 $self->{'_part'}++;
1947 0         0 $self->{'encoding'} = $encoding;
1948 0         0 my $cnt = '';
1949 0         0 my $name = File::Basename::basename $file;
1950 0 0       0 my $fctype = $ctype ? $ctype : GuessCType $name, $file;
1951 0         0 $self->{'ctype'} = $fctype;
1952              
1953             $self->{'socket'}->start_logging()
1954 0 0 0     0 if ($self->{'debug'} and $self->{'debug_level'} == 3);
1955              
1956 0 0       0 if ($fctype =~ /;\s*name(?:\*(?:0\*?)?)?=/)
1957             { # looking for name=, name*=, name*0= or name*0*=
1958 0         0 print $s ("Content-Type: $fctype\r\n");
1959             }
1960             else {
1961 0         0 print $s ("Content-Type: $fctype; name=\"$name\"\r\n");
1962             }
1963              
1964 0 0       0 if ($description) {
1965 0         0 print $s ("Content-Description: $description\r\n");
1966             }
1967 0         0 print $s ("Content-Transfer-Encoding: $encoding\r\n");
1968              
1969 0 0 0     0 if ($disposition =~ /^(.*)filename=\*(.*)$/i) {
    0          
1970 0         0 print $s ("Content-Disposition: ${1}filename=\"$name\"$2\r\n");
1971             }
1972             elsif ($disposition and uc($disposition) ne 'NONE') {
1973 0         0 print $s ("Content-Disposition: $disposition\r\n");
1974             }
1975              
1976 0 0       0 if ($content_id) {
1977 0 0       0 if ($content_id eq '*') {
    0          
1978 0         0 print $s ("Content-ID: <$name>\r\n");
1979             }
1980             elsif ($content_id eq '#') {
1981 0         0 print $s ("Content-ID: {'idcounter'}++ . ">\r\n");
1982             }
1983             else {
1984 0         0 print $s ("Content-ID: <$content_id>\r\n");
1985             }
1986             }
1987 0         0 print $s "\r\n";
1988              
1989             $self->{'socket'}->stop_logging("... data skipped ...")
1990 0 0 0     0 if ($self->{'debug'} and $self->{'debug_level'} == 3);
1991              
1992 0 0       0 open my $FH, "<", $file or return $self->Error(_FILECANTREAD($file));
1993 0 0 0     0 binmode $FH
1994             unless $fctype =~ m#^text/#i
1995             and $encoding =~ /Quoted[_\-]print|Base64/i;
1996              
1997 0         0 my $mychunksize = $chunksize;
1998 0 0       0 $mychunksize = $chunksize64 if lc($encoding) eq "base64";
1999 0         0 my $s;
2000 0 0       0 $s = $self->{'socket'} or return $self->Error(_NOTCONNECTED);
2001 0         0 while (read $FH, $cnt, $mychunksize) {
2002 0         0 print $s ($code->($cnt));
2003             }
2004 0         0 close $FH;
2005             }
2006              
2007 0         0 return $self;
2008             }
2009              
2010             sub EndPart {
2011 0     0 1 0 my $self = shift;
2012 0 0       0 return unless $self->{'_part'};
2013 0         0 my $end = shift();
2014 0         0 my $s;
2015 0         0 my $LN = "\x0D\x0A";
2016 0 0       0 $s = $self->{'socket'} or return $self->Error(_NOTCONNECTED);
2017              
2018             # flush the buffer (if it contains anything)
2019 0 0       0 if ($self->{'_buffer'}) { # used only for base64
2020 0         0 my $code = $self->{'code'};
2021 0 0       0 if (defined $code) {
2022 0         0 print $s ($code->($self->{'_buffer'}));
2023             }
2024             else {
2025 0         0 print $s ($self->{'_buffer'});
2026             }
2027 0         0 delete $self->{'_buffer'};
2028             }
2029 0 0       0 if ($self->{'_had_newline'}) {
2030 0         0 $LN = '';
2031             }
2032             else {
2033             print $s "="
2034             if !$self->{'bypass_outlook_bug'}
2035 0 0 0     0 and $self->{'encoding'}
2036             =~ /Quoted[_\-]print/i; # make sure we do not add a newline
2037             }
2038              
2039             $self->{'socket'}->start_logging()
2040 0 0 0     0 if ($self->{'debug'} and $self->{'debug_level'} == 3);
2041              
2042 0 0       0 if ($self->{'_part'} > 1) { # end of a subpart
2043 0 0       0 print $s "$LN--Part-$self->{'boundary'}_$self->{'_part'}",
2044             ($end ? "--" : ()), "\r\n";
2045             }
2046             else {
2047 0 0       0 print $s "$LN--$self->{'boundary'}", ($end ? "--" : ()), "\r\n";
2048             }
2049              
2050 0         0 $self->{'_part'}--;
2051 0         0 $self->{'code'} = enc_plain($self->{'charset'});
2052 0         0 $self->{'encoding'} = '';
2053 0         0 return $self;
2054             }
2055              
2056             sub Close {
2057 0     0 1 0 my $self = shift;
2058 0         0 local $_;
2059 0         0 my $s = $self->{'socket'};
2060 0 0       0 return 0 unless $s;
2061              
2062 0 0       0 if ($self->{'_data'}) {
2063              
2064             # flush the buffer (if it contains anything)
2065 0 0       0 if ($self->{'_buffer'}) {
2066 0         0 my $code = $self->{'code'};
2067 0 0       0 if (defined $code) {
2068 0         0 print $s ($code->($self->{'_buffer'}));
2069             }
2070             else {
2071 0         0 print $s ($self->{'_buffer'});
2072             }
2073 0         0 delete $self->{'_buffer'};
2074             }
2075              
2076 0 0       0 if ($self->{'_part'}) {
2077 0         0 while ($self->{'_part'}) {
2078 0         0 $self->EndPart(1);
2079             }
2080             }
2081              
2082 0 0       0 $self->{'socket'}->start_logging() if ($self->{'debug'});
2083 0         0 print $s "\r\n.\r\n";
2084 0         0 $self->{'_data'} = 0;
2085 0         0 $_ = get_response($s);
2086 0 0       0 if (/^[45]\d* (.*)$/) { return $self->Error(_TRANSFAILED($1)); }
  0         0  
2087 0         0 $self->{message_response} = $_;
2088             }
2089              
2090 0         0 delete $self->{'encoding'};
2091 0         0 delete $self->{'ctype'};
2092              
2093 0 0 0     0 if ($_[0] or !$self->{'keepconnection'}) {
2094 0         0 $_ = send_cmd $s, "QUIT";
2095 0 0       0 if (!/^[123]/) { return $self->Error(_COMMERROR($_)); }
  0         0  
2096 0         0 close $s;
2097 0         0 delete $self->{'socket'};
2098 0         0 delete $self->{'debug'};
2099             }
2100 0         0 return $self;
2101             }
2102              
2103             sub Cancel {
2104 0     0 1 0 my $self = shift;
2105 0         0 my $s;
2106 0 0       0 $s = $self->{'socket'} or return $self->Error(_NOTCONNECTED);
2107 0         0 close $s;
2108 0         0 delete $self->{'socket'};
2109 0         0 delete $self->{'error'};
2110 0         0 return $self;
2111             }
2112              
2113             sub DESTROY {
2114 19 50   19   4743 return if ref($_[0]) ne 'Mail::Sender';
2115 19         26 my $self = shift;
2116 19 50       249 if (defined $self->{'socket'}) {
2117 0           delete $self->{'keepconnection'};
2118 0           $self->Close;
2119             }
2120             }
2121              
2122             sub MessageID {
2123 0     0 1   my $from = shift;
2124 0           my ($sec, $min, $hour, $mday, $mon, $year) = gmtime(time);
2125 0           $mon++;
2126 0           $year += 1900;
2127              
2128 0           return sprintf "<%04d%02d%02d_%02d%02d%02d_%06d.%s>", $year, $mon, $mday,
2129             $hour, $min, $sec, rand(100000), $from;
2130             }
2131              
2132             sub QueryAuthProtocols {
2133 0     0 1   my $self = shift;
2134 0 0         Carp::croak(
2135             "Mail::Sender::QueryAuthProtocols() called without any parameter!")
2136             unless defined $self;
2137 0           local $_;
2138 0 0         if (ref $self) {
    0          
2139              
2140             # $sender->QueryAuthProtocols() or $sender->QueryAuthProtocols('the.server.com)
2141 0 0         if ($self->{'socket'}) {
2142              
2143             # the user did not Close() or Cancel() the previous mail
2144 0           die
2145             "You forgot to close the mail before calling QueryAuthProtocols!\n";
2146             }
2147 0 0         if (@_) {
2148 0           $self->{'smtp'} = shift();
2149 0           $self->{'smtp'} =~ s/^\s+//g; # remove spaces around $smtp
2150 0           $self->{'smtp'} =~ s/\s+$//g;
2151 0           $self->{'smtpaddr'} = Socket::inet_aton($self->{'smtp'});
2152 0 0         if (!defined($self->{'smtpaddr'})) {
2153 0           return $self->Error(_HOSTNOTFOUND($self->{'smtp'}));
2154             }
2155             $self->{'smtpaddr'} = $1
2156 0 0         if ($self->{'smtpaddr'} =~ /(.*)/s); # Untaint
2157             }
2158             }
2159             elsif ($self =~ /::/) { # Mail::Sender->QueryAuthProtocols('the.server.com')
2160 0 0         Carp::croak
2161             "Mail::Sender->QueryAuthProtocols() called without any parameter!"
2162             if !@_;
2163 0           $self = Mail::Sender->new({smtp => $_[0]});
2164 0 0         return unless ref $self;
2165             }
2166             else { # Mail::Sender::QueryAuthProtocols('the.server.com')
2167 0           $self = Mail::Sender->new({smtp => $self});
2168 0 0         return unless ref $self;
2169             }
2170              
2171 0 0         return $self->Error(_NOSERVER) unless defined $self->{'smtp'};
2172              
2173             my $s = IO::Socket::INET->new(
2174             PeerHost => $self->{'smtp'},
2175             PeerPort => $self->{'port'},
2176             Proto => "tcp",
2177 0 0 0       Timeout => $self->{'timeout'} || 120,
2178             ) or return $self->Error(_CONNFAILED);
2179              
2180 0           $s->autoflush(1);
2181              
2182 0           $_ = get_response($s);
2183 0 0 0       if (not $_ or !/^[123]/) { return $self->Error(_SERVNOTAVAIL($_)); }
  0            
2184 0           $self->{'server'} = substr $_, 4;
2185              
2186             {
2187 0           my $res = $self->_say_helo($s);
  0            
2188 0 0         return $res if $res;
2189             }
2190              
2191 0           $_ = send_cmd $s, "QUIT";
2192 0           close $s;
2193 0           delete $self->{'socket'};
2194              
2195 0 0         if (wantarray) {
2196 0           return keys %{$self->{'auth_protocols'}};
  0            
2197             }
2198             else {
2199 0           my $key = each %{$self->{'auth_protocols'}};
  0            
2200 0           return $key;
2201             }
2202             }
2203              
2204             sub printAuthProtocols {
2205 0   0 0 0   print "$_[1] supports: ",
2206             join(", ", Mail::Sender->QueryAuthProtocols($_[1] || 'localhost')),
2207             "\n";
2208             }
2209              
2210             sub TestServer {
2211 0     0 0   my $self = shift;
2212 0           local $_;
2213 0 0         if (!defined $self) {
    0          
    0          
2214 0           Carp::croak "Mail::Sender::TestServer() called without any parameter!";
2215             }
2216             elsif (ref $self)
2217             { # $sender->TestServer() or $sender->TestServer('the.server.com)
2218 0 0         if ($self->{'socket'})
2219             { # the user did not Close() or Cancel() the previous mail
2220 0           die "You forgot to close the mail before calling TestServer!\n";
2221             }
2222 0 0         if (@_) {
2223 0           $self->{'smtp'} = shift();
2224 0           $self->{'smtp'} =~ s/^\s+//g; # remove spaces around $smtp
2225 0           $self->{'smtp'} =~ s/\s+$//g;
2226 0           $self->{'smtpaddr'} = Socket::inet_aton($self->{'smtp'});
2227 0 0         if (!defined($self->{'smtpaddr'})) {
2228 0           return $self->Error(_HOSTNOTFOUND($self->{'smtp'}));
2229             }
2230             $self->{'smtpaddr'} = $1
2231 0 0         if ($self->{'smtpaddr'} =~ /(.*)/s); # Untaint
2232             }
2233 0           $self->{'on_errors'} = 'die';
2234             }
2235             elsif ($self =~ /::/) { # Mail::Sender->TestServer('the.server.com')
2236 0 0         Carp::croak("Mail::Sender->TestServer() called without any parameter!")
2237             if !@_;
2238 0           $self = Mail::Sender->new({smtp => $_[0], on_errors => 'die'});
2239 0 0         return unless ref $self;
2240             }
2241             else { # Mail::Sender::QueryAuthProtocols('the.server.com')
2242 0           $self = Mail::Sender->new({smtp => $self, on_errors => 'die'});
2243 0 0         return unless ref $self;
2244             }
2245              
2246 0 0         return $self->Error(_NOSERVER) unless defined $self->{'smtp'};
2247              
2248             # if (!defined($self->{'smtpaddr'})) { return $self->Error(_HOSTNOTFOUND($self->{'smtp'})); }
2249              
2250 0 0 0       if (exists $self->{'on_errors'}
    0 0        
      0        
2251             and (!defined($self->{'on_errors'}) or $self->{'on_errors'} eq 'undef'))
2252             {
2253 0   0       return ($self->Connect() and $self->Close() and 1);
2254             }
2255             elsif (exists $self->{'on_errors'} and $self->{'on_errors'} eq 'die') {
2256 0           $self->Connect();
2257 0           $self->Close();
2258 0           return 1;
2259             }
2260             else {
2261 0           my $res = $self->Connect();
2262 0 0         return $res unless ref $res;
2263 0           $res = $self->Close();
2264 0 0         return $res unless ref $res;
2265 0           return $self;
2266             }
2267             }
2268              
2269             #====== Debuging bazmecks
2270              
2271             $debug_code = <<'END';
2272             package Mail::Sender::DBIO;
2273             use IO::Handle;
2274             use Tie::Handle;
2275             @Mail::Sender::DBIO::ISA = qw(Tie::Handle);
2276              
2277             sub SOCKET () {0}
2278             sub LOG () {1}
2279             sub ENDLINE () {2}
2280             sub CLOSELOG () {3}
2281             sub OFF () {4}
2282              
2283             sub TIEHANDLE {
2284             my ($pkg,$socket,$debughandle, $mayCloseLog) = @_;
2285             return bless [$socket,$debughandle,1, $mayCloseLog,0], $pkg;
2286             }
2287              
2288             sub PRINT {
2289             my $self = shift;
2290             my $text = join(($\ || ''), @_);
2291             $self->[SOCKET]->print($text);
2292             return if $self->[OFF];
2293             $text =~ s/\x0D\x0A(?=.)/\x0D\x0A<< /g;
2294             $text = "<< ".$text if $self->[ENDLINE];
2295             $self->[ENDLINE] = ($text =~ /\x0D\x0A$/);
2296             $self->[LOG]->print($text);
2297             }
2298              
2299             sub READLINE {
2300             my $self = shift();
2301             my $socket = $self->[SOCKET];
2302             my $line = <$socket>;
2303             $self->[LOG]->print(">> $line") if defined $line and !$self->[OFF];
2304             return $line;
2305             }
2306              
2307             sub CLOSE {
2308             my $self = shift();
2309             $self->[SOCKET]->close();
2310             $self->[LOG]->close() if $self->[CLOSELOG];
2311             return $self->[SOCKET];
2312             }
2313              
2314             sub opened {
2315             our $SOCKET;
2316             local *SOCKET = $_[SOCKET] or return;
2317             $SOCKET->opened();
2318             }
2319              
2320             use Data::Dumper;
2321             sub stop_logging {
2322             my $self = tied(${$_[0]});
2323              
2324             #print "stop_logging( ".$self." )\n";
2325              
2326             return if $self->[OFF];
2327             $self->[OFF] = 1;
2328              
2329             my $text = join(($\ || ''), $_[1])
2330             or return;
2331             $text .= "\x0D\x0A";
2332             $text =~ s/\x0D\x0A(?=.)/\x0D\x0A<< /g;
2333             $text = "<< ".$text if $self->[ENDLINE];
2334             $self->[ENDLINE] = ($text =~ /\x0D\x0A$/);
2335             $self->[LOG]->print($text);
2336             }
2337              
2338             sub start_logging {
2339             my $self = tied(${$_[0]});
2340             $self->[OFF] = 0;
2341             }
2342             END
2343              
2344             my $pseudo_handle_code = <<'END';
2345             package Mail::Sender::IO;
2346             use IO::Handle;
2347             use Tie::Handle;
2348             @Mail::Sender::IO::ISA = qw(Tie::Handle);
2349              
2350             sub TIEHANDLE {
2351             my ($pkg,$sender) = @_;
2352             return bless [$sender, $sender->{'_part'}], $pkg;
2353             }
2354              
2355             sub PRINT {
2356             my $self = shift;
2357             $self->[0]->SendEnc(@_);
2358             }
2359              
2360             sub PRINTF {
2361             my $self = shift;
2362             my $format = shift;
2363             $self->[0]->SendEnc( sprintf $format, @_);
2364             }
2365              
2366             sub CLOSE {
2367             my $self = shift();
2368             if ($self->[1]) {
2369             $self->[1]->EndPart();
2370             } else {
2371             $self->[0]->Close();
2372             }
2373             }
2374             END
2375              
2376             package Mail::Sender;
2377              
2378             sub GetHandle {
2379 0     0 1   my $self = shift();
2380 0 0         unless (@Mail::Sender::IO::ISA) {
2381 0           eval "use Symbol;";
2382 0           eval $pseudo_handle_code;
2383             }
2384 0           my $handle = gensym();
2385 0           tie *$handle, 'Mail::Sender::IO', $self;
2386 0           return $handle;
2387             }
2388              
2389             1;
2390              
2391             __END__