/usr/share/perl5/MSDW/SMTP/Client.pm is in libmsdw-smtp-perl 1.2-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | # This code is Copyright (C) 2001 Morgan Stanley Dean Witter, and
# is distributed according to the terms of the GNU Public License
# as found at <URL:http://www.fsf.org/copyleft/gpl.html>.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# Written by Bennett Todd <bet@rahul.net>
#enable support for IPv6, if available
eval "require IO::Socket::INET6";
if ($@ && $@ =~ /^Can't locate/)
{
# a dummy INET6 module that falls back on IO::Socket::INET
eval q|
package IO::Socket::INET6;
use base "IO::Socket::INET";
|;
}
package MSDW::SMTP::Client;
use IO::Socket;
=head1 NAME
MSDW::SMTP::Client --- SMTP client for content-scanning proxy
=head1 SYNOPSIS
use MSDW::SMTP::Client;
my $client = MSDW::SMTP::Client->new(interface => $interface,
port => $port);
my %response;
$response{banner} = $client->hear;
$client->say("helo bunky");
$response{helo} = $client->hear;
$client->say("mail from: me");
$response{from} = $client->hear;
$client->say("rcpt to: you");
$response{to} = $client->hear;
$client->say("data");
$response{data} = $client->hear;
$client->yammer(FILEHANDLE);
$response{dot} = $client->hear;
$client->say("quit");
$response{quit} = $client->hear;
undef $client;
=head1 DESCRIPTION
MSDW::SMTP::Client provides a very lean SMTP client implementation;
the only protocol-specific knowlege it has is the structure of SMTP
multiline responses. All specifics lie in the hands of the calling
program; this makes it appropriate for a semi-transparent SMTP
proxy, passing commands between a talker and a listener.
=head1 METHODS
=over 8
=item new(interface => $interface, port => $port[, timeout = 300]);
The interface and port to talk to must be specified. The interface
must be a valid numeric IP address; the port must be numeric. If
this call succeeds, it returns a client structure with an open
IO::Socket::INET in it, ready to talk to. If it fails it dies,
so if you want anything other than an exit with an explanatory
error message, wrap the constructor call in an eval block and pull
the error out of $@ as usual. This is also the case for all other
methods; they succeed or they die. The timeout parameter is passed
on into the IO::Socket::INET constructor.
=item hear
hear collects a complete SMTP response and returns it with trailing
CRLF removed; for multi-line responses, intermediate CRLFs are left
intact. Returns undef if EOF is seen before a complete reply is
collected.
=item say("command text")
say sends an SMTP command, appending CRLF.
=item yammer(FILEHANDLE)
yammer takes a filehandle (which should be positioned at the
beginning of the file, remember to $fh->seek(0,0) if you've just
written it) and sends its contents as the contents of DATA. This
should only be invoked after a $client->say("data") and a
$client->hear to collect the reply to the data command. It will send
the trailing "." as well. It will perform leading-dot-doubling in
accordance with the SMTP protocol spec, where "leading dot" is
defined in terms of CR-LF terminated lines --- i.e. the data should
contain CR-LF data without the leading-dot-quoting. The filehandle
will be left at EOF.
=back
=cut
sub new {
my ($this, @opts) = @_;
my $class = ref($this) || $this;
my $self = bless { timeout => 300, @opts }, $class;
$self->{sock} = IO::Socket::INET6->new(
PeerAddr => $self->{interface},
PeerPort => $self->{port},
Timeout => $self->{timeout},
Proto => 'tcp',
Type => SOCK_STREAM,
);
die "$0: socket connect failure: $!\n" unless defined $self->{sock};
return $self;
}
sub hear {
my ($self) = @_;
my ($tmp, $reply);
return undef unless $tmp = $self->{sock}->getline;
while ($tmp =~ /^\d{3}-/) {
$reply .= $tmp;
return undef unless $tmp = $self->{sock}->getline;
}
$reply .= $tmp;
$reply =~ s/\r\n$//;
return $reply;
}
sub say {
my ($self, @msg) = @_;
return unless @msg;
$self->{sock}->print("@msg", "\r\n") or die "$0: write error: $!";
}
sub yammer {
my ($self, $fh) = (@_);
local (*_);
local ($/) = "\r\n";
while (<$fh>) {
$self->write_data_line($_);
}
$self->{sock}->print(".\r\n") or die "$0: write error: $!\n";
}
sub write_data_line
{
my ($self, $line) = @_;
$line =~ s/^\./../;
$self->{sock}->print($line)
or die "$0: write error: $!\n";
}
1;
|