${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.