${COURIER_HOME}/lib/modules
contains shared
libraries and programs which provide input and output modules to
Courier. The actual module itself can actually be installed and
invoked anywhere else, the SMTP module, in fact, is installed in
bin. The shared library in lib, however, may include functions
which rewrite addresses for messages submitted from the input
module. All files for module named MODULE are stored in the
directory ${COURIER_HOME}/lib/modules/MODULE
.
modules.ctl
file${COURIER_HOME}/lib/modules/modules.ctl
contains a
list of all the modules that Courier loads.
modules.ctl
is only used if Courier is compiled with
shared library support. If Courier is compiled with static
linkage only (by choice, or by necessity), all the module
libraries are statically linked into Courier, and
modules.ctl
is not used. Each line in modules.ctl is
in the following form:
priority<SP>name<SP>filename,
where <SP>
designates the space character. The
lines are sorted in increasing priority order! "priority" is
taken from the module's config file, and filename is the
filename of the shared library.
${COURIER_HOME}/lib/modules/name
directorymodules.ctl
file.
NAME=VALUE
notation, where NAME
is the name of the
configuration parameter, and VALUE
is its value.
submit
and courierd
. The shared library
provides code to rewrite addresses to and from the canonical
format for messages to or from this module. If Courier is
compiled with static linkage, this file does not exist - the
library is statically linked.
The actual name of the library may vary, and is specified in
the config
file.
If this shared library does not exist, an attempt is made to
load librewrite-old
. This allows an updated version
of the shared library to be installed in a live, running, system
by renaming the current one to librewrite-old
, then
renaming the new one to librewrite
.
Although submit will pick up new rewriting rules immediately,
courierd
must be SIGHUPed in order to reload the new
shared library.
NAME=name
- specifies
the name of this module. Should be the same as the directory
name.
LIBRARY=filename
- specifies the name of the
shared library to load. Not used if Courier was compiled with
static libraries.
VERSION=version
- version of the module
interface. Not the actual version of the module, but version of
the interface between the module, and Courier. The current
version is version 0.
PRIORITY=n
- priority of the output module.
Courier calls all the modules' rewritedel
functions
in the increasing priority order until it finds one which accepts
messages addressed to the recipient's address.
PROG=pathname
- pathname to the output module
program. Must be a full path, unless the module itself is in the
lib/MODULE
directory. If the PROG
parameter is missing, this module is an input only module. If the
attempt to execute PROG
fails, Courier will attempt
to execute PROG-old
, which allows an updated output
module to be inserted into a live system by renaming the current
one PROG-old
, then renaming the new output module as
PROG
.
MAXDELS=n
- maximum concurrent deliveries for
this module. No more than these many instances of
PROG
will be started at any given time.
MAXHOST=n
- maximum instances of
PROG
that will be started with the same
HOST
parameter.
MAXRCPT=n
- maximum number of addresses that will
be given to any single instance of PROG
.
Please note that although these parameters are reread by
courierd
when it restarts, the individual output
module may impose its own restrictions on the valid limits for
these parameters.
XXXX
is used to
represent the name of the function in the library for module
XXXX
. For example, in the "local" module, the
rw_install
function is called
local_rw_install
.
struct rw_list *XXXX_rw_install(const struct
rw_install_info *info);
The rw_install()
function is called after the
shared library is open. It receives a pointer to the following
structure:
struct rw_install_info { int rw_verlo; int rw_verhi; const char *courier_home; } ;
rw_verlo/rw_verhi
- reserved for future
expansion. Currently set to 0. rw_install
function of
modules compatible with this Courier interface must check that
rw_verlo
is set to 0, and ignore
rw_verhi
.
courier_home
- Courier's home directory, the
shared library can use this to find its files.
rw_search
functionstruct rw_list *rw_search(const char *);The
rw_search
function can be called by a
library function in order to return the rw_list (see below)
structure of a function in another library. rw_search
may NOT be called form XXXX_rw_install
, because the
library containing this function may not've been installed yet.
rw_search
may be called from the
XXXX_rw_init
function.
const char *XXXX_rw_init()
After all modules are installed, each module's
rw_init()
function is called, which can complete any
additional setup. rw_init
should return a null
pointer. Otherwise, rw_init
should return the error
message text. Courier will refuse to start if
rw_init
does not return a null pointer.
The library's rw_install
function must return a
pointer to the following structure. If rw_install
returns a NULL pointer, Courier will refuse to start.
struct rw_list { int rw_version; void (*rewrite)(struct rw_info *info, void (*func)(struct rw_info *)); void (*rewrite_del)(struct rw_info *info, void (*func)(struct rw_info *), void (*delfunc)(struct rw_info *info, const struct rfc822token *host, const struct rfc822 *addr)); int (*filter_msg)(const char *, int, const char *, const char *, const char *, char *, unsigned); } ;
rw_version
- shared libraries compatible with
this module interface must set rw_version to zero.
rewrite
- this function is called to rewrite a
single address. The first argument points to the following
structure:
struct rw_info {
int mode;
struct rfc822token *ptr;
void (*err_func)(int, const char *, struct rw_info *);
const struct rfc822token *sender;
const char *smodule;
void *udata;
} ;
mode
contains the following values, ORed into a
bitmask: RW_ENVSENDER
- rewrite envelope sender,
RW_ENVRECIPIENT
- rewrite envelope recipient,
RW_HEADER
- rewrite header. When calling
rewrite()
, one of these three bits will be set.
Additional bits that may be set: RW_OUTPUT
-
rewrite
() should convert canonical format to the
transport format. If this bit is not set, rewrite should convert
from the transport format to the canonical format. In fact, the
main courierd
does not call rewrite with the
RW_OUTPUT
bit set, because that function is performed
by the dedicated output module, which may handle rewriting on its
own. Also, the RW_SUBMIT
can be set together with
RW_ENVSENDER
or RW_ENVRECIPIENT
,
indicating that this call is as a result of a message being
submitted for delivery (as opposed to address verification for
EXPN/VRFY
functionality).
It is possible that none of those bits are set, when invoked by another rewrite function.
ptr
is the address to rewrite, as rfc822
tokens.
udata
contains an arbitrary pointer, for usage by
rewrite's caller.
When mode has RW_ENVRECIPIENT
set,
sender
points to the envelope sender format in the
canonical format (previous result of RW_ENVSENDER
),
otherwise this field is unused. If sender
is NULL,
this should be interpreted as an empty envelope sender (or if
rewrite
is being called in test mode.
smodule
is initialized when mode has the
RW_SUBMIT
bit set. It will point to the name of the
module argument to submit - the module sending the message.
err_func
is the function to call in case of an
error.
rewrite
is expected to call either
func
, (it's second argument), or
err_func
, before returning. If rewriting succeeds,
func
is called. If rewriting failed,
rewrite
must call the err_func
is
function. errcode
will be the RFC822-style error
number, errmsg
is the error message, which may be
multiline (includes newlines). The text in errmsg
is
NOT prefixed by the error number.
After calling func
, or err_func
,
rewrite
is expected to immediately terminate.
rewrite
may alter the 'ptr' link list in any form or
fashion it wants, except that it may NOT malloc or free any node,
or a part thereof. However, it can relink portions of the link
list, or modify the link pointers to include tokens created by
rewrite
internally.
After func
or err_func
terminates,
rewrite
may deallocate everything it allocated, then
terminate itself.
This interface allows rewrite to execute very quickly, without allocating or deallocating any memory. If new RFC822 tokens are required, they can be allocated on the stack, and linked into the original list.
The rewrite_del
function is called to determine
if the module can accept delivery of a message to this address.
The rewrite_del
of all installed libraries are
called until one of them calls the delfunc
function.
If rewrite_del
cannot accept delivery of a message,
it should call func
. The rewrite_del
function should call the delfunc
function to
indicate that this module can accept mail addressed to the
address specified by info->ptr
.
rewrite_del
receives the pointer to the rw_info
structure, then the host
and the
address
information for the output module, as
rfc822token lists. If the mode field has the
RW_SUBMIT
bit set, rewrite_del can find the
message's envelope sender address in canonical format) in
info->sender
.
Like rewrite
, rewrite_del
may make
arbitrary changes to info->ptr
, except that it
may not deallocate memory used for the existing list.
rewrite_del
may modify the link list, and allocate
memory for new rfc822 tokens. After calling either
func
or delfunc
,
rewrite_del
should terminate immediately, and
deallocate any allocated memory. rewrite_del
must
keep track of any allocated memory separate, and cannot assume
that info->ptr
hasn't changed.
When RW_SUBMIT
bit is set,
rewrite_del
can be used to perform additional
recipient-specific code, which may be too expensive to run every
time courier goes through the queue. The udata
field
contains a pointer to caller-specific data. The
sender
field contains a pointer to the envelope
sender, in canonical format. Like rewrite
,
rewrite_del
may muck around with the
rfc822token
list in ptr
.
rewrite_del
functions are called in order according
to the configured module priority. By setting a higher priority,
it is possible to have rewrite_del
rewrite the
address so that it would be accepted by another module's
rewrite_del
, down the chain.
The last function, rw_filter_msg
, is called to
run an arbitrary spam filter which can be used to selectively
reject messages. rw_filter_msg
will be called after
rewrite_del
accepted the message for delivery. The
arguments are as follows:
rewrite_del
, as a
text string.rewrite_del
, as a
text string.rw_filter_msg
should return 0 if the message is
acceptable, a negative value to permanently reject the message to
this recipient, and a positive value for a temporary
rejection.
PROG
PROG
is the output
module that will be started by Courier when it comes up. PROG can
be a shell command, it is executed via "$SHELL -c
".
It will be started under userid mail, group mail, in
${COURIER_HOME}/lib/modules/NAME
. Courier will
communicate with PROG
on standard input and output.
If PROG
succesfully initializes, it should fork,
and the parent should exit with status of 0. Courier waits until
PROG
exits. If it exits with a non-0 exit code,
Courier will fail starting up. The child process will then
continue to read and write from standard output.
COURIER_HOME
, MAXDELS
,
MAXHOST
, and MAXRCPTS
will be placed in
the environment, prior to executing PROG
.
Tip: if the environment variables are not set,
PROG
can presume that it's being run in test mode,
from the command line, and forego the fork.
If PROG
terminates, Courier will consider it a
fatal error (Courier detects the input channel being closed).
If PROG
gets an end-of-file indication, it can
assume that Courier is being shut down, so it should promptly
cease all activities, without waiting for pending messages to be
delivered.
To start delivery for a particular message, PROG
will receive a newline-terminated command, specifying the
message, and the recipients, and the delivery ID. Once
PROG
finishes delivering messages, PROG
should write the results of the delivery into the message's
control file, then print the delivery ID on its standard output,
terminated by newline. If the module's config file
specifies that the module can handle multiple deliveries at the
same time, PROG
may receive additional deliveries
before it finishes delivering the first message.
The command that prog receives is a newline-terminated line that looks like this:
msgnum<tab>sender<tab>delid<tab>host<tab>num1<tab>addr1<tab>num2<tab>addr2...
<tab> represents the ASCII tab character. This is basically a list of tab-separated fields. The first field is the message id number (the inode number).
sender is the message envelope sender, after it's rewritten to the module format, by the module shared library.
delid is the "delivery ID", which is a small integer,
representing this delivery. After PROG
finishes
delivering the message, it should print the message's delivery ID
on standard output after saving the delivery status of each
recipient in the control file.
The host field specifies the host where the message should be
delivered to, as determined by the module's output rewrite rule.
Following the host, there will be one or more num/address pairs.
address is the recipient's address as determined by the output
rewrite rule, and num is the recipient's number in the message's
list of recipients (this is used to save the delivery status in
the control file). Note that the address can be an empty string,
so there will be two consecutive tabs there.