diff -urNp qpsmtpd.orig/config.sample/plugins qpsmtpd/config.sample/plugins
--- qpsmtpd.orig/config.sample/plugins  2004-09-22 11:01:16.000000000 -0500
+++ qpsmtpd/config.sample/plugins       2004-11-28 19:36:19.000000000 -0600
@@ -8,6 +8,9 @@
 
 quit_fortune
 
+#logging/syslog unix
+logging/stdout 5
+
 check_earlytalker
 count_unrecognized_commands 4
 check_relay
diff -urNp qpsmtpd.orig/lib/Qpsmtpd/Auth.pm qpsmtpd/lib/Qpsmtpd/Auth.pm
--- qpsmtpd.orig/lib/Qpsmtpd/Auth.pm    2004-09-23 11:14:56.000000000 -0500
+++ qpsmtpd/lib/Qpsmtpd/Auth.pm 2004-11-28 11:22:04.000000000 -0600
@@ -260,7 +260,7 @@ sub SASL {
     
           $session->respond(334, e64("Username:"));
           $user = decode_base64(<>);
-          #warn("Debug: User: '$user'");
+          #$session->log( LOGDEBUG, ("Debug: User: '$user'"));
           if ($user eq '*') {
             $session->respond(501, "Authentification canceled");
             return DECLINED;
@@ -269,7 +269,7 @@ sub SASL {
           $session->respond(334, e64("Password:"));
           $passClear = <>;
           $passClear = decode_base64($passClear);
-          #warn("Debug: Pass: '$pass'");
+          #$session->log( LOGDEBUG, ("Debug: Pass: '$pass'"));
           if ($passClear eq '*') {
             $session->respond(501, "Authentification canceled");
             return DECLINED;
diff -urNp qpsmtpd.orig/lib/Qpsmtpd/Plugin.pm qpsmtpd/lib/Qpsmtpd/Plugin.pm
--- qpsmtpd.orig/lib/Qpsmtpd/Plugin.pm  2004-11-18 13:47:10.000000000 -0600
+++ qpsmtpd/lib/Qpsmtpd/Plugin.pm       2004-11-28 17:26:05.000000000 -0600
@@ -5,7 +5,7 @@ our %hooks = map { $_ => 1 } qw(
     config  queue  data  data_post  quit  rcpt  mail  ehlo  helo
     auth auth-plain auth-login auth-cram-md5
     connect  reset_transaction  unrecognized_command  disconnect
-    deny
+    deny logging
 );
 
 sub new {
diff -urNp qpsmtpd.orig/lib/Qpsmtpd/SMTP.pm qpsmtpd/lib/Qpsmtpd/SMTP.pm
--- qpsmtpd.orig/lib/Qpsmtpd/SMTP.pm    2004-11-27 00:38:32.000000000 -0600
+++ qpsmtpd/lib/Qpsmtpd/SMTP.pm 2004-11-28 11:23:38.000000000 -0600
@@ -21,7 +21,7 @@ use Net::DNS;
 # this is only good for forkserver
 # can't set these here, cause forkserver resets them
 #$SIG{ALRM} = sub { respond(421, "Game over pal, game over. You got a timeout; I just can't wait that long..."); exit };
-#$SIG{ALRM} = sub { warn "Connection Timed Out\n"; exit; };
+#$SIG{ALRM} = sub { $self->log(LOGERROR, "Connection Timed Out"); exit; };
 
 sub new {
   my $proto = shift;
diff -urNp qpsmtpd.orig/lib/Qpsmtpd/SelectServer.pm qpsmtpd/lib/Qpsmtpd/SelectServer.pm
--- qpsmtpd.orig/lib/Qpsmtpd/SelectServer.pm    2004-03-05 06:46:23.000000000 -0600
+++ qpsmtpd/lib/Qpsmtpd/SelectServer.pm 2004-11-28 16:29:17.000000000 -0600
@@ -8,6 +8,7 @@ use Socket qw(CRLF);
 use Fcntl;
 use Tie::RefHash;
 use Net::DNS;
+use Sys::Syslog qw(:DEFAULT setlogsock);
 
 @ISA = qw(Qpsmtpd::SMTP);
 use strict;
@@ -27,13 +28,18 @@ our $QUIT = 0;
 
 $SIG{INT} = $SIG{TERM} = sub { $QUIT++ };
 
-sub log {
-  my ($self, $trace, @log) = @_;
-  my $level = Qpsmtpd::TRACE_LEVEL();
-  $level = $self->init_logger unless defined $level;
-  warn join(" ", fileno($self->client), @log), "\n"
-    if $trace <= $level;
-}
+#sub log {
+#  my ($self, $trace, @log) = @_;
+#  my $level = Qpsmtpd::TRACE_LEVEL();
+#  $level = $self->init_logger unless defined $level;
+#  my $msg = join(" ", $$, @log);
+#  if ($level eq 'syslog') {
+#      syslog((($trace - 1 < 0) ? 0 : $trace -1), $msg);
+#  } else {
+#      warn $msg, "\n"
+#        if $trace <= $level;
+#  }
+#}
 
 sub main {
     my $class = shift;
@@ -135,7 +141,7 @@ sub main {
             
             my $rv = $client->send($outbuffer{$client}, 0);
             unless (defined($rv)) {
-                warn("I was told to write, but I can't: $!\n");
+                $qp->log(LOGERROR, ("I was told to write, but I can't: $!"));
                 next;
             }
             if ($rv == length($outbuffer{$client}) ||
diff -urNp qpsmtpd.orig/lib/Qpsmtpd.pm qpsmtpd/lib/Qpsmtpd.pm
--- qpsmtpd.orig/lib/Qpsmtpd.pm 2004-11-27 00:46:21.000000000 -0600
+++ qpsmtpd/lib/Qpsmtpd.pm      2004-11-28 18:55:45.000000000 -0600
@@ -4,34 +4,21 @@ use vars qw($VERSION $LogLevel);
 
 use Sys::Hostname;
 use Qpsmtpd::Constants;
+use Sys::Syslog qw(:DEFAULT setlogsock);
 
 $VERSION = "0.28";
-sub TRACE_LEVEL { $LogLevel }
 
 sub version { $VERSION };
 
-sub init_logger {
-    my $self = shift;
-    # Get the loglevel - we localise loglevel to zero while we do this
-    my $loglevel = do {
-        local $LogLevel = 0;
-        $self->config("loglevel");
-    };
-    if (defined($loglevel) and $loglevel =~ /^\d+$/) {
-        $LogLevel = $loglevel;
-    }
-    else {
-        $LogLevel = LOGWARN; # Default if no loglevel file found.
-    }
-    return $LogLevel;
-}
+my $inlog = 0;
 
 sub log {
   my ($self, $trace, @log) = @_;
-  my $level = TRACE_LEVEL();
-  $level = $self->init_logger unless defined $level;
-  warn join(" ", $$, @log), "\n"
-    if $trace <= $level;
+  return
+    if $inlog;
+  $inlog = 1;
+  $self->run_hooks('logging', $trace, @log);
+  $inlog = 0;
 }
 
 #
@@ -110,7 +97,7 @@ sub get_qmail_config {
 sub _config_from_file {
   my ($self, $configfile, $config) = @_;
   return unless -e $configfile;
-  open CF, "<$configfile" or warn "$$ could not open configfile $configfile: $!" and return;
+  open CF, "<$configfile" or $self->log(LOGERROR, "$$ could not open configfile $configfile: $!") and return;
   my @config = <CF>;
   chomp @config;
   @config = grep { length($_) and $_ !~ m/^\s*#/ and $_ =~ m/\S/} @config;
@@ -215,6 +202,9 @@ sub run_hooks {
                        ."running the $hook hook returned undef!")
           and next;
 
+      next
+       if $hook eq 'logging';
+
       if ($self->transaction) {
         my $tnotes = $self->transaction->notes( $code->{name} );
         $tnotes->{"hook_$hook"}->{'return'} = $r[0]
diff -urNp qpsmtpd.orig/plugins/check_badmailfrom qpsmtpd/plugins/check_badmailfrom
--- qpsmtpd.orig/plugins/check_badmailfrom      2004-11-27 12:40:54.000000000 -0600
+++ qpsmtpd/plugins/check_badmailfrom   2004-11-28 11:31:05.000000000 -0600
@@ -42,7 +42,7 @@ sub mail_handler {
     $bad =~ s/^\s*(\S+).*/$1/;
     next unless $bad;
     $bad = lc $bad;
-    warn "Bad badmailfrom config: No \@ sign in $bad\n" and next unless $bad =~ m/\@/;
+    $self->log(LOGINFO, "Bad badmailfrom config: No \@ sign in $bad\n") and next unless $bad =~ m/\@/;
     $transaction->notes('badmailfrom', "Mail from $bad not accepted here")
       if ($bad eq $from) || (substr($bad,0,1) eq '@' && $bad eq "\@$host");
   }
diff -urNp qpsmtpd.orig/plugins/logging/stdout qpsmtpd/plugins/logging/stdout
--- qpsmtpd.orig/plugins/logging/stdout 1969-12-31 18:00:00.000000000 -0600
+++ qpsmtpd/plugins/logging/stdout      2004-11-28 19:34:57.000000000 -0600
@@ -0,0 +1,21 @@
+# this is a simple 'warn' plugin
+
+
+sub register {
+  my ($self, $qp, $loglevel) = @_;
+
+  $self->{_level} = LOGWARN;
+  if (defined($loglevel) and ($loglevel =~ /^\d+$/)) {
+      $self->{_level} = $loglevel;
+  }
+  warn $loglevel, "\n";
+  $self->register_hook('logging', 'wlog');
+}
+
+sub wlog {
+  my ($self, $qp, $level, @log) = @_;
+  my $msg = join(' ', $$, @log);
+  warn $msg, "\n"
+    if ($level <= $self->{_level});
+  return DECLINED;
+}
diff -urNp qpsmtpd.orig/plugins/logging/syslog qpsmtpd/plugins/logging/syslog
--- qpsmtpd.orig/plugins/logging/syslog 1969-12-31 18:00:00.000000000 -0600
+++ qpsmtpd/plugins/logging/syslog      2004-11-28 19:27:21.000000000 -0600
@@ -0,0 +1,27 @@
+# this is a simple syslog plugin
+
+use Sys::Syslog qw(:DEFAULT setlogsock);
+
+sub register {
+  my ($self, $qp, @args) = @_;
+  my $loglevel = join(' ', @args);
+
+  setlogsock('inet');
+  if ($loglevel =~ /stream (\W+)/) {
+    setlogsock('stream', $1);
+  }
+  if ($loglevel =~ /unix/) {
+    setlogsock('unix');
+  }
+  openlog('qpsmtpd', 'ndelay', 'mail');
+
+  $self->register_hook('logging', 'mylog');
+}
+
+sub mylog {
+  my ($self, $qp, $level, @log) = @_;
+  my $msg = join(' ', $$, @log);
+
+  syslog((($level - 1 < 0) ? 0 : $level -1), $msg);
+  return DECLINED;
+}
diff -urNp qpsmtpd.orig/plugins/require_resolvable_fromhost qpsmtpd/plugins/require_resolvable_fromhost
--- qpsmtpd.orig/plugins/require_resolvable_fromhost    2004-11-27 01:08:45.000000000 -0600
+++ qpsmtpd/plugins/require_resolvable_fromhost 2004-11-28 11:32:41.000000000 -0600
@@ -40,7 +40,7 @@ sub check_dns {
     }
   }
   else {
-    warn "$$ query for $host failed: ", $res->errorstring, "\n"
+    $self->log(LOGINFO, "$$ query for $host failed: ", $res->errorstring)
       unless $res->errorstring eq "NXDOMAIN";
   }
   return 0;
diff -urNp qpsmtpd.orig/plugins/spamassassin qpsmtpd/plugins/spamassassin
--- qpsmtpd.orig/plugins/spamassassin   2004-11-27 01:02:23.000000000 -0600
+++ qpsmtpd/plugins/spamassassin        2004-11-28 11:35:04.000000000 -0600
@@ -138,18 +138,18 @@ sub check_spam {
   # or CHECK or REPORT or SYMBOLS
 
   print SPAMD "X-Envelope-From: ", $transaction->sender->format, CRLF
-    or warn "Could not print to spamd: $!";
+    or $self->log(LOGERROR, "Could not print to spamd: $!");
 
   print SPAMD join CRLF, split /\n/, $transaction->header->as_string
-    or warn "Could not print to spamd: $!";
+    or $self->log(LOGERROR, "Could not print to spamd: $!");
 
   print SPAMD CRLF
-    or warn "Could not print to spamd: $!";
+    or $self->log(LOGERROR, "Could not print to spamd: $!");
 
   while (my $line = $transaction->body_getline) {
     chomp $line;
     print SPAMD $line, CRLF
-      or warn "Could not print to spamd: $!";
+      or $self->log(LOGERROR, "Could not print to spamd: $!");
   }
 
   print SPAMD CRLF;
diff -urNp qpsmtpd.orig/qpsmtpd-forkserver qpsmtpd/qpsmtpd-forkserver
--- qpsmtpd.orig/qpsmtpd-forkserver     2004-08-29 02:57:07.000000000 -0500
+++ qpsmtpd/qpsmtpd-forkserver  2004-11-28 19:15:32.000000000 -0600
@@ -18,7 +18,7 @@ $| = 1;
 
 # Configuration
 my $MAXCONN   = 15;                            # max simultaneous connections
-my $PORT      = 2525;                          # port number
+my $PORT      = 25;                            # port number
 my $LOCALADDR = '0.0.0.0';             # ip address to bind to
 my $USER      = 'smtpd';               # user to suid to
 my $MAXCONNIP = 5;              # max simultaneous connections from one IP
@@ -55,7 +55,7 @@ sub REAPER {
   $SIG{CHLD} = \&REAPER;
   while ( defined(my $chld = waitpid(-1, WNOHANG)) ){
     last unless $chld > 0;
-    warn("$$ cleaning up after $chld\n");
+    ::log(LOGINFO, "cleaning up after $chld\n");
     delete $childstatus{$chld};
   }
 }
@@ -77,7 +77,6 @@ my $server = IO::Socket::INET->new(Local
                                    Reuse     => 1,
                                    Listen    => SOMAXCONN )
   or die "Creating TCP socket $LOCALADDR:$PORT: $!\n";
-::log(LOGINFO,"Listening on port $PORT");
 
 # Drop priviledges
 my (undef, undef, $quid, $qgid) = getpwnam $USER or
@@ -89,15 +88,17 @@ POSIX::setuid($quid) or
       die "unable to change uid: $!\n";
 $> = $quid;
 
+# Load plugins here
+my $plugin_loader = Qpsmtpd::TcpServer->new();
+$plugin_loader->load_plugins;
+
+::log(LOGINFO,"Listening on port $PORT");
+
 ::log(LOGINFO, 'Running as user '.
        (getpwuid($>) || $>) .
        ', group '.
        (getgrgid($)) || $)));
 
-# Load plugins here
-my $plugin_loader = Qpsmtpd::TcpServer->new();
-$plugin_loader->load_plugins;
-
 
 while (1) {
   my $running = scalar keys %childstatus;
@@ -186,9 +187,8 @@ while (1) {
 }
 
 sub log {
-  my ($level,$message) = @_;
-  # $level not used yet.  this is reimplemented from elsewhere anyway
-  warn("$$ $message\n");
+  my ($level, @msg) = @_;
+  $plugin_loader->log($level, @msg);
 }
 
 __END__
