Peter J. Holzer wrote:
Devin Carraway wrote:
  my $h = new Mail::Header;
  $h->read(\*RD);
  while (<RD>) {
      chomp;
    $self->log(10,"spamc returned body: [$_]");
  }
  close RD;
  waitpid $pid, 0;


This read loop would have to be interleaved with the write loop above, using select.

Patch is attached. Not very heavily tested yet.

hp

--- spamassassin.2003-04-06T12:44:23    Tue Apr  1 11:16:43 2003
+++ spamassassin        Sun Apr  6 13:59:00 2003
@@ -82,18 +82,56 @@
        );
   $pid or return DECLINED;
 
+  # spamc may start to return the result before it has received all its
+  # input. Therefore we must be prepared to read it back while we are
+  # still writing to it. 
+  #
+  # XXX - One should use sysread instead of <> when using select to
+  # avoid buffering issues. In this case, however, I think this is safe.
+
+  { my $oldfh = select(WR); $| = 1; select($oldfh); }
+
   print WR $transaction->header->as_string, "\n";
-  my $line;
-  print WR $line while $line = $transaction->body_getline;
+  my $h;
+  for (;;) {
+       my ($rin, $win, $ein);
+       my ($rout, $wout, $eout);
+       $rin = $win = $ein = '';
+       vec($rin, fileno(RD), 1) = 1;
+       vec($win, fileno(WR), 1) = 1;
+       $ein = $rin | $win;
+       my ($nfound,$timeleft) =
+           select($rout=$rin, $wout=$win, $eout=$ein, undef);
+       if (vec($wout, fileno(WR), 1)) {
+           my $line = $transaction->body_getline;
+           last unless ($line);
+           print WR $line;
+       }
+       if (vec($rout, fileno(RD), 1)) {
+           if ($h) {
+               # already read header, discard one line
+               my $dummy = <RD>;
+           } else {
+               # read whole header. This assumes that spamc will dump
+               # the whole header without waiting for input between. 
+               $h = new Mail::Header;
+               $h->read(\*RD);
+           }
+       }
+  }
+
+
   $transaction->body_resetpos;
   close WR;
 
-  my $h = new Mail::Header;
-  $h->read(\*RD);
-  while (<RD>) {
-       chomp;
-       $self->log(10,"spamc returned body: [$_]");
+  if (!$h) {
+       # read whole header.
+       $h = new Mail::Header;
+       $h->read(\*RD);
   }
+  # discard rest of lines
+  while (<RD>) { }
+  
   close RD;
   waitpid $pid, 0;
 

Reply via email to