Procedural macros to generate C callback functions and a thin wrapping layer.
These attribute macros are used to annotate callback functions in milter.
These callback functions serve the purpose of event handlers (hence the
nomenclature on_*
) for the various ‘events’ that happen during an SMTP
conversation and are thus exposed in the milter protocol.
Usage
This crate is a dependency of the milter crate, which re-exports all macros under its namespace. Thus you should not need to use this crate directly.
Note that with Rust 2018 there are two ways of importing procedural macros. Nowadays, macros can be imported like other symbols:
use milter::{on_connect, on_close, Milter, Status};
That does require you to list all macros in the use
statement, though.
The older syntax with extern crate
lets you import all macros without
listing them explicitly:
#[macro_use] extern crate milter;
use milter::{Milter, Status};
Both notations are fine.
Callback results
The result type may be wrapped in a milter::Result
where desired. This is
a convenience as most Context
methods return milter::Result
s these can
then be propagated with the ?
operator.
For example, the end-of-message handler may return plain Status
:
# #[macro_use] extern crate milter_callback;
# use milter::{ActionContext, Status};
#[on_eom(eom_callback)]
fn handle_eom(context: ActionContext<()>) -> Status {
Status::Continue
}
Or it may return milter::Result<Status>
. The example shows use of the ?
operator enabled by choosing this return type.
# #[macro_use] extern crate milter_callback;
# use milter::{ActionContext, Status};
#[on_eom(eom_callback)]
fn handle_eom(context: ActionContext<()>) -> milter::Result<Status> {
if let Some(version) = context.macro_value("v")? {
println!("{}", version);
}
Ok(Status::Continue)
}
This feature is supported on all the callback functions.
Errors
An error result returned from a callback leads to a Status::Tempfail
response returned to the MTA. The milter will continue processing.
Panicking leads to shutdown of the milter. That is, Milter::run
returns.
It could then be restarted by invoking Milter::run
again. However,
restarting is potentially hazardous as panic exits without going through
potential cleanup paths in close
or abort
. That is, there is a
possibility of memory leakage.
Returning an error result does not have this problem. Returning an error
leads to tempfail and then the ordinary cleanup path on connection close
.