14 releases
0.2.4 | Dec 6, 2021 |
---|---|
0.2.3 | May 3, 2021 |
0.2.2 | Jan 7, 2021 |
0.2.1 | May 17, 2020 |
0.1.4 | Nov 26, 2019 |
#10 in #sendmail
104 downloads per month
Used in milter
41KB
445 lines
Procedural macros that generate C callback functions for use in milter implementation.
The attribute macros in this crate facilitate the creation of FFI callback
functions that are required for the configuration of a Milter
. The
attribute macros are used to annotate ordinary Rust functions as milter
callbacks. A C function is then generated that delegates to the Rust
callback, safely, and taking care of conversion between Rust/C types.
Callback functions serve the purpose of event handlers (hence the
nomenclature on_*
) for the various ‘events’ that happen during an SMTP
conversation. For each of the stages in the milter protocol there is a
corresponding attribute macro.
Usage
This crate is a dependency of the milter crate, which re-exports
all macros under its namespace. It is recommended to use
macros from the
milter
namespace and not rely on this crate directly:
use milter::{on_connect, on_close, Milter, Status};
The remaining sections describe some additional features of the attribute macros.
Raw string inputs
By default, callbacks receive string inputs of type &str
, that is, UTF-8
strings. Where UTF-8 encoding is not desired, it is possible to substitute
the C string type &CStr
for &str
in your handler function signature in
order to receive the raw bytes instead.
Contrast the following example with the one shown at [macro@on_header
].
use std::ffi::CStr;
#[on_header(header_callback)]
fn handle_header(context: Context<()>, name: &CStr, value: &CStr) -> Status {
// ^^^^^ ^^^^^
Status::Continue
}
This feature is supported wherever &str
appears in callback function
arguments.
Callback results
The return type of a callback function may be wrapped in a
milter::Result
where desired. This is a convenience: as most context API
methods return milter::Result
s these can then be unwrapped with the ?
operator.
Compare the following example with the one shown at [macro@on_eom
]. This code
fragment also demonstrates the use of the ?
operator enabled by choosing
this return type.
#[on_eom(eom_callback)]
fn handle_eom(context: Context<()>) -> milter::Result<Status> {
// ^^^^^^^^^^^^^^^^^^^^^^
if let Some(version) = context.api.macro_value("v")? {
println!("{}", version);
}
Ok(Status::Continue)
}
This feature is supported on all callback functions.
Failure modes
An Err
result returned from a callback leads to a temporary failure
(Status::Tempfail
) response being returned to the MTA. The milter
then continues to handle requests normally.
Panicking, on the other hand, leads to immediate shutdown of the milter.
All stages switch to returning a failure response and no longer execute the
handler functions (however, currently executing callback handlers are
allowed to finish). The libmilter worker processes are terminated and the
currently blocked invocation of Milter::run
returns. Cleanup logic in the
close
or other stages is not executed.
The principle behind the panicking behaviour is, as elsewhere, exit as quickly as possible, within the constraints posed by libmilter and the FFI interface.
The above failure modes are provided as a convenience. Use explicit error handling if they don’t satisfy your requirements.
Dependencies
~1.5MB
~37K SLoC