File Coverage

blib/lib/Net/SMTP/Server/Client2.pm
Criterion Covered Total %
statement 15 128 11.7
branch 0 26 0.0
condition 0 6 0.0
subroutine 5 25 20.0
pod 0 9 0.0
total 20 194 10.3


line stmt bran cond sub pod time code
1             package Net::SMTP::Server::Client2;
2              
3 1     1   5354 use 5.001;
  1         4  
  1         32  
4 1     1   5 use strict;
  1         2  
  1         31  
5              
6 1     1   5 use vars qw($VERSION );
  1         11  
  1         33  
7              
8 1     1   4 use Carp;
  1         1  
  1         55  
9 1     1   778 use IO::Socket;
  1         24109  
  1         4  
10              
11              
12             $VERSION = '0.2';
13              
14             my %_cmds = (
15             DATA => \&_data,
16             EXPN => \&_noway,
17             HELO => \&_hello,
18             HELP => \&_help,
19             MAIL => \&_mail,
20             NOOP => \&_noop,
21             QUIT => \&_quit,
22             RCPT => \&_receipt,
23             RSET => \&_reset,
24             VRFY => \&_noway
25             );
26              
27             # Utility functions.
28             sub _put {
29 0     0     print {shift->{SOCK}} @_, "\r\n";
  0            
30              
31             }
32              
33             sub _reset0 {
34 0     0     my $self = shift;
35 0           $self->{FROM} = undef;
36 0           $self->{TO} = [];
37 0           $self->{MSG} = undef;
38 0           $self->{faults} = 0;
39             }
40              
41            
42             sub _reset {
43 0     0     my $self = shift;
44 0           $self->_reset0;
45 0           $self->_put("250 buffahs ah cleah, suh!");
46             }
47              
48             # New instance.
49             sub new {
50 0     0 0   my($this, $sock) = @_;
51            
52 0   0       my $class = ref($this) || $this;
53 0           my $self = {};
54            
55 0           bless($self, $class);
56 0           $self->_reset0;
57 0           $self->{SOCK} = $sock;
58              
59 0 0         croak("No client connection specified.") unless defined($self->{SOCK});
60 0           return $self;
61             }
62              
63             sub greet {
64            
65 0     0 0   $_[0]->_put("220 Debatable SMTP $VERSION Ready.");
66             }
67              
68             sub basta{
69 0     0 0   my $self = shift;
70 0           $self -> _put("421 closing transmission channel");
71 0           $self->{SOCK}->close;
72 0           1;
73             }
74              
75             # sub process {
76             sub get_message {
77 0     0 0   my $self = shift;
78 0           my($cmd, @args);
79            
80 0           my $sock = $self->{SOCK};
81 0           $self->_reset0;
82            
83 0           while(<$sock>) {
84 0           print "$$ command: $_";
85 0 0 0       $$self{faults} > 15 and $self->basta and last;
86             # Clean up.
87 0           chomp;
88 0           s/^\s+//;
89 0           s/\s+$//;
90 0 0         unless(length $_){
91 0           ++$$self{faults};
92 0           $self->greet;
93 0           next;
94             };
95 0           ($cmd, @args) = split(/\s+/);
96            
97 0           $cmd =~ tr/a-z/A-Z/;
98            
99 0 0         if(!defined($_cmds{$cmd})) {
100 0           sleep ++$$self{faults};
101 0           $self->_put("500 sorry, I don't know how to $cmd");
102 0           next;
103             };
104            
105             # all commands return TRUE to indicate that
106             # we need to keep working to get the message.
107 0 0         &{$_cmds{$cmd}}($self, \@args) or
  0            
108             return(defined($self->{MSG}));
109             }
110              
111 0           return undef;
112             }
113              
114             sub find_addresses {
115             # find e-mail addresses in the arguments and return them.
116             # max one e-mail address per argument.
117             # print "looking for addresses in <@_>\n";
118 0 0   0 0   return map { /([^<|;]+\@[^>|;&,\s]+)/ ? $1 : () } @_;
  0            
119             };
120              
121             sub okay {
122 0     0 0   my $self = shift;
123 0           $self -> _put("250 OK @_");
124             }
125              
126             sub fail {
127 0     0 0   my $self = shift;
128 0           $self -> _put("554 @_");
129             }
130              
131             sub too_long {
132 0     0 0   $_[0] -> _put("552 Too much mail data");
133             };
134              
135             sub _mail {
136 0     0     my $self = $_[0];
137 0           my @who = find_addresses(@{$_[1]});
  0            
138 0           my $who = shift @who;
139 0 0         if ($who){
140 0           $self->{FROM} = $who;
141 0           return $self->okay("Envelope sender set to <$who> ")
142             }else{
143 0           $self->{faults}++;
144 0           return $self-> _put("501 could not find name\@postoffice in <@{$_[1]}>")
  0            
145             };
146             }
147              
148             sub rcpt_syntax{
149 0     0 0   $_[0] -> _put("553 no user\@host addresses found in <@{$_[1]}>");
  0            
150             }
151              
152             sub _receipt {
153 0     0     my $self = $_[0];
154 0           my @recipients = find_addresses(@{$_[1]});
  0            
155 0 0         @recipients or return $self->rcpt_syntax($_[1]);
156 0           push @{ $self->{TO} }, @recipients;
  0            
157 0           $self->okay("sending to @{$self->{TO}}");
  0            
158             }
159              
160             sub _data {
161 0     0     my $self = shift;
162            
163 0           my @msg;
164            
165 0 0         if(!$self->{FROM}) {
166 0           $self-> _put("503 start with 'mail from: ...'");
167 0           $self->{faults}++;
168 0           return 1;
169             }
170            
171 0 0         if(!@{$self->{TO}}) {
  0            
172 0           $self->_put("503 specify recipients with 'rcpt to: ...'");
173 0           $self->{faults}++;
174 0           return 1;
175             }
176              
177 0           $self->_put("354 And what am I to tell them?");
178              
179 0           my $sock = $self->{SOCK};
180            
181 0           while(<$sock>) {
182 0           print "$$ data: $_";
183 0 0         if(/^\.\r*\n*$/) {
184 0           $self->{MSG} = join ('', @msg);
185 0           return 0; # please examine MSG
186             }
187            
188             # RFC 821 compliance.
189 0           s/^\.\./\./;
190 0           push @msg, $_;
191             }
192            
193 0           return 0; # socket died
194             }
195              
196             sub _noway {
197 0     0     shift->_put("252 Nice try.");
198             }
199              
200             sub _noop {
201 0     0     shift->_put("250 Whatever.");
202             }
203              
204             sub _help {
205 0     0     my $self = shift;
206 0           my $i = 0;
207 0           my $str = "214-Commands\r\n";
208 0           my $total = keys(%_cmds);
209            
210 0           foreach(sort(keys(%_cmds))) {
211 0 0         if(!($i++ % 5)) {
212 0 0         if(($total - $i) < 5) {
213 0           $str .= "\r\n214 ";
214             } else {
215 0           $str .= "\r\n214-";
216             }
217             } else {
218 0           $str .= ' ';
219             }
220            
221 0           $str .= $_;
222             }
223            
224 0           $self->_put($str);
225             }
226              
227             sub _quit {
228 0     0     my $self = shift;
229            
230 0           $self->_put("221 Ciao");
231 0           $self->{SOCK}->close;
232 0           return 0;
233             }
234              
235             sub _hello {
236 0     0     shift->okay( "Welcome" );
237             }
238              
239             1;
240             __END__