diff --git a/README.plugins b/README.plugins index 9f61225..972ad1a 100644 --- a/README.plugins +++ b/README.plugins @@ -84,6 +84,17 @@ Hook after receiving all data; just before the message is queued. All other codes and the message will be queued normally +=head2 queue + +Called on completion of the DATA command. + + DONE - skip further processing (plugin gave response code) + OK - Return success message + DENY - Return hard failure code + DENYSOFT - Return soft failure code + +Any other code will return a soft failure code. + =head2 connect @@ -93,6 +104,7 @@ Allowed return codes: DECLINED - Process the next plugin DONE - Stop processing plugins and don't give the default response + =head2 quit Called on the "quit" command. diff --git a/config.sample/plugins b/config.sample/plugins index bbaa5be..5ebabfb 100644 --- a/config.sample/plugins +++ b/config.sample/plugins @@ -8,7 +8,9 @@ check_badrcptto # this plugin needs to run after all other "rcpt" plugins check_relay - +# content filters klez_filter +spamassassin + +queue/qmail-queue -spamassassin \ No newline at end of file diff --git a/lib/Qpsmtpd/SMTP.pm b/lib/Qpsmtpd/SMTP.pm index fd657a5..387a253 100644 --- a/lib/Qpsmtpd/SMTP.pm +++ b/lib/Qpsmtpd/SMTP.pm @@ -300,6 +300,8 @@ sub data { # way a Received: line that is already in the header. $header->extract(\@header); + $header->add("X-SMTPD", "qpsmtpd/".$self->version.", http://develooper.com/code/qpsmtpd/"); + $buffer = ""; # FIXME - call plugins to work on just the header here; can @@ -360,55 +362,23 @@ sub data { sub queue { my ($self, $transaction) = @_; - # these bits inspired by Peter Samuels "qmail-queue wrapper" - pipe(MESSAGE_READER, MESSAGE_WRITER) or fault("Could not create message pipe"), exit; - pipe(ENVELOPE_READER, ENVELOPE_WRITER) or fault("Could not create envelope pipe"), exit; - - my $child = fork(); - - not defined $child and fault(451, "Could not fork"), exit; - - if ($child) { - # Parent - my $oldfh = select(MESSAGE_WRITER); $| = 1; - select(ENVELOPE_WRITER); $| = 1; - select($oldfh); - - close MESSAGE_READER or fault("close msg reader fault"),exit; - close ENVELOPE_READER or fault("close envelope reader fault"), exit; - - $transaction->header->add("X-SMTPD", "qpsmtpd/".$self->version.", http://develooper.com/code/qpsmtpd/"); - - $transaction->header->print(\*MESSAGE_WRITER); - $transaction->body_resetpos; - while (my $line = $transaction->body_getline) { - print MESSAGE_WRITER $line; - } - close MESSAGE_WRITER; - - my @rcpt = map { "T" . $_->address } $transaction->recipients; - my $from = "F".($transaction->sender->address|| "" ); - print ENVELOPE_WRITER "$from\0", join("\0",@rcpt), "\0\0" - or respond(451,"Could not print addresses to queue"),exit; - - close ENVELOPE_WRITER; - waitpid($child, 0); - my $exit_code = $? >> 8; - $exit_code and respond(451, "Unable to queue message ($exit_code)"), exit; - $self->respond(250, "Queued."); + my ($rc, $msg) = $self->run_hooks("queue"); + if ($rc == DONE) { + return 1; } - elsif (defined $child) { - # Child - close MESSAGE_WRITER or die "could not close message writer in parent"; - close ENVELOPE_WRITER or die "could not close envelope writer in parent"; - - open(STDIN, "<&MESSAGE_READER") or die "b1"; - open(STDOUT, "<&ENVELOPE_READER") or die "b2"; - - unless (exec '/var/qmail/bin/qmail-queue') { - die "should never be here!"; - } + elsif ($rc == OK) { + $self->respond(250, ($msg || 'Queued')); } + elsif ($rc == DENY) { + $self->respond(552, $msg || "Message denied"); + } + elsif ($rc == DENYSOFT) { + $self->respond(452, $msg || "Message denied temporarily"); + } + else { + $self->respond(451, $msg || "Queuing declined or disabled; try again later" ); + } + } diff --git a/plugins/queue/qmail-queue b/plugins/queue/qmail-queue new file mode 100644 index 0000000..8eaf3f1 --- /dev/null +++ b/plugins/queue/qmail-queue @@ -0,0 +1,57 @@ + +sub register { + my ($self, $qp) = @_; + $self->register_hook("queue", "queue_handler"); +} + +sub queue_handler { + my ($self, $transaction) = @_; + + # these bits inspired by Peter Samuels "qmail-queue wrapper" + pipe(MESSAGE_READER, MESSAGE_WRITER) or fault("Could not create message pipe"), exit; + pipe(ENVELOPE_READER, ENVELOPE_WRITER) or fault("Could not create envelope pipe"), exit; + + my $child = fork(); + + not defined $child and fault(451, "Could not fork"), exit; + + if ($child) { + # Parent + my $oldfh = select(MESSAGE_WRITER); $| = 1; + select(ENVELOPE_WRITER); $| = 1; + select($oldfh); + + close MESSAGE_READER or fault("close msg reader fault"),exit; + close ENVELOPE_READER or fault("close envelope reader fault"), exit; + + $transaction->header->print(\*MESSAGE_WRITER); + $transaction->body_resetpos; + while (my $line = $transaction->body_getline) { + print MESSAGE_WRITER $line; + } + close MESSAGE_WRITER; + + my @rcpt = map { "T" . $_->address } $transaction->recipients; + my $from = "F".($transaction->sender->address|| "" ); + print ENVELOPE_WRITER "$from\0", join("\0",@rcpt), "\0\0" + or return(DECLINED,"Could not print addresses to queue"); + + close ENVELOPE_WRITER; + waitpid($child, 0); + my $exit_code = $? >> 8; + $exit_code and return(DECLINED, "Unable to queue message ($exit_code)"); + return (OK, "Queued!"); + } + elsif (defined $child) { + # Child + close MESSAGE_WRITER or die "could not close message writer in parent"; + close ENVELOPE_WRITER or die "could not close envelope writer in parent"; + + open(STDIN, "<&MESSAGE_READER") or die "b1"; + open(STDOUT, "<&ENVELOPE_READER") or die "b2"; + + unless (exec '/var/qmail/bin/qmail-queue') { + return (DECLINED, "fatal error spawning qmail-queue"); + } + } +}