Contents
======
This README
A patch with all the below features
An example milter, taken from sendmail source, nicknamed verbose-milter which basically is a noisy milter used to test this patch



New Features:
===========
Milter Rulesets:

You can configure rulesets to be evaluated by sendmail for different actions before sendmail sends the commands to the milter.

If the ruleset resolves to $#discard or $#error, then sendmail will not send the milter command. Certain failures will also trigger sendmail to shut down processing of the milter for this message/connection, such as a lack of recipients, no mail from, connect denied and so on so forth.

As a special case to this, resolving to $#abort will cause sendmail to cease milter processing for the duration of the message/connection, whichever it is in at the time.

If the ruleset resolves to $#ok or anything other than mentioned previously, the command is sent to the milter. Currently, changing the data sent to the milter is not available. That might change. Make it a habit to finish the ruleset with what you were given, if you are not resolving to any of the mailers.

Ruleset namespaces are initialized with the immediate argument data sent to the milter.

To turn this on compile sendmail with -D_FFR_MILTER_RWSETS
Additionaly, if you wish to be able to define multiple rulesets for each relevant milter command, compile with -D_FFR_MILTER_RWSETS_MULTI

You must then add this line to your sendmail.mc
define(`confMILTER_RWSETS', `1')dnl

You may then add an extra portion to your milter definition, seperated with a comma from the others in this fashion:

R=C:MConnectRS;E:HeloRS;M:MFromRS;R:MRcptRS;H:MHeaderRS

Ensure that -D_FFR_MILTER_RWSETS is used on the m4 line which rebuilds your cf from mc file.

(The values for the commands 'happen' to be synonymous with the relevant commands in include/libmilter/mfdef.h)

=============
Milter Rcpt Error:
=============

Previously Sendmail sent to the milter ALL rcpt commands, even when they were already deemed undeliverable. There was no mechanism for the milter to know what sendmail had decided about the milter. 

Now Sendmail will only send Recipients to the milter if they are deliverable. 

To receive undeliverable and check_rcpt rejected recipients, compile sendmail with 
-D_FFR_MILTER_RCPT_ERROR
This is on by default,

To receive even more rejected recipients for miltering, compile sendmail with -D_FFR_MILTER_RCPT_ERROR -D_FFR_MILTER_RCPT_ERROR_ALL
This is off by default.

In all these cases the macro {rcpt_mailer} will be set to "error" for these recipients.

============
Milter Rewrite:
============

There is a new function available to milters

sfsistat smfi_rewrite(SMFICTX *ctx, char * ruleset, char ***rs_strings, int *ruleset_result);

This will request sendmail rewrite strings using the named ruleset.

On a successfull return, the variable passed into smfi_rewrite pointing to the array of char pointers will most likely be pointing to a new array of char pointers. Keep a reference to the original structure handy if you need to free anything.

On unsuccessfull returns (return != MI_SUCCESS) either a system error or a smfi_rewrite specific error will be returned. Consult patched source for more details.

You must loop the new array, free each pointer and then freeing the array itself.

The return code from the ruleset rewriting will be stored in ruleset_results. Currently this is 0 for resolving to no mailer, 1 for resolving to $#ok, 2 for resolving to $#accept, 3 $#relay, -1 for resolving to $#error, -2 $#discard, -3 for resolving to $#abort and -4 for resolving to $#reject.

To enable this behavior libmilter, sendmail and the milter must be compiled with -D_FFR_MILTER_REWRITE
This line may be added to sendmail.mc
define(`confMILTER_REWRITE', `1')dnl

This line may be added to sendmail.mc
define(`confMILTER_REWRITE_RULESET', `RuleSetName')dnl

This defines a ruleset which gets passed the requested ruleset and the name of the milter which reqested it, as defined in your sendmail.mc file.
Something like this will be passed to the milter: 
MConnectRS $| verbose-milter

You can use this to be paranoid of which rulesets milters can call. If the ruleset returns any mailer other than $#ok and/or the ruleset namespace is returned empty the rewrite request is sent back empty. Which translates into the milter as a successfull call with nothing returned from the rewrite space, so check for that.

You also need to enable this on a per milter basis. This is done by adding the W to the flags section.
Ensure that -D_FFR_MILTER_REWRITE is used on the m4 line which rebuilds your cf from mc file.

To enable the milter to communicate the request to sendmail, you must add this flag in the milter similar to

smfi_Desc->xxfi_flags |= SMFIF_REWRITE;

Extensive debugging can be seen when using a level >7.

==========
EAGAIN
==========

While writing above feature, I feared I may misorder the sendmail commands.
I have not yet seen that this is actually needed. That being said, here goes the description.

This adds rudimentary flow control by allowing the milter to send a EAGAIN command to the MTA, telling it to send the previous command again.

In instances where formerly the MTA would not expect a response and now waits for a possible EAGAIN, the milter may either send the EAGAIN or send a NOOP command to let the MTA continue without error.

To turn this on libmilter, sendmail and the milter need to be compiled with -D_FFR_MILTER_EAGAIN
This line needs to be in sendmail.mc
define(`confMILTER_EAGAIN', `1')dnl
And the G flag needs to be added to each milter definition line that needs it.

Ensure that -D_FFR_MILTER_EAGAIN is used on the m4 line which rebuilds your cf from mc file.

The milter must set this flag like this:
mfi_Desc->xxfi_flags |= SMFIF_EAGAIN;

No other feature on this page depends on this one. So far it has proven to be a complete waste of time. Even though it appears to work fine.


===============
Testing this
===============

I highly recommend you do not place this into any sort of production environment without first compiling it into a seperate source tree and running the generated sendmail with newly compiled milters (also in a non-system wide location) with a local copy of the cf files and a new spool directory. Make it run on an unused privelege port (DAEMON_OPTIONS) and as an unprivileged user.

Somewhere on the /var/tmp paritition perhaps.....


