Author: vetinari
Date: Mon Dec 10 00:49:08 2007
New Revision: 829
Modified:
trunk/docs/plugins.pod
Log:
plugins.pod update
* hook_help
* isa_plugin() example
* some white space at EOL removed
Modified: trunk/docs/plugins.pod
==============================================================================
--- trunk/docs/plugins.pod (original)
+++ trunk/docs/plugins.pod Mon Dec 10 00:49:08 2007
@@ -156,6 +156,9 @@
$self->SUPER::hook_rcpt($transaction, $recipient);
}
+See also chapter C<Changing return values> and
+F<contrib/vetinari/rcpt_ok_maxrelay> in SVN.
+
=head2 Config files
Most of the existing plugins fetch their configuration data from files in the
@@ -1092,6 +1095,32 @@
Example plugin is F<tls>.
+=head2 hook_help
+
+This hook triggers if a client sends the B<HELP> command, allowed return
+codes are:
+
+=over 4
+
+=item DONE
+
+Plugin gave the answer.
+
+=item DENY
+
+Will result in a syntax error, probably not what you want, better use
+ $self->qp->respond(502, "Not implemented.");
+ return DONE;
+
+=back
+
+Anything else will be send as help answer.
+
+Arguments are
+ my ($self, $transaction, @args) = @_;
+
+with C<@args> being the arguments from the client's command.
+
=head2 hook_vrfy
If the client sents the B<VRFY> command, this hook is called. Default is to
@@ -1167,7 +1196,7 @@
=pod
-...documentation will follow later
+See F<README.authentication> in the qpsmtpd base dir.
=head1 Writing your own plugins
@@ -1230,7 +1259,7 @@
Proto => 'tcp')
or $self->log(LOGERROR, "Failed to connect to "
."$self->{_qmqp_server}:"
- ."$self->{_qmqp_port}: $!"),
+ ."$self->{_qmqp_port}: $!"),
return(DECLINED);
$sock->autoflush(1);
@@ -1238,21 +1267,21 @@
=item *
-The client starts with a safe 8-bit text message. It encodes the message
+The client starts with a safe 8-bit text message. It encodes the message
as the byte string C<firstline\012secondline\012 ... \012lastline>. (The
last line is usually, but not necessarily, empty.) The client then encodes
-this byte string as a netstring. The client also encodes the envelope
+this byte string as a netstring. The client also encodes the envelope
sender address as a netstring, and encodes each envelope recipient address
as a netstring.
-The client concatenates all these netstrings, encodes the concatenation
-as a netstring, and sends the result.
+The client concatenates all these netstrings, encodes the concatenation
+as a netstring, and sends the result.
(from L<http://cr.yp.to/proto/qmqp.html>)
=back
-The first idea is to build the package we send, in the order described
+The first idea is to build the package we send, in the order described
in the paragraph above:
my $message = $transaction->header->as_string;
@@ -1267,7 +1296,7 @@
}
$message .= join "", netstring_encode(@rcpt);
print $sock netstring_encode($message)
- or do {
+ or do {
my $err = $!;
$self->_disconnect($sock);
return(DECLINED, "Failed to print to socket: $err");
@@ -1298,7 +1327,7 @@
We've got everything we need. Now build the netstrings for the full package
and the message.
-First the beginning of the netstring of the full package
+First the beginning of the netstring of the full package
# (+ 2: the ":" and "," of the message's netstring)
print $sock ($msglen + length($msglen) + 2 + length($addrs))
@@ -1373,23 +1402,23 @@
We're done. Now let's see what the remote qmqpd says...
-=over 4
+=over 4
=item *
(continued from L<http://cr.yp.to/proto/qmqp.html>:)
-The server's response is a nonempty string of 8-bit bytes, encoded as a
+The server's response is a nonempty string of 8-bit bytes, encoded as a
netstring.
-The first byte of the string is either K, Z, or D. K means that the
-message has been accepted for delivery to all envelope recipients. This
-is morally equivalent to the 250 response to DATA in SMTP; it is subject
-to the reliability requirements of RFC 1123, section 5.3.3. Z means
-temporary failure; the client should try again later. D means permanent
+The first byte of the string is either K, Z, or D. K means that the
+message has been accepted for delivery to all envelope recipients. This
+is morally equivalent to the 250 response to DATA in SMTP; it is subject
+to the reliability requirements of RFC 1123, section 5.3.3. Z means
+temporary failure; the client should try again later. D means permanent
failure.
-Note that there is only one response for the entire message; the server
+Note that there is only one response for the entire message; the server
cannot accept some recipients while rejecting others.
=back
@@ -1440,6 +1469,52 @@
return(DECLINED);
}
+
+=head2 Changing return values
+
+This is an example how to use the C<isa_plugin> method.
+
+The B<rcpt_ok_maxrelay> plugin wraps the B<rcpt_ok> plugin. The B<rcpt_ok>
+plugin checks the F<rcpthosts> and F<morercpthosts> config files for
+domains, which we accept mail for. If not found it tells the
+client that relaying is not allowed. Clients which are marked as
+C<relay clients> are excluded from this rule. This plugin counts the
+number of unsuccessfull relaying attempts and drops the connection if
+too many were made.
+
+The optional parameter I<MAX_RELAY_ATTEMPTS> configures this plugin to drop
+the connection after I<MAX_RELAY_ATTEMPTS> unsuccessful relaying attempts.
+Set to C<0> to disable, default is C<5>.
+
+Note: Do not load both (B<rcpt_ok> and B<rcpt_ok_maxrelay>). This plugin
+should be configured to run I<last>, like B<rcpt_ok>.
+
+ use Qpsmtpd::DSN;
+
+ sub init {
+ my ($self, $qp, @args) = @_;
+ die "too many arguments"
+ if @args > 1;
+ $self->{_count_relay_max} = defined $args[0] ? $args[0] : 5;
+ $self->isa_plugin("rcpt_ok");
+ }
+
+ sub hook_rcpt {
+ my ($self, $transaction, $recipient) = @_;
+ my ($rc, @msg) = $self->SUPER::hook_rcpt($transaction, $recipient);
+
+ return ($rc, @msg)
+ unless (($rc == DENY) and $self->{_count_relay_max});
+
+ my $count =
+ ($self->qp->connection->notes('count_relay_attempts') || 0) + 1;
+ $self->qp->connection->notes('count_relay_attempts', $count);
+
+ return ($rc, @msg) unless ($count > $self->{_count_relay_max});
+ return Qpsmtpd::DSN->relaying_denied(DENY_DISCONNECT,
+ "Too many relaying attempts");
+ }
+
=head2 TBC... :-)
=cut