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

Reply via email to