Devin Carraway wrote:Patch is attached. Not very heavily tested yet.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.
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;
