home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / xampp / xampp-perl-addon-1.4.9-installer.exe / Client2.pm < prev    next >
Encoding:
Perl POD Document  |  2002-11-13  |  7.0 KB  |  338 lines

  1. package Net::SMTP::Server::Client2;
  2.  
  3. use 5.001;
  4. use strict;
  5.  
  6. use vars qw($VERSION );
  7.  
  8. use Carp;
  9. use IO::Socket;
  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.     print {shift->{SOCK}} @_, "\r\n";
  30.  
  31. }
  32.  
  33. sub _reset0 {
  34.     my $self = shift;
  35.     $self->{FROM} = undef;
  36.     $self->{TO} = [];
  37.     $self->{MSG} = undef;
  38.     $self->{faults} = 0;
  39. }
  40.  
  41.     
  42. sub _reset {
  43.     my $self = shift;
  44.     $self->_reset0;
  45.     $self->_put("250 buffahs ah cleah, suh!");
  46. }
  47.  
  48. # New instance.
  49. sub new {
  50.     my($this, $sock) = @_;
  51.     
  52.     my $class = ref($this) || $this;
  53.     my $self = {};
  54.     
  55.     bless($self, $class);
  56.     $self->_reset0;
  57.     $self->{SOCK} = $sock;
  58.  
  59.     croak("No client connection specified.") unless defined($self->{SOCK});
  60.     return $self;
  61. }
  62.  
  63. sub greet {
  64.     
  65.     $_[0]->_put("220 Debatable SMTP $VERSION Ready.");
  66. }
  67.  
  68. sub basta{
  69.     my $self = shift;
  70.     $self -> _put("421 closing transmission channel");
  71.         $self->{SOCK}->close;
  72.     1;
  73. }
  74.  
  75. # sub process {
  76. sub get_message {
  77.     my $self = shift;
  78.     my($cmd, @args);
  79.     
  80.     my $sock = $self->{SOCK};
  81.     $self->_reset0;
  82.     
  83.     while(<$sock>) {
  84.     print "$$ command: $_";
  85.     $$self{faults} > 15 and $self->basta and last;
  86.     # Clean up.
  87.     chomp;
  88.     s/^\s+//;
  89.     s/\s+$//;
  90.     unless(length $_){
  91.         ++$$self{faults};
  92.         $self->greet;
  93.         next;
  94.     };
  95.     ($cmd, @args) = split(/\s+/);
  96.     
  97.     $cmd =~ tr/a-z/A-Z/;
  98.     
  99.     if(!defined($_cmds{$cmd})) {
  100.         sleep ++$$self{faults};
  101.         $self->_put("500 sorry, I don't know how to $cmd");
  102.        next;
  103.     };
  104.     
  105.     # all commands return TRUE to indicate that
  106.     # we need to keep working to get the message.
  107.     &{$_cmds{$cmd}}($self, \@args) or 
  108.         return(defined($self->{MSG}));
  109.     }
  110.  
  111.     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.     return map { /([^<|;]+\@[^>|;&,\s]+)/ ? $1 : () } @_;
  119. };
  120.  
  121. sub okay {
  122.     my $self = shift;
  123.     $self -> _put("250 OK @_");
  124. }
  125.  
  126. sub fail {
  127.     my $self = shift;
  128.     $self -> _put("554 @_");
  129. }
  130.  
  131. sub too_long {
  132.     $_[0] -> _put("552 Too much mail data");
  133. };
  134.  
  135. sub _mail {
  136.     my $self = $_[0];
  137.     my @who = find_addresses(@{$_[1]});
  138.     my $who = shift @who;
  139.     if ($who){
  140.     $self->{FROM} = $who;
  141.     return $self->okay("Envelope sender set to <$who> ")
  142.     }else{
  143.     $self->{faults}++;
  144.     return $self-> _put("501 could not find name\@postoffice in <@{$_[1]}>")
  145.     };
  146. }
  147.  
  148. sub rcpt_syntax{
  149.     $_[0] -> _put("553 no user\@host addresses found in <@{$_[1]}>");
  150. }
  151.  
  152. sub _receipt {
  153.     my $self = $_[0];
  154.     my @recipients = find_addresses(@{$_[1]});
  155.     @recipients or return $self->rcpt_syntax($_[1]);
  156.     push @{ $self->{TO} }, @recipients;
  157.     $self->okay("sending to @{$self->{TO}}");
  158. }
  159.  
  160. sub _data {
  161.     my $self = shift;
  162.    
  163.     my @msg;
  164.     
  165.     if(!$self->{FROM}) {
  166.     $self-> _put("503 start with 'mail from: ...'");
  167.     $self->{faults}++;
  168.     return 1;
  169.     }
  170.     
  171.     if(!@{$self->{TO}}) {
  172.     $self->_put("503 specify recipients with 'rcpt to: ...'");
  173.     $self->{faults}++;
  174.     return 1;
  175.     }
  176.  
  177.     $self->_put("354 And what am I to tell them?");
  178.  
  179.     my $sock = $self->{SOCK};
  180.     
  181.     while(<$sock>) {
  182.     print "$$ data: $_";
  183.     if(/^\.\r*\n*$/) {
  184.         $self->{MSG} = join ('', @msg);
  185.         return 0; # please examine MSG
  186.     }
  187.     
  188.     # RFC 821 compliance.
  189.     s/^\.\./\./;
  190.     push @msg, $_;
  191.     }
  192.     
  193.     return 0; # socket died
  194. }
  195.  
  196. sub _noway {
  197.     shift->_put("252 Nice try.");
  198. }
  199.  
  200. sub _noop {
  201.     shift->_put("250 Whatever.");
  202. }
  203.  
  204. sub _help {
  205.     my $self = shift;
  206.     my $i = 0;
  207.     my $str = "214-Commands\r\n";
  208.     my $total = keys(%_cmds);
  209.     
  210.     foreach(sort(keys(%_cmds))) {
  211.     if(!($i++ % 5)) {
  212.         if(($total - $i) < 5) {
  213.         $str .= "\r\n214 ";
  214.         } else {
  215.         $str .= "\r\n214-";
  216.         }
  217.     } else {
  218.         $str .= ' ';
  219.     }
  220.     
  221.     $str .= $_;
  222.     }
  223.     
  224.     $self->_put($str);
  225. }
  226.  
  227. sub _quit {
  228.     my $self = shift;
  229.     
  230.     $self->_put("221 Ciao");
  231.     $self->{SOCK}->close;
  232.     return 0;
  233. }
  234.  
  235. sub _hello {
  236.     shift->okay( "Welcome" );
  237. }
  238.  
  239. 1;
  240. __END__
  241.  
  242. =head1 NAME
  243.  
  244. Net::SMTP::Server::Client2 - A better client for Net::SMTP::Server.
  245.  
  246. =head1 SYNOPSIS
  247.  
  248.         use Carp;
  249.         use Net::SMTP::Server;
  250.         use Net::SMTP::Server::Client2;
  251.  
  252.         my $server = new Net::SMTP::Server(localhost => 25) ||
  253.            croak("Unable to open server : $!\n");
  254.  
  255.         while($conn = $server->accept()) {
  256.  
  257.        fork and last;
  258.        $conn->close;
  259.         };
  260.       
  261.     my $count = 'aaa';
  262.         my $client = new Net::SMTP::Server::Client2($conn) ||
  263.                croak("Unable to handle client: $!\n");
  264.  
  265.     $client->greet; # this is new
  266.  
  267.         while($client->get_message){ # this is different
  268.  
  269.     if (length($client->{MSG}) > 1400000){
  270.             $client->too_long; # this is new
  271.     }else{
  272.  
  273.         if( $client->{MSG} =~ /viagra/i ){
  274.             $client->fail(" we need no viagra "); # this is new
  275.             next;
  276.         };
  277.  
  278.         $count++;
  279.         open MOUT, ">/tmp/tmpMOUT_${$}_$count" or die "open: $!";
  280.         print MOUT  join("\n",
  281.             $client->{FROM},
  282.             @{$client->{TO}},
  283.             '',
  284.             $client-{MSG}) or die "print: $!";
  285.         close MOUT or die "close: $!";
  286.         link 
  287.             "/tmp/tmpMOUT_${$}_$count",
  288.             "/tmp/MOUT_${$}_$count"
  289.              or die "link: $!";
  290.         unlink 
  291.             "/tmp/tmpMOUT_${$}_$count"
  292.              or die "unlink: $!";
  293.         $client->okay("message saved for relay"); # this is new
  294.          }}
  295.  
  296.  
  297.  
  298. =head1 DESCRIPTION
  299.  
  300. The Net::SMTP::Server::Client2 module
  301. is a patched Net::SMTP::Server::Client module.
  302.  
  303.  $client->get_message returns before delivering a response
  304. code to the client.  $client->okay(...) and $client->too_large()
  305. and $client->fail(...) return the appropriate codes, rather than
  306. assuming that all messages were 250.  "Is that 250 with you?"  
  307. $client->basta() will 421 and close, which is also an option after
  308. receiving a message you don't want to accept.
  309.  
  310.   $client->{faults} is the number of booboos the client made while
  311.    presenting the message, after 15 of them we 421 and close.
  312.  
  313. And, Client2 is no longer is an autoloader or an exporter because it
  314. doesn't export anything or autoload.
  315.  
  316. =head1 AUTHOR AND COPYRIGHT
  317.  
  318.   Net::SMTP::Server::Client is Copyright(C) 1999, 
  319.   MacGyver (aka Habeeb J. Dihu), who released
  320.   it under the AL and GPL, so it is okay to patch and re-release it,
  321.   even though he said "all reigths reserved."  He reserved all the
  322.   rights, then he released it.  Go figure.
  323.  
  324.   Client2,  released by me, in 2002,  contains changes that make
  325.   the interface more complex,  and not backwards-compatible.
  326.  
  327.   You may distribute this package under the terms of either the GNU
  328.   General Public License or the Artistic License, as specified in the
  329.   Perl README file. 
  330.  
  331.   David Nicol
  332.  
  333. =head1 SEE ALSO
  334.  
  335. Net::SMTP::Server, Net::SMTP::Server::Client
  336.  
  337. =cut
  338.