Author: msergeant
Date: Sat Jun 18 11:22:16 2005
New Revision: 436

Modified:
   branches/high_perf/lib/Qpsmtpd.pm
   branches/high_perf/lib/Qpsmtpd/Constants.pm
   branches/high_perf/lib/Qpsmtpd/PollServer.pm
   branches/high_perf/lib/Qpsmtpd/SMTP.pm
   branches/high_perf/plugins/dnsbl
Log:
Continuation support


Modified: branches/high_perf/lib/Qpsmtpd.pm
==============================================================================
--- branches/high_perf/lib/Qpsmtpd.pm   (original)
+++ branches/high_perf/lib/Qpsmtpd.pm   Sat Jun 18 11:22:16 2005
@@ -208,38 +208,20 @@ sub _load_plugins {
 
 sub run_hooks {
   my ($self, $hook) = (shift, shift);
+  if ($self->{_continuation}) {
+    die "Continuations in progress from previous hook (this is the $hook 
hook)";
+  }
   my $hooks = $self->{hooks};
   if ($hooks->{$hook}) {
     my @r;
-    for my $code (@{$hooks->{$hook}}) {
-      $self->log(LOGINFO, "running plugin ($hook):", $code->{name});
-      eval { (@r) = $code->{code}->($self, $self->transaction, @_); };
-      $@ and $self->log(LOGCRIT, "FATAL PLUGIN ERROR: ", $@) and next;
-
-      !defined $r[0]
-        and $self->log(LOGERROR, "plugin ".$code->{name}
-                       ."running the $hook hook returned undef!")
-          and next;
-
-      if ($self->transaction) {
-        my $tnotes = $self->transaction->notes( $code->{name} );
-        $tnotes->{"hook_$hook"}->{'return'} = $r[0]
-          if (!defined $tnotes || ref $tnotes eq "HASH");
-      } else {
-        my $cnotes = $self->connection->notes( $code->{name} );
-        $cnotes->{"hook_$hook"}->{'return'} = $r[0]
-          if (!defined $cnotes || ref $cnotes eq "HASH");
-      }
-
-      # should we have a hook for "OK" too?
-      if ($r[0] == DENY or $r[0] == DENYSOFT or
-          $r[0] == DENY_DISCONNECT or $r[0] == DENYSOFT_DISCONNECT)
-      {
-        $r[1] = "" if not defined $r[1];
-        $self->log(LOGDEBUG, "Plugin $code->{name}, hook $hook returned $r[0], 
$r[1]");
-        $self->run_hooks("deny", $code->{name}, $r[0], $r[1]) unless ($hook eq 
"deny");
+    my @local_hooks = @{$hooks->{$hook}};
+    while (@local_hooks) {
+      my $code = shift @local_hooks;
+      @r = $self->run_hook($hook, $code, @_);
+      next unless @r;
+      if ($r[0] == CONTINUATION) {
+        $self->{_continuation} = [$hook, [EMAIL PROTECTED], @local_hooks];
       }
-
       last unless $r[0] == DECLINED;
     }
     $r[0] = DECLINED if not defined $r[0];
@@ -248,6 +230,65 @@ sub run_hooks {
   return (0, '');
 }
 
+sub finish_continuation {
+  my ($self) = @_;
+  die "No continuation in progress" unless $self->{_continuation};
+  my $todo = $self->{_continuation};
+  $self->{_continuation} = undef;
+  my $hook = shift @$todo || die "No hook in the continuation";
+  my $args = shift @$todo || die "No hook args in the continuation";
+  my @r;
+  while (@$todo) {
+    my $code = shift @$todo;
+    @r = $self->run_hook($hook, $code, @$args);
+    if ($r[0] == CONTINUATION) {
+      $self->{_continuation} = [$hook, $args, @$todo];
+      return @r;
+    }
+    last unless $r[0] == DECLINED;
+  }
+  $r[0] = DECLINED if not defined $r[0];
+  my $responder = $hook . "_respond";
+  if (my $meth = $self->can($responder)) {
+    return $meth->($self, @r, @$args);
+  }
+  die "No ${hook}_respond method";
+}
+
+sub run_hook {
+  my ($self, $hook, $code, @args) = @_;
+  my @r;
+  $self->log(LOGINFO, "running plugin ($hook):", $code->{name});
+  eval { (@r) = $code->{code}->($self, $self->transaction, @args); };
+  $@ and $self->log(LOGCRIT, "FATAL PLUGIN ERROR: ", $@) and return;
+
+  !defined $r[0]
+    and $self->log(LOGERROR, "plugin ".$code->{name}
+                   ."running the $hook hook returned undef!")
+      and return;
+
+  if ($self->transaction) {
+    my $tnotes = $self->transaction->notes( $code->{name} );
+    $tnotes->{"hook_$hook"}->{'return'} = $r[0]
+      if (!defined $tnotes || ref $tnotes eq "HASH");
+  } else {
+    my $cnotes = $self->connection->notes( $code->{name} );
+    $cnotes->{"hook_$hook"}->{'return'} = $r[0]
+      if (!defined $cnotes || ref $cnotes eq "HASH");
+  }
+
+  # should we have a hook for "OK" too?
+  if ($r[0] == DENY or $r[0] == DENYSOFT or
+      $r[0] == DENY_DISCONNECT or $r[0] == DENYSOFT_DISCONNECT)
+  {
+    $r[1] = "" if not defined $r[1];
+    $self->log(LOGDEBUG, "Plugin $code->{name}, hook $hook returned $r[0], 
$r[1]");
+    $self->run_hooks("deny", $code->{name}, $r[0], $r[1]) unless ($hook eq 
"deny");
+  }
+  
+  return @r;
+}
+
 sub _register_hook {
   my $self = shift;
   my ($hook, $code, $unshift) = @_;

Modified: branches/high_perf/lib/Qpsmtpd/Constants.pm
==============================================================================
--- branches/high_perf/lib/Qpsmtpd/Constants.pm (original)
+++ branches/high_perf/lib/Qpsmtpd/Constants.pm Sat Jun 18 11:22:16 2005
@@ -3,7 +3,7 @@ use strict;
 require Exporter;
 
 my (@common) = qw(OK DECLINED DONE DENY DENYSOFT DENYHARD
-                  DENY_DISCONNECT DENYSOFT_DISCONNECT
+                  DENY_DISCONNECT DENYSOFT_DISCONNECT CONTINUATION
                  );
 my (@loglevels) = qw(LOGDEBUG LOGINFO LOGNOTICE LOGWARN LOGERROR LOGCRIT 
LOGALERT LOGEMERG LOGRADAR);
 
@@ -11,14 +11,15 @@ use vars qw($VERSION @ISA @EXPORT);
 @ISA    = qw(Exporter);
 @EXPORT = (@common, @loglevels);
 
-use constant OK       => 900;
-use constant DENY     => 901;   # 550
-use constant DENYSOFT => 902;   # 450
-use constant DENYHARD => 903;   # 550 + disconnect  (deprecated in 0.29)
-use constant DENY_DISCONNECT     => 903; # 550 + disconnect
-use constant DENYSOFT_DISCONNECT => 904; # 450 + disconnect
-use constant DECLINED => 909;
-use constant DONE     => 910;
+use constant OK                     => 900;
+use constant DENY                   => 901;   # 550
+use constant DENYSOFT               => 902;   # 450
+use constant DENYHARD               => 903;   # 550 + disconnect  (deprecated 
in 0.29)
+use constant DENY_DISCONNECT        => 903; # 550 + disconnect
+use constant DENYSOFT_DISCONNECT    => 904; # 450 + disconnect
+use constant DECLINED               => 909;
+use constant DONE                   => 910;
+use constant CONTINUATION           => 911;
 
 
 # log levels

Modified: branches/high_perf/lib/Qpsmtpd/PollServer.pm
==============================================================================
--- branches/high_perf/lib/Qpsmtpd/PollServer.pm        (original)
+++ branches/high_perf/lib/Qpsmtpd/PollServer.pm        Sat Jun 18 11:22:16 2005
@@ -21,6 +21,7 @@ use fields qw(
     _transaction
     _test_mode
     _extras
+    _continuation
 );
 use Qpsmtpd::Constants;
 use Qpsmtpd::Auth;
@@ -95,6 +96,13 @@ sub fault {
     return;
 }
 
+sub log {
+    my ($self, $trace, @log) = @_;
+    my $fd = $self->{fd};
+    $fd ||= '?';
+    $self->SUPER::log($trace, "fd:$fd", @log);
+}
+
 sub process_line {
     my $self = shift;
     my $line = shift || return;
@@ -164,17 +172,8 @@ sub process_cmd {
     else {
         # No such method - i.e. unrecognized command
         my ($rc, $msg) = $self->run_hooks("unrecognized_command", $cmd);
-        if ($rc == DENY) {
-            $self->respond(521, $msg);
-            $self->disconnect;
-            return;
-        }
-        elsif ($rc == DONE) {
-            return; # TODO - this isn't right.
-        }
-        else {
-            return $self->respond(500, "Unrecognized command");
-        }
+        return $self->unrecognized_command_respond unless $rc == CONTINUATION;
+        return 1;
     }
 }
 
@@ -201,29 +200,20 @@ sub start_conversation {
     );
     
     my ($rc, $msg) = $self->run_hooks("connect");
-    if ($rc == DENY) {
-        $self->respond(550, ($msg || 'Connection from you denied, bye bye.'));
-        return $rc;
-    }
-    elsif ($rc == DENYSOFT) {
-        $self->respond(450, ($msg || 'Connection from you temporarily denied, 
bye bye.'));
-        return $rc;
-    }
-    elsif ($rc == DONE) {
-        $self->respond(220, $msg);
-        return $rc;
-    }
-    else {
-        $self->respond(220, $self->config('me') ." ESMTP qpsmtpd "
-                       . $self->version ." ready; send us your mail, but not 
your spam.");
-        return DONE;
-    }
+    return $self->connect_respond($rc, $msg) unless $rc == CONTINUATION;
+    return DONE;
 }
 
 sub data {
     my $self = shift;
     
     my ($rc, $msg) = $self->run_hooks("data");
+    return $self->data_respond($rc, $msg) unless $rc == CONTINUATION;
+    return 1;
+}
+
+sub data_respond {
+    my ($self, $rc, $msg) = @_;
     if ($rc == DONE) {
         return;
     }
@@ -350,22 +340,8 @@ sub end_of_data {
     return $self->respond(552, "Message too big!") if $self->{max_size} and 
$self->{data_size} > $self->{max_size};
     
     my ($rc, $msg) = $self->run_hooks("data_post");
-    if ($rc == DONE) {
-        return;
-    }
-    elsif ($rc == DENY) {
-        $self->respond(552, $msg || "Message denied");
-    }
-    elsif ($rc == DENYSOFT) {
-        $self->respond(452, $msg || "Message denied temporarily");
-    } 
-    else {
-        $self->queue($self->transaction);    
-    }
-    
-    # DATA is always the end of a "transaction"
-    $self->reset_transaction;
-    return;
+    return $self->data_post_respond($rc, $msg) unless $rc == CONTINUATION;
+    return 1;
 }
 
 1;

Modified: branches/high_perf/lib/Qpsmtpd/SMTP.pm
==============================================================================
--- branches/high_perf/lib/Qpsmtpd/SMTP.pm      (original)
+++ branches/high_perf/lib/Qpsmtpd/SMTP.pm      Sat Jun 18 11:22:16 2005
@@ -54,18 +54,9 @@ sub dispatch {
   #  if $state{dnsbl_blocked} and ($cmd eq "rcpt");
 
   if ($cmd !~ /^(\w{1,12})$/ or !exists $self->{_commands}->{$1}) {
-    my ($rc, $msg) = $self->run_hooks("unrecognized_command", $cmd);
-    if ($rc == DENY) {
-      $self->respond(521, $msg);
-      $self->disconnect;
-    }
-    elsif ($rc == DONE) {
-      1;
-    }
-    else {
-      $self->respond(500, "Unrecognized command");
-    }
-    return 1
+    my ($rc, $msg) = $self->run_hooks("unrecognized_command", $cmd, @_);
+    return $self->unrecognized_command_respond($rc, $msg, @_) unless $rc == 
CONTINUATION;
+    return 1;
   }
   $cmd = $1;
 
@@ -79,6 +70,17 @@ sub dispatch {
   return;
 }
 
+sub unrecognized_command_respond {
+    my ($self, $rc, $msg) = @_;
+    if ($rc == DENY) {
+        $self->respond(521, $msg);
+        $self->disconnect;
+    }
+    elsif ($rc != DONE) {
+        $self->respond(500, "Unrecognized command");
+    }
+}
+
 sub fault {
   my $self = shift;
   my ($msg) = shift || "program fault - command not performed";
@@ -92,6 +94,12 @@ sub start_conversation {
     # this should maybe be called something else than "connect", see
     # lib/Qpsmtpd/TcpServer.pm for more confusion.
     my ($rc, $msg) = $self->run_hooks("connect");
+    return $self->connect_respond($rc, $msg) unless $rc == CONTINUATION;
+    return 1;
+}
+
+sub connect_respond {
+    my ($self, $rc, $msg) = @_;
     if ($rc == DENY) {
       $self->respond(550, ($msg || 'Connection from you denied, bye bye.'));
       return $rc;
@@ -118,17 +126,25 @@ sub helo {
   return $self->respond (503, "but you already said HELO ...") if $conn->hello;
 
   my ($rc, $msg) = $self->run_hooks("helo", $hello_host, @stuff);
-  if ($rc == DONE) {
-    # do nothing
-  } elsif ($rc == DENY) {
+  return $self->helo_respond($rc, $msg, $hello_host, @stuff) unless $rc == 
CONTINUATION;
+  return 1;
+}
+
+sub helo_respond {
+  my ($self, $rc, $msg, $hello_host) = @_;
+  if ($rc == DENY) {
     $self->respond(550, $msg);
-  } elsif ($rc == DENYSOFT) {
+  }
+  elsif ($rc == DENYSOFT) {
     $self->respond(450, $msg);
-  } else {
+  }
+  elsif ($rc != DONE) {
+    my $conn = $self->connection;
     $conn->hello("helo");
     $conn->hello_host($hello_host);
     $self->transaction;
-    $self->respond(250, $self->config('me') ." Hi " . $conn->remote_info . " 
[" . $conn->remote_ip ."]; I am so happy to meet you.");
+    $self->respond(250, $self->config('me') ." Hi " . $conn->remote_info . 
+                        " [" . $conn->remote_ip ."]; I am so happy to meet 
you.");
   }
 }
 
@@ -140,13 +156,20 @@ sub ehlo {
   return $self->respond (503, "but you already said HELO ...") if $conn->hello;
 
   my ($rc, $msg) = $self->run_hooks("ehlo", $hello_host, @stuff);
-  if ($rc == DONE) {
-    # do nothing
-  } elsif ($rc == DENY) {
+  return $self->ehlo_respond($rc, $msg, $hello_host, @stuff) unless $rc == 
CONTINUATION;
+  return 1;
+}
+
+sub ehlo_respond {
+  my ($self, $rc, $msg, $hello_host) = @_;
+  if ($rc == DENY) {
     $self->respond(550, $msg);
-  } elsif ($rc == DENYSOFT) {
+  }
+  elsif ($rc == DENYSOFT) {
     $self->respond(450, $msg);
-  } else {
+  }
+  elsif ($rc != DONE) {
+    my $conn = $self->connection;
     $conn->hello("ehlo");
     $conn->hello_host($hello_host);
     $self->transaction;
@@ -211,57 +234,62 @@ sub mail {
   unless ($self->connection->hello) {
     return $self->respond(503, "please say hello first ...");
   }
-  else {
-    my $from_parameter = join " ", @_;
-    $self->log(LOGINFO, "full from_parameter: $from_parameter");
+  
+  my $from_parameter = join " ", @_;
+  $self->log(LOGINFO, "full from_parameter: $from_parameter");
 
-    my ($from) = ($from_parameter =~ m/^from:\s*(<[^>]*>)/i)[0];
+  my ($from) = ($from_parameter =~ m/^from:\s*(<[^>]*>)/i)[0];
 
-    # support addresses without <> ... maybe we shouldn't?
-    ($from) = "<" . ($from_parameter =~ m/^from:\s*(\S+)/i)[0] . ">"
-      unless $from;
-
-    $self->log(LOGWARN, "from email address : [$from]");
-
-    if ($from eq "<>" or $from =~ m/\[undefined\]/ or $from eq "<[EMAIL 
PROTECTED]>") {
-      $from = Qpsmtpd::Address->new("<>");
-    } 
-    else {
-      $from = (Qpsmtpd::Address->parse($from))[0];
-    }
-    return $self->respond(501, "could not parse your mail from command") 
unless $from;
+  # support addresses without <> ... maybe we shouldn't?
+  ($from) = "<" . ($from_parameter =~ m/^from:\s*(\S+)/i)[0] . ">"
+    unless $from;
 
-    my ($rc, $msg) = $self->run_hooks("mail", $from);
-    if ($rc == DONE) {
-      return 1;
-    }
-    elsif ($rc == DENY) {
-      $msg ||= $from->format . ', denied';
-      $self->log(LOGINFO, "deny mail from " . $from->format . " ($msg)");
-      $self->respond(550, $msg);
-    }
-    elsif ($rc == DENYSOFT) {
-      $msg ||= $from->format . ', temporarily denied';
-      $self->log(LOGINFO, "denysoft mail from " . $from->format . " ($msg)");
-      $self->respond(450, $msg);
-    }
-    elsif ($rc == DENY_DISCONNECT) {
-      $msg ||= $from->format . ', denied';
-      $self->log(LOGINFO, "deny mail from " . $from->format . " ($msg)");
-      $self->respond(550, $msg);
-      $self->disconnect;
-    }
-    elsif ($rc == DENYSOFT_DISCONNECT) {
-      $msg ||= $from->format . ', temporarily denied';
-      $self->log(LOGINFO, "denysoft mail from " . $from->format . " ($msg)");
-      $self->respond(450, $msg);
-      $self->disconnect;
-    }
-    else { # includes OK
-      $self->log(LOGINFO, "getting mail from ".$from->format);
-      $self->respond(250, $from->format . ", sender OK - how exciting to get 
mail from you!");
-      $self->transaction->sender($from);
-    }
+  $self->log(LOGWARN, "from email address : [$from]");
+
+  if ($from eq "<>" or $from =~ m/\[undefined\]/ or $from eq "<[EMAIL 
PROTECTED]>") {
+    $from = Qpsmtpd::Address->new("<>");
+  } 
+  else {
+    $from = (Qpsmtpd::Address->parse($from))[0];
+  }
+  return $self->respond(501, "could not parse your mail from command") unless 
$from;
+
+  my ($rc, $msg) = $self->run_hooks("mail", $from);
+  return $self->mail_respond($rc, $msg, $from) unless $rc == CONTINUATION;
+  return 1;
+}
+
+sub mail_respond {
+  my ($self, $rc, $msg, $from) = @_;
+  if ($rc == DONE) {
+    return 1;
+  }
+  elsif ($rc == DENY) {
+    $msg ||= $from->format . ', denied';
+    $self->log(LOGINFO, "deny mail from " . $from->format . " ($msg)");
+    $self->respond(550, $msg);
+  }
+  elsif ($rc == DENYSOFT) {
+    $msg ||= $from->format . ', temporarily denied';
+    $self->log(LOGINFO, "denysoft mail from " . $from->format . " ($msg)");
+    $self->respond(450, $msg);
+  }
+  elsif ($rc == DENY_DISCONNECT) {
+    $msg ||= $from->format . ', denied';
+    $self->log(LOGINFO, "deny mail from " . $from->format . " ($msg)");
+    $self->respond(550, $msg);
+    $self->disconnect;
+  }
+  elsif ($rc == DENYSOFT_DISCONNECT) {
+    $msg ||= $from->format . ', temporarily denied';
+    $self->log(LOGINFO, "denysoft mail from " . $from->format . " ($msg)");
+    $self->respond(450, $msg);
+    $self->disconnect;
+  }
+  else { # includes OK
+    $self->log(LOGINFO, "getting mail from ".$from->format);
+    $self->respond(250, $from->format . ", sender OK - how exciting to get 
mail from you!");
+    $self->transaction->sender($from);
   }
 }
 
@@ -278,6 +306,12 @@ sub rcpt {
   return $self->respond(501, "could not parse recipient") unless $rcpt;
 
   my ($rc, $msg) = $self->run_hooks("rcpt", $rcpt);
+  return $self->rcpt_respond($rc, $msg, $rcpt) unless $rc == CONTINUATION;
+  return 1;
+}
+
+sub rcpt_respond {
+  my ($self, $rc, $msg, $rcpt) = @_;
   if ($rc == DONE) {
     return 1;
   }
@@ -312,7 +346,6 @@ sub rcpt {
 }
 
 
-
 sub help {
   my $self = shift;
   $self->respond(214, 
@@ -334,6 +367,12 @@ sub vrfy {
   # I also don't think it provides all the proper result codes.
 
   my ($rc, $msg) = $self->run_hooks("vrfy");
+  return $self->vrfy_respond($rc, $msg) unless $rc == CONTINUATION;
+  return 1;
+}
+
+sub vrfy_respond {
+  my ($self, $rc, $msg) = @_;
   if ($rc == DONE) {
     return 1;
   }
@@ -361,6 +400,12 @@ sub rset {
 sub quit {
   my $self = shift;
   my ($rc, $msg) = $self->run_hooks("quit");
+  return $self->quit_respond($rc, $msg) unless $rc == CONTINUATION;
+  return 1;
+}
+
+sub quit_respond {
+  my ($self, $rc, $msg) = @_;
   if ($rc != DONE) {
     $self->respond(221, $self->config('me') . " closing connection. Have a 
wonderful day.");
   }
@@ -373,9 +418,17 @@ sub disconnect {
   $self->reset_transaction;
 }
 
+sub disconnect_respond { }
+
 sub data {
   my $self = shift;
   my ($rc, $msg) = $self->run_hooks("data");
+  return $self->data_respond($rc, $msg) unless $rc == CONTINUATION;
+  return 1;
+}
+
+sub data_respond {
+  my ($self, $rc, $msg) = @_;
   if ($rc == DONE) {
     return 1;
   }
@@ -493,6 +546,11 @@ sub data {
   $self->respond(552, "Message too big!"),return 1 if $max_size and $size > 
$max_size;
 
   ($rc, $msg) = $self->run_hooks("data_post");
+  return $self->data_post_respond($rc, $msg) unless $rc == CONTINUATION;
+}
+
+sub data_post_respond {
+  my ($self, $rc, $msg) = @_;
   if ($rc == DONE) {
     return 1;
   }
@@ -508,7 +566,6 @@ sub data {
 
   # DATA is always the end of a "transaction"
   return $self->reset_transaction;
-
 }
 
 sub getline {
@@ -524,6 +581,12 @@ sub queue {
   my ($self, $transaction) = @_;
 
   my ($rc, $msg) = $self->run_hooks("queue");
+  return $self->queue_respond($rc, $msg) unless $rc == CONTINUATION;
+  return 1;
+}
+
+sub queue_respond {
+  my ($self, $rc, $msg) = @_;
   if ($rc == DONE) {
     return 1;
   }
@@ -539,8 +602,6 @@ sub queue {
   else {
     $self->respond(451, $msg || "Queuing declined or disabled; try again 
later" );
   }
-
-
 }
 
 

Modified: branches/high_perf/plugins/dnsbl
==============================================================================
--- branches/high_perf/plugins/dnsbl    (original)
+++ branches/high_perf/plugins/dnsbl    Sat Jun 18 11:22:16 2005
@@ -5,7 +5,7 @@ use Danga::DNS;
 sub register {
   my ($self) = @_;
   $self->register_hook("connect", "connect_handler");
-  $self->register_hook("rcpt", "rcpt_handler");
+  $self->register_hook("connect", "pickup_handler");
 }
 
 sub connect_handler {
@@ -34,12 +34,14 @@ sub connect_handler {
 
   my $reversed_ip = join(".", reverse(split(/\./, $remote_ip)));
 
+  $self->transaction->notes('pending_dns_queries', scalar(keys(%dnsbl_zones)));
+  my $qp = $self->qp;
   for my $dnsbl (keys %dnsbl_zones) {
     # fix to find A records, if the dnsbl_zones line has a second field 
20/1/04 ++msp
     if (defined($dnsbl_zones{$dnsbl})) {
       $self->log(LOGDEBUG, "Checking $reversed_ip.$dnsbl for A record in the 
background");
       Danga::DNS->new(
-        callback => sub { $self->process_a_result($dnsbl_zones{$dnsbl}, @_) },
+        callback => sub { process_a_result($qp, $dnsbl_zones{$dnsbl}, @_) },
         host => "$reversed_ip.$dnsbl",
         type => 'A',
         client => $self->qp->input_sock,
@@ -47,7 +49,7 @@ sub connect_handler {
     } else {
       $self->log(LOGDEBUG, "Checking $reversed_ip.$dnsbl for TXT record in the 
background");
       Danga::DNS->new(
-        callback => sub { $self->process_txt_result(@_) },
+        callback => sub { process_txt_result($qp, @_) },
         host => "$reversed_ip.$dnsbl",
         type => 'TXT',
         client => $self->qp->input_sock,
@@ -55,40 +57,48 @@ sub connect_handler {
     }
   }
 
-  return DECLINED;
+  return CONTINUATION;
 }
 
 sub process_a_result {
-    my $self = shift;
-    my ($template, $result, $query) = @_;
+    my ($qp, $template, $result, $query) = @_;
+    
+    my $pending = $qp->transaction->notes('pending_dns_queries');
+    $qp->transaction->notes('pending_dns_queries', --$pending);
     
     warn("Result for A $query: $result\n");
     if ($result !~ /^\d+\.\d+\.\d+\.\d+$/) {
         # NXDOMAIN or ERROR possibly...
+        $qp->finish_continuation unless $pending;
         return;
     }
     
-    my $ip = $self->connection->remote_ip;
+    my $conn = $qp->connection;
+    my $ip = $conn->remote_ip;
     $template =~ s/%IP%/$ip/g;
-    my $conn = $self->connection;
     $conn->notes('dnsbl', $template) unless $conn->notes('dnsbl');
+    $qp->finish_continuation unless $pending;
 }
 
 sub process_txt_result {
-    my $self = shift;
-    my ($result, $query) = @_;
+    my ($qp, $result, $query) = @_;
+    
+    my $pending = $qp->transaction->notes('pending_dns_queries');
+    $qp->transaction->notes('pending_dns_queries', --$pending);
     
     warn("Result for TXT $query: $result\n");
     if ($result !~ /[a-z]/) {
         # NXDOMAIN or ERROR probably...
+        $qp->finish_continuation unless $pending;
         return;
     }
     
-    my $conn = $self->connection;
+    my $conn = $qp->connection;
     $conn->notes('dnsbl', $result) unless $conn->notes('dnsbl');
+    $qp->finish_continuation unless $pending;
 }
 
-sub rcpt_handler {
+sub pickup_handler {
   my ($self, $transaction, $rcpt) = @_;
 
   # RBLSMTPD being non-empty means it contains the failure message to return

Reply via email to