use ExtUtils::testlib; use Sendmail::Milter; use Socket; # # Each of these callbacks is actually called with a first argument # that is blessed into the pseudo-package Sendmail::Milter::Context. You can # use them like object methods of package Sendmail::Milter::Context. # # $ctx is a blessed reference of package Sendmail::Milter::Context to something # yucky, but the Mail Filter API routines are available as object methods # (sans the smfi_ prefix) from this # sub connect_callback { my $ctx = shift; # Some people think of this as $self my $hostname = shift; my $sockaddr_in = shift; my ($port, $iaddr); print "my_connect:\n"; print " + hostname: '$hostname'\n"; if (defined $sockaddr_in) { ($port, $iaddr) = sockaddr_in($sockaddr_in); print " + port: '$port'\n"; print " + iaddr: '" . inet_ntoa($iaddr) . "'\n"; } print " + callback completed.\n"; return SMFIS_CONTINUE; } sub helo_callback { my $ctx = shift; my $helohost = shift; print "my_helo:\n"; print " + helohost: '$helohost'\n"; print " + callback completed.\n"; return SMFIS_CONTINUE; } sub envfrom_callback { my $ctx = shift; my @args = @_; my $message = ""; print "my_envfrom:\n"; print " + args: '" . join(', ', @args) . "'\n"; $ctx->setpriv(\$message); print " + private data allocated.\n"; print " + callback completed.\n"; return SMFIS_CONTINUE; } sub envrcpt_callback { my $ctx = shift; my @args = @_; print "my_envrcpt:\n"; print " + args: '" . join(', ', @args) . "'\n"; print " + callback completed.\n"; return SMFIS_CONTINUE; } sub header_callback { my $ctx = shift; my $headerf = shift; my $headerv = shift; print "my_header:\n"; print " + field: '$headerf'\n"; print " + value: '$headerv'\n"; print " + callback completed.\n"; return SMFIS_CONTINUE; } sub eoh_callback { my $ctx = shift; print "my_eoh:\n"; print " + callback completed.\n"; return SMFIS_CONTINUE; } sub body_callback { my $ctx = shift; my $body_chunk = shift; my $len = shift; my $message_ref = $ctx->getpriv(); # Note: You don't need $len to have a good time. # But it's there if you like. print "my_body:\n"; print " + chunk len: $len\n"; ${$message_ref} .= $body_chunk; $ctx->setpriv($message_ref); print " + callback completed.\n"; return SMFIS_CONTINUE; } sub eom_callback { my $ctx = shift; my $message_ref = $ctx->getpriv(); my $chunk; print "my_eom:\n"; print " + adding line to message body...\n"; # Let's have some fun... # Note: This doesn't support messages with MIME data. # Pig-Latin, Babelfish, Double dutch, soo many possibilities! # But we're boring... ${$message_ref} .= "---> Append me to this message body!\r\n"; if (not $ctx->replacebody(${$message_ref})) { print " - write error!\n"; last; } $ctx->setpriv(undef); print " + private data cleared.\n"; print " + callback completed.\n"; return SMFIS_CONTINUE; } sub abort_callback { my $ctx = shift; print "my_abort:\n"; $ctx->setpriv(undef); print " + private data cleared.\n"; print " + callback completed.\n"; return SMFIS_CONTINUE; } sub close_callback { my $ctx = shift; print "my_close:\n"; print " + callback completed.\n"; return SMFIS_CONTINUE; } my %my_callbacks = ( 'connect' => \&connect_callback, 'helo' => \&helo_callback, 'envfrom' => \&envfrom_callback, 'envrcpt' => \&envrcpt_callback, 'header' => \&header_callback, 'eoh' => \&eoh_callback, 'body' => \&body_callback, 'eom' => \&eom_callback, 'abort' => \&abort_callback, 'close' => \&close_callback, ); BEGIN: { if (scalar(@ARGV) < 2) { print "Usage: perl $0 \n"; exit; } my $conn = Sendmail::Milter::auto_getconn($ARGV[0], $ARGV[1]); print "Found connection info for '$ARGV[0]': $conn\n"; if ($conn =~ /^local:(.+)$/) { my $unix_socket = $1; if (-e $unix_socket) { print "Attempting to unlink UNIX socket '$conn' ... "; if (unlink($unix_socket) == 0) { print "failed.\n"; exit; } print "successful.\n"; } } if (not Sendmail::Milter::auto_setconn($ARGV[0], $ARGV[1])) { print "Failed to detect connection information.\n"; exit; } # # The flags parameter is optional. SMFI_CURR_ACTS sets all of the # current version's filtering capabilities. # # %Sendmail::Milter::DEFAULT_CALLBACKS is provided for you in getting # up to speed quickly. I highly recommend creating a callback table # of your own with only the callbacks that you need. # if (not Sendmail::Milter::register($ARGV[0], \%my_callbacks, SMFI_CURR_ACTS)) { print "Failed to register callbacks for $ARGV[0].\n"; exit; } print "Starting Sendmail::Milter $Sendmail::Milter::VERSION engine.\n"; if (Sendmail::Milter::main()) { print "Successful exit from the Sendmail::Milter engine.\n"; } else { print "Unsuccessful exit from the Sendmail::Milter engine.\n"; } }