### Construct a Pin Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html Example of creating a Pin for an Unpin type. ```rust use std::pin::Pin; let mut val: u8 = 5; // Since `val` doesn't care about being moved, we can safely create a "facade" `Pin` // which will allow `val` to participate in `Pin`-bound apis without checking that // pinning guarantees are actually upheld. let mut pinned: Pin<&mut u8> = Pin::new(&mut val); ``` -------------------------------- ### Basic Milter Implementation Source: https://docs.rs/indymilter/0.3.0/indymilter/fn.run.html A minimal example demonstrating how to initialize and run a no-op milter using a TCP listener. ```rust use indymilter::Callbacks; use std::future; use tokio::net::TcpListener; let listener = TcpListener::bind("127.0.0.1:3000").await?; let callbacks = Callbacks::<()>::new(); let config = Default::default(); let shutdown = future::pending::<()>(); indymilter::run(listener, callbacks, config, shutdown).await ``` -------------------------------- ### Configuring NegotiateContext Fields Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.NegotiateContext.html?search=std%3A%3Avec Examples for modifying the requested actions, protocol options, and macros within the context. ```rust context.requested_actions |= Actions::ADD_RCPT | Actions::ADD_RCPT_EXT; ``` ```rust context.requested_opts |= ProtoOpts::SKIP; ``` ```rust let macros = CString::new("{auth_authen} {auth_type}").unwrap(); context.requested_macros.insert(MacroStage::Mail, macros); ``` -------------------------------- ### Unwrap a Pin Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html Example of unwrapping a Pin to retrieve the underlying pointer. ```rust use std::pin::Pin; let mut val: u8 = 5; let pinned: Pin<&mut u8> = Pin::new(&mut val); // Unwrap the pin to get the underlying mutable reference to the value. We can do // this because `val` doesn't care about being moved, so the `Pin` was just // a "facade" anyway. let r = Pin::into_inner(pinned); assert_eq!(*r, 5); ``` -------------------------------- ### pub fn get(&self, name: &CStr) -> Option<&CStr> Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Macros.html Retrieves the value associated with a specific macro name. Single-character macros can be looked up with or without braces. ```APIDOC ## pub fn get(&self, name: &CStr) -> Option<&CStr> ### Description Returns the value associated with the given macro name, if any. Single-character macros like `i` or `{i}` can be looked up in either form (both names `i` and `{i}` return the same result). ### Parameters - **name** (&CStr) - Required - The name of the macro to retrieve. ``` -------------------------------- ### Callback Registration Methods Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Callbacks.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Methods to configure callbacks for specific milter stages. ```APIDOC ## Callback Registration ### Methods - **on_negotiate**: Configures the callback for the `negotiate` stage. - **on_connect**: Configures the callback for the `connect` stage. - **on_helo**: Configures the callback for the `helo` stage. - **on_mail**: Configures the callback for the `mail` stage. - **on_rcpt**: Configures the callback for the `rcpt` stage. - **on_data**: Configures the callback for the `data` stage. - **on_header**: Configures the callback for the `header` stage. - **on_eoh**: Configures the callback for the `eoh` stage. - **on_body**: Configures the callback for the `body` stage. - **on_eom**: Configures the callback for the `eom` stage. - **on_abort**: Configures the callback for the `abort` stage. - **on_close**: Configures the callback for the `close` stage. - **on_unknown**: Configures the callback for the `unknown` stage. ``` -------------------------------- ### Callbacks::new Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Callbacks.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Creates a new, empty collection of milter callbacks. ```APIDOC ## pub fn new() -> Self ### Description Returns a new, empty collection of callbacks. ``` -------------------------------- ### Callbacks Methods Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Callbacks.html?search= Methods for initializing and configuring event callbacks for the milter lifecycle. ```APIDOC ## pub fn new() -> Self ### Description Returns a new, empty collection of callbacks. ## pub fn on_negotiate(self, callback: impl Fn(&mut NegotiateContext, Actions, ProtoOpts) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `negotiate` stage. ## pub fn on_connect(self, callback: impl Fn(&mut Context, CString, SocketInfo) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `connect` stage. ## pub fn on_helo(self, callback: impl Fn(&mut Context, CString) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `helo` stage. ## pub fn on_mail(self, callback: impl Fn(&mut Context, Vec) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `mail` stage. ## pub fn on_rcpt(self, callback: impl Fn(&mut Context, Vec) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `rcpt` stage. ## pub fn on_data(self, callback: impl Fn(&mut Context) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `data` stage. ## pub fn on_header(self, callback: impl Fn(&mut Context, CString, CString) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `header` stage. ## pub fn on_eoh(self, callback: impl Fn(&mut Context) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `eoh` stage. ## pub fn on_body(self, callback: impl Fn(&mut Context, Bytes) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `body` stage. ## pub fn on_eom(self, callback: impl Fn(&mut EomContext) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `eom` stage. ## pub fn on_abort(self, callback: impl Fn(&mut Context) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `abort` stage. ## pub fn on_close(self, callback: impl Fn(&mut Context) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `close` stage. ## pub fn on_unknown(self, callback: impl Fn(&mut Context, CString) -> CallbackFuture<'_> + Send + Sync + 'static) -> Self ### Description Configures the callback for the `unknown` stage. ``` -------------------------------- ### pub async fn run Source: https://docs.rs/indymilter/0.3.0/indymilter/fn.run.html Runs a milter that handles MTA connections until the provided shutdown future completes. ```APIDOC ## Function: run ### Description Runs a milter that handles MTA connections until it is shut down. While the future returned by `run` is awaited, it perpetually accepts new MTA connections and spawns a session task for each connection. ### Signature `pub async fn run(listener: impl Listener, callbacks: Callbacks, config: Config, shutdown: impl Future) -> Result<()>` ### Parameters - **listener** (impl Listener) - The listener to accept MTA connections. - **callbacks** (Callbacks) - The callbacks to handle milter events. - **config** (Config) - Configuration for the milter. - **shutdown** (impl Future) - A future that, when completed, triggers a graceful shutdown of the milter. ### Termination For graceful termination, the milter task should be shut down by letting the `shutdown` future complete. When the `shutdown` future completes, all sessions exit cleanly as soon as possible. ### Errors Returns an error when the listener fails to accept any new connections. ``` -------------------------------- ### ContextActions Methods Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E A collection of methods for performing milter actions. Each method corresponds to specific MTA capabilities and requires corresponding flags to be enabled. ```APIDOC ## add_header(name, value) Adds a header to the message. Requires `Actions::ADD_HEADER`. ## insert_header(index, name, value) Inserts a header at the specified index. Requires `Actions::ADD_HEADER`. ## change_header(name, index, value) Replaces or deletes the header at the given index. Requires `Actions::CHANGE_HEADER`. ## change_sender(mail, args) Replaces the envelope sender, with optional ESMTP arguments. Requires `Actions::CHANGE_SENDER`. ## add_recipient(rcpt) Adds an envelope recipient. Requires `Actions::ADD_RCPT`. ## add_recipient_ext(rcpt, args) Adds an envelope recipient with ESMTP arguments. Requires `Actions::ADD_RCPT_EXT`. ## delete_recipient(rcpt) Removes an envelope recipient. Requires `Actions::DELETE_RCPT`. ## replace_body(chunk) Replaces the message body. Requires `Actions::REPLACE_BODY`. ## progress() Reports operation-in-progress to the MTA. ## quarantine(reason) Quarantines the message. Requires `Actions::QUARANTINE`. ``` -------------------------------- ### pub fn to_hash_map(&self) -> HashMap Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Macros.html Exports all currently defined macros into a new HashMap. ```APIDOC ## pub fn to_hash_map(&self) -> HashMap ### Description Returns a new hash map containing all defined macros. ``` -------------------------------- ### MacroStage::all Source: https://docs.rs/indymilter/0.3.0/indymilter/enum.MacroStage.html?search= Returns an iterator of all available macro stages. ```APIDOC ## pub fn all() -> impl DoubleEndedIterator ### Description Returns an iterator of all macro stages. ### Returns - **Iterator** (impl DoubleEndedIterator) - An iterator over all variants of the MacroStage enum. ``` -------------------------------- ### Pinning closure captures with the pin! macro Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Shows the recommended approach for pinning closure captures using the pin! macro to avoid pinning contract violations. ```rust use std::pin::pin; use std::task::Context; use std::future::Future; fn move_pinned_closure(mut x: impl Future, cx: &mut Context<'_>) { let mut x = pin!(x); // Create a closure that captures `x: Pin<&mut _>`, which is safe to move. let mut closure = move || { let _ignore = x.as_mut().poll(cx); }; // Call the closure, so the future can assume it has been pinned. closure(); // Move the closure somewhere else. let mut moved = closure; // Calling it again here is fine (except that we might be polled a future that already // returned `Poll::Ready`, but that is a separate problem). moved(); } ``` -------------------------------- ### Message::new Source: https://docs.rs/indymilter/0.3.0/indymilter/message/struct.Message.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Creates a new milter protocol message instance. ```APIDOC ## Message::new ### Description Creates a new message with the given kind and payload buffer. ### Signature `pub fn new(kind: impl Into, buffer: impl Into) -> Self` ### Parameters - **kind** (impl Into) - The message kind. - **buffer** (impl Into) - The message payload buffer. ``` -------------------------------- ### Export macros to HashMap Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Macros.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Convert all currently defined macros into a HashMap of CString keys and values. ```rust pub fn to_hash_map(&self) -> HashMap ``` -------------------------------- ### Reborrowing Pin with as_mut Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html Shows how to use as_mut to reborrow a Pin<&mut Self> when calling methods that consume the pin. ```rust use std::pin::Pin; impl Type { fn method(self: Pin<&mut Self>) { // do something } fn call_method_twice(mut self: Pin<&mut Self>) { // `method` consumes `self`, so reborrow the `Pin<&mut Self>` via `as_mut`. self.as_mut().method(); self.as_mut().method(); } } ``` -------------------------------- ### ProtoOpts Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.ProtoOpts.html The definition of the ProtoOpts struct. ```rust pub struct ProtoOpts(/* private fields */); ``` -------------------------------- ### Create New Message Source: https://docs.rs/indymilter/0.3.0/indymilter/message/struct.Message.html?search=u32+-%3E+bool Constructor for creating a new Message instance. ```rust pub fn new(kind: impl Into, buffer: impl Into) -> Self ``` -------------------------------- ### Request protocol options Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.NegotiateContext.html Update the requested protocol options for the MTA within the negotiate context. ```rust context.requested_opts |= ProtoOpts::SKIP; ``` -------------------------------- ### OptNegPayload Struct Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/message/command/struct.OptNegPayload.html The structure definition for OptNegPayload, containing version, actions, and protocol options. ```rust pub struct OptNegPayload { pub version: Version, pub actions: Actions, pub opts: ProtoOpts, } ``` -------------------------------- ### Request MTA macros Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.NegotiateContext.html Insert requested macros into the negotiate context for a specific mail stage. ```rust let macros = CString::new("{auth_authen} {auth_type}").unwrap(); context.requested_macros.insert(MacroStage::Mail, macros); ``` -------------------------------- ### pub async fn write(stream: &mut S, msg: Message) -> Result<()> Source: https://docs.rs/indymilter/0.3.0/indymilter/message/fn.write.html Writes a milter protocol message to a stream. The stream must implement AsyncWrite and Unpin. ```APIDOC ## write ### Description Writes a milter protocol message to a stream. ### Signature `pub async fn write(stream: &mut S, msg: Message) -> Result<()>` ### Constraints - **S**: Must implement `AsyncWrite` and `Unpin` traits. ``` -------------------------------- ### Pinning closure captures safely Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html Demonstrates the risks of using Pin::new_unchecked in closures and the recommended approach using the pin! macro. ```rust use std::pin::Pin; use std::task::Context; use std::future::Future; fn move_pinned_closure(mut x: impl Future, cx: &mut Context<'_>) { // Create a closure that moves `x`, and then internally uses it in a pinned way. let mut closure = move || unsafe { let _ignore = Pin::new_unchecked(&mut x).poll(cx); }; // Call the closure, so the future can assume it has been pinned. closure(); // Move the closure somewhere else. This also moves `x`! let mut moved = closure; // Calling it again means we polled the future from two different locations, // violating the pinning API contract. moved(); // Potential UB ⚠️ } ``` ```rust use std::pin::pin; use std::task::Context; use std::future::Future; fn move_pinned_closure(mut x: impl Future, cx: &mut Context<'_>) { let mut x = pin!(x); // Create a closure that captures `x: Pin<&mut _>`, which is safe to move. let mut closure = move || { let _ignore = x.as_mut().poll(cx); }; // Call the closure, so the future can assume it has been pinned. closure(); // Move the closure somewhere else. let mut moved = closure; // Calling it again here is fine (except that we might be polled a future that already // returned `Poll::Ready`, but that is a separate problem). moved(); } ``` -------------------------------- ### Request MTA actions Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.NegotiateContext.html Update the requested actions for the MTA within the negotiate context. ```rust context.requested_actions |= Actions::ADD_RCPT | Actions::ADD_RCPT_EXT; ``` -------------------------------- ### ProtoOpts constants Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.ProtoOpts.html?search=std%3A%3Avec Constants used to configure milter protocol options, such as skipping stages or setting noreply behavior. ```rust pub const NO_CONNECT: Self ``` ```rust pub const NO_HELO: Self ``` ```rust pub const NO_MAIL: Self ``` ```rust pub const NO_RCPT: Self ``` ```rust pub const NO_DATA: Self ``` ```rust pub const NO_HEADER: Self ``` ```rust pub const NO_EOH: Self ``` ```rust pub const NO_BODY: Self ``` ```rust pub const NO_UNKNOWN: Self ``` ```rust pub const NOREPLY_CONNECT: Self ``` ```rust pub const NOREPLY_HELO: Self ``` ```rust pub const NOREPLY_MAIL: Self ``` ```rust pub const NOREPLY_RCPT: Self ``` ```rust pub const NOREPLY_DATA: Self ``` ```rust pub const NOREPLY_HEADER: Self ``` ```rust pub const NOREPLY_EOH: Self ``` ```rust pub const NOREPLY_BODY: Self ``` ```rust pub const NOREPLY_UNKNOWN: Self ``` ```rust pub const REJECTED_RCPT: Self ``` ```rust pub const LEADING_SPACE: Self ``` ```rust pub const SKIP: Self ``` -------------------------------- ### Config Struct Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Config.html The primary structure used for milter configuration. ```rust pub struct Config { pub max_connections: usize, pub actions: Actions, pub connection_timeout: Duration, } ``` -------------------------------- ### run Source: https://docs.rs/indymilter/0.3.0/indymilter/index.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E The run function is the main entry point to the indymilter API. It executes a milter that handles MTA connections until it is shut down. ```APIDOC ## run ### Description Runs a milter that handles MTA connections until it is shut down. This function returns a future that can be awaited. ### Signature `pub async fn run(listener: L, config: Config, callbacks: C) -> Result<(), Box>` ### Parameters - **listener** (L) - The listener implementation (e.g., a Tokio-based listener). - **config** (Config) - The milter configuration settings. - **callbacks** (C) - The callback closures defined for each milter stage. ``` -------------------------------- ### run Source: https://docs.rs/indymilter/0.3.0/indymilter/index.html?search= The run function is the main entry point to the indymilter API. It executes a milter that handles MTA connections until it is shut down. ```APIDOC ## run ### Description Runs a milter that handles MTA connections until it is shut down. This function returns a future that can be awaited to execute the milter application. ### Signature `pub async fn run(listener: L, config: Config, callbacks: C) -> Result<(), Error>` ### Parameters - **listener** (L) - Required - A listener implementing the Listener trait. - **config** (Config) - Required - The milter configuration. - **callbacks** (C) - Required - The callback closures for each milter stage. ``` -------------------------------- ### pub async fn read(stream: &mut S) -> Result Source: https://docs.rs/indymilter/0.3.0/indymilter/message/fn.read.html Reads a milter protocol message from a stream. ```APIDOC ## pub async fn read(stream: &mut S) -> Result ### Description Reads a milter protocol message from a stream. ### Signature `pub async fn read(stream: &mut S) -> Result where S: AsyncRead + Unpin` ### Parameters - **stream** (&mut S) - Required - An asynchronous stream that implements AsyncRead and Unpin traits. ### Returns - **Result** - Returns a Result containing the parsed Message if successful, or an error if the read operation fails. ``` -------------------------------- ### Command Parsing and Conversion Source: https://docs.rs/indymilter/0.3.0/indymilter/message/command/enum.Command.html?search= Methods for parsing a command from a message and converting a command back into a message. ```rust pub fn parse_command(msg: Message) -> Result ``` ```rust pub fn into_message(self) -> Message ``` -------------------------------- ### into_message Source: https://docs.rs/indymilter/0.3.0/indymilter/message/reply/enum.Reply.html?search=std%3A%3Avec Converts a Reply instance into a milter protocol message. ```APIDOC ## pub fn into_message(self) -> Message ### Description Converts this reply to a milter protocol message. ### Returns - **Message** - The resulting milter protocol message. ``` -------------------------------- ### Unsafe Pinning with Rc Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html Demonstrates how using Pin::new_unchecked on an Rc can lead to undefined behavior due to potential aliasing and mutable access after dropping the pin. ```rust use std::rc::Rc; use std::pin::Pin; fn move_pinned_rc(mut x: Rc) { // This should mean the pointee can never move again. let pin = unsafe { Pin::new_unchecked(Rc::clone(&x)) }; { let p: Pin<&T> = pin.as_ref(); // ... } drop(pin); let content = Rc::get_mut(&mut x).unwrap(); // Potential UB down the road ⚠️ // Now, if `x` was the only reference, we have a mutable reference to // data that we pinned above, which we could use to move it as we have // seen in the previous example. We have violated the pinning API contract. } ``` -------------------------------- ### pub fn index(&self) -> i32 Source: https://docs.rs/indymilter/0.3.0/indymilter/message/struct.TryFromIndexError.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Retrieves the index that caused the conversion error. ```APIDOC ### pub fn index(&self) -> i32 #### Description Returns the index that caused the conversion error. #### Returns - **i32** - The index value that triggered the error. ``` -------------------------------- ### pub fn index(&self) -> i32 Source: https://docs.rs/indymilter/0.3.0/indymilter/message/struct.TryFromIndexError.html?search=u32+-%3E+bool Retrieves the index that caused the conversion error. ```APIDOC ### Method `pub fn index(&self) -> i32` ### Description Returns the index that caused the conversion error. ### Returns - **i32**: The index value that triggered the error. ``` -------------------------------- ### run Source: https://docs.rs/indymilter/0.3.0/indymilter/index.html The run function is the main entry point to the indymilter API. It returns a future that can be awaited to execute a milter application and handle MTA connections until shutdown. ```APIDOC ## run ### Description Runs a milter that handles MTA connections until it is shut down. This function returns a future that can be awaited. ### Signature `pub async fn run(listener: L, config: Config, callbacks: C) -> Result<(), Box>` ### Parameters - **listener** (L) - Required - A listener implementing the Listener trait. - **config** (Config) - Required - The milter configuration. - **callbacks** (C) - Required - The callback closures for each milter stage. ``` -------------------------------- ### Function Signature Source: https://docs.rs/indymilter/0.3.0/indymilter/fn.run.html The signature for the run function, requiring a listener, callbacks, configuration, and a shutdown future. ```rust pub async fn run( listener: impl Listener, callbacks: Callbacks, config: Config, shutdown: impl Future, ) -> Result<()> where T: Send + 'static, ``` -------------------------------- ### Safe Pinning with pin! Macro Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html?search=u32+-%3E+bool Uses the pin! macro to safely pin a future before capturing it in a closure. ```rust use std::pin::pin; use std::task::Context; use std::future::Future; fn move_pinned_closure(mut x: impl Future, cx: &mut Context<'_>) { let mut x = pin!(x); // Create a closure that captures `x: Pin<&mut _>`, which is safe to move. let mut closure = move || { let _ignore = x.as_mut().poll(cx); }; // Call the closure, so the future can assume it has been pinned. closure(); // Move the closure somewhere else. let mut moved = closure; // Calling it again here is fine (except that we might be polling a future that already // returned `Poll::Ready`, but that is a separate problem). moved(); } ``` -------------------------------- ### IntoCString::into_c_string Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.IntoCString.html?search=u32+-%3E+bool Converts the implementing type into a CString. ```APIDOC ## fn into_c_string(self) -> CString ### Description Converts the value into a CString. This is an infallible conversion. ### Signature `fn into_c_string(self) -> CString` ### Implementations - `impl IntoCString for &CStr` - `impl IntoCString for &str` - `impl IntoCString for CString` - `impl IntoCString for String` ``` -------------------------------- ### indymilter::run Source: https://docs.rs/indymilter/0.3.0/indymilter/fn.run.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Runs a milter that handles MTA connections until it is shut down. The function accepts a listener, callbacks, configuration, and a shutdown future. ```APIDOC ## Function: indymilter::run ### Description Runs a milter that handles MTA connections until it is shut down. While the future returned by `run` is awaited, it perpetually accepts new MTA connections and spawns a session task for each connection. ### Signature `pub async fn run(listener: impl Listener, callbacks: Callbacks, config: Config, shutdown: impl Future) -> Result<()>` ### Parameters - **listener** (impl Listener) - The listener to accept MTA connections. - **callbacks** (Callbacks) - The callbacks to handle milter events. - **config** (Config) - Configuration for the milter. - **shutdown** (impl Future) - A future that, when completed, triggers a graceful shutdown of the milter. ### Errors Returns an error if the listener fails to accept new connections. ### Example ```rust use indymilter::Callbacks; use std::future; use tokio::net::TcpListener; let listener = TcpListener::bind("127.0.0.1:3000").await?; let callbacks = Callbacks::<()>::new(); let config = Default::default(); let shutdown = future::pending::<()>(); indymilter::run(listener, callbacks, config, shutdown).await ``` ``` -------------------------------- ### progress Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=std%3A%3Avec Reports operation-in-progress to the MTA. ```APIDOC fn progress() -> Future> ``` -------------------------------- ### Macros::to_hash_map Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Macros.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Converts the collection of defined macros into a HashMap. ```APIDOC ## fn to_hash_map(&self) -> HashMap ### Description Returns a new hash map containing all currently defined macros. ``` -------------------------------- ### Define NegotiateContext structure Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.NegotiateContext.html The structure definition for NegotiateContext, which holds user data and configuration for the negotiation phase. ```rust pub struct NegotiateContext { pub data: Option, pub reply: SmtpReply, pub requested_actions: Actions, pub requested_opts: ProtoOpts, pub requested_macros: HashMap, } ``` -------------------------------- ### IntoCString Method Signature Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.IntoCString.html?search=u32+-%3E+bool The required method signature for converting a value into a CString. ```rust fn into_c_string(self) -> CString ``` -------------------------------- ### Unsafe Pinning with Mutable References Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html Demonstrates how using Pin::new_unchecked on a mutable reference can lead to undefined behavior if the value is moved after pinning. ```rust use std::mem; use std::pin::Pin; fn move_pinned_ref(mut a: T, mut b: T) { unsafe { let p: Pin<&mut T> = Pin::new_unchecked(&mut a); // This should mean the pointee `a` can never move again. } mem::swap(&mut a, &mut b); // Potential UB down the road ⚠️ // The address of `a` changed to `b`'s stack slot, so `a` got moved even // though we have previously pinned it! We have violated the pinning API contract. } ``` -------------------------------- ### Overwriting pinned data with set Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html Demonstrates using the set method to replace the value pointed to by a Pin. ```rust use std::pin::Pin; let mut val: u8 = 5; let mut pinned: Pin<&mut u8> = Pin::new(&mut val); println!("{}", pinned); // 5 pinned.set(10); println!("{}", pinned); // 10 ``` -------------------------------- ### TryFromIndexError index method Source: https://docs.rs/indymilter/0.3.0/indymilter/message/struct.TryFromIndexError.html?search= Retrieves the index that caused the conversion error. ```rust pub fn index(&self) -> i32 ``` -------------------------------- ### pub fn byte(&self) -> u8 Source: https://docs.rs/indymilter/0.3.0/indymilter/message/struct.TryFromByteError.html?search=std%3A%3Avec Returns the byte that caused the conversion error. ```APIDOC ## pub fn byte(&self) -> u8 ### Description Returns the byte that caused the conversion error. ### Signature `pub fn byte(&self) -> u8` ``` -------------------------------- ### ConnInfoPayload Struct Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/message/command/struct.ConnInfoPayload.html The structure definition for ConnInfoPayload, containing the hostname and socket information fields. ```rust pub struct ConnInfoPayload { pub hostname: CString, pub socket_info: SocketInfo, } ``` -------------------------------- ### Accessing PROTOCOL_VERSION Source: https://docs.rs/indymilter/0.3.0/indymilter/message/constant.PROTOCOL_VERSION.html The constant represents the Milter protocol version as a Version type. ```rust pub const PROTOCOL_VERSION: Version = 6; ``` -------------------------------- ### ContextActions Trait Methods for EomActions Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.EomActions.html Asynchronous methods available on EomActions for performing milter operations. ```rust fn add_header<'cx, 'k, 'v, 'async_trait>( &'cx self, name: impl 'async_trait + IntoCString + Send + 'k, value: impl 'async_trait + IntoCString + Send + 'v, ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, 'k: 'async_trait, 'v: 'async_trait, ``` ```rust fn insert_header<'cx, 'k, 'v, 'async_trait>( &'cx self, index: i32, name: impl 'async_trait + IntoCString + Send + 'k, value: impl 'async_trait + IntoCString + Send + 'v, ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, 'k: 'async_trait, 'v: 'async_trait, ``` ```rust fn change_header<'cx, 'k, 'v, 'async_trait>( &'cx self, name: impl 'async_trait + IntoCString + Send + 'k, index: i32, value: Option, ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, 'k: 'async_trait, 'v: 'async_trait, ``` ```rust fn change_sender<'cx, 'a, 'b, 'async_trait>( &'cx self, mail: impl 'async_trait + IntoCString + Send + 'a, args: Option, ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, 'a: 'async_trait, 'b: 'async_trait, ``` ```rust fn add_recipient<'cx, 'a, 'async_trait>( &'cx self, rcpt: impl 'async_trait + IntoCString + Send + 'a, ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, 'a: 'async_trait, ``` ```rust fn add_recipient_ext<'cx, 'a, 'b, 'async_trait>( &'cx self, rcpt: impl 'async_trait + IntoCString + Send + 'a, args: Option, ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, 'a: 'async_trait, 'b: 'async_trait, ``` ```rust fn delete_recipient<'cx, 'a, 'async_trait>( &'cx self, rcpt: impl 'async_trait + IntoCString + Send + 'a, ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, 'a: 'async_trait, ``` ```rust fn replace_body<'cx, 'a, 'async_trait>( &'cx self, chunk: &'a [u8], ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, 'a: 'async_trait, ``` ```rust fn progress<'cx, 'async_trait>( &'cx self, ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, ``` ```rust fn quarantine<'cx, 'a, 'async_trait>( &'cx self, reason: impl 'async_trait + IntoCString + Send + 'a, ) -> Pin> + Send + 'async_trait>> where Self: 'async_trait, 'cx: 'async_trait, 'a: 'async_trait, ``` -------------------------------- ### Configure SMTP error reply Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.SmtpReply.html?search=std%3A%3Avec Method to set an SMTP error reply using a return code, extended code, and message. ```rust fn set_error_reply( &mut self, rcode: &str, xcode: Option<&str>, message: I, ) -> Result<(), SmtpReplyError> where I: IntoIterator, T: IntoCString, ``` -------------------------------- ### Define Version type alias Source: https://docs.rs/indymilter/0.3.0/indymilter/message/type.Version.html Represents the milter protocol version as a u32. ```rust pub type Version = u32; ``` -------------------------------- ### Reply Enum Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/message/reply/enum.Reply.html The complete definition of the Reply enum, including all variants and their associated fields. ```rust pub enum Reply { Show 18 variants AddRcpt { rcpt: CString, }, DeleteRcpt { rcpt: CString, }, AddRcptExt { rcpt: CString, args: Option, }, OptNeg { version: Version, actions: Actions, opts: ProtoOpts, macros: HashMap, }, Accept, ReplaceBody { chunk: Bytes, }, Continue, Discard, ChangeSender { mail: CString, args: Option, }, AddHeader { name: CString, value: CString, }, InsertHeader { index: i32, name: CString, value: CString, }, ChangeHeader { name: CString, index: i32, value: CString, }, Progress, Quarantine { reason: CString, }, Reject, Skip, Tempfail, ReplyCode { reply: CString, }, } ``` -------------------------------- ### EnvAddrPayload Struct Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/message/command/struct.EnvAddrPayload.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E The primary structure definition for EnvAddrPayload, containing a vector of CString arguments. ```rust pub struct EnvAddrPayload { pub args: Vec, } ``` -------------------------------- ### IntoCString Implementations Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.IntoCString.html?search=u32+-%3E+bool Implementations of the IntoCString trait for various foreign types. ```rust impl IntoCString for &CStr fn into_c_string(self) -> CString ``` ```rust impl IntoCString for &str fn into_c_string(self) -> CString ``` ```rust impl IntoCString for CString fn into_c_string(self) -> Self ``` ```rust impl IntoCString for String fn into_c_string(self) -> CString ``` -------------------------------- ### quarantine Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=std%3A%3Avec Quarantines the message. Requires Actions::QUARANTINE flag. ```APIDOC fn quarantine(reason: impl IntoCString) -> Future> ``` -------------------------------- ### add_header Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=std%3A%3Avec Adds a header to the message. Requires Actions::ADD_HEADER flag. ```APIDOC fn add_header(name: impl IntoCString, value: impl IntoCString) -> Future> ``` -------------------------------- ### Define Macros struct Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Macros.html The definition of the Macros struct. ```rust pub struct Macros(/* private fields */); ``` -------------------------------- ### Command Enum Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/message/command/enum.Command.html The Command enum lists all supported milter protocol commands as variants. ```rust pub enum Command { Show 15 variants Abort, BodyChunk(Bytes), ConnInfo(ConnInfoPayload), DefMacros(MacroPayload), BodyEnd(Bytes), Helo(HeloPayload), QuitNc, Header(HeaderPayload), Mail(EnvAddrPayload), Eoh, OptNeg(OptNegPayload), Quit, Rcpt(EnvAddrPayload), Data, Unknown(UnknownPayload), } ``` -------------------------------- ### fn into_c_string(self) -> CString Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.IntoCString.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Converts the implementing type into a CString. This method is required for all types implementing the IntoCString trait. ```APIDOC ## fn into_c_string(self) -> CString ### Description Converts the value into a CString. This is an infallible conversion. ### Signature `fn into_c_string(self) -> CString` ### Implementations - `&CStr` - `&str` - `CString` - `String` ``` -------------------------------- ### MacroStage::all_sorted_by_index Source: https://docs.rs/indymilter/0.3.0/indymilter/enum.MacroStage.html?search= Returns an iterator of all macro stages, sorted by their underlying index value. ```APIDOC ## pub fn all_sorted_by_index() -> impl DoubleEndedIterator ### Description Returns an iterator of all macro stages, sorted by their index value. ### Returns - **Iterator** (impl DoubleEndedIterator) - An iterator over all variants of the MacroStage enum, ordered by index. ``` -------------------------------- ### Macros::get Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Macros.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Retrieves the value associated with a specific macro name. Single-character macros can be looked up with or without braces. ```APIDOC ## fn get(&self, name: &CStr) -> Option<&CStr> ### Description Returns the value associated with the given macro name, if any. Single-character macros like `i` or `{i}` can be looked up in either form. ### Parameters - **name** (&CStr) - Required - The name of the macro to retrieve. ``` -------------------------------- ### HeaderPayload Struct Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/message/command/struct.HeaderPayload.html?search= The primary structure definition for HeaderPayload. ```rust pub struct HeaderPayload { pub name: CString, pub value: CString, } ``` -------------------------------- ### MacroPayload Struct Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/message/command/struct.MacroPayload.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E The structure definition for MacroPayload, containing the stage and macros fields. ```rust pub struct MacroPayload { pub stage: MacroStage, pub macros: Vec, } ``` -------------------------------- ### add_recipient_ext Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=std%3A%3Avec Adds an envelope recipient with ESMTP arguments. Requires Actions::ADD_RCPT_EXT flag. ```APIDOC fn add_recipient_ext(rcpt: impl IntoCString, args: Option) -> Future> ``` -------------------------------- ### replace_body Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=std%3A%3Avec Replaces the message body. Requires Actions::REPLACE_BODY flag. ```APIDOC fn replace_body(chunk: &[u8]) -> Future> ``` -------------------------------- ### byte() Source: https://docs.rs/indymilter/0.3.0/indymilter/message/struct.TryFromByteError.html Retrieves the byte that caused the conversion error. ```APIDOC ## pub fn byte(&self) -> u8 ### Description Returns the byte that caused the conversion error. ### Returns - **u8** - The byte value that triggered the error. ``` -------------------------------- ### parse_reply Source: https://docs.rs/indymilter/0.3.0/indymilter/message/reply/enum.Reply.html?search=std%3A%3Avec Parses a milter protocol message into a Reply instance. ```APIDOC ## pub fn parse_reply(msg: Message) -> Result ### Description Parses a reply from a milter protocol message. ### Parameters - **msg** (Message) - Required - The milter protocol message to parse. ### Returns - **Result** - Returns the parsed Reply instance or a ParseReplyError if parsing fails. ``` -------------------------------- ### change_header Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=std%3A%3Avec Replaces or deletes a header at a specific index. Requires Actions::CHANGE_HEADER flag. ```APIDOC fn change_header(name: impl IntoCString, index: i32, value: Option) -> Future> ``` -------------------------------- ### Context Struct Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Context.html The primary structure used to manage state and responses within an indymilter callback. ```rust pub struct Context { pub data: Option, pub macros: Macros, pub reply: SmtpReply, } ``` -------------------------------- ### set_error_reply Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.SmtpReply.html Configures an SMTP error reply for the current SmtpReply instance. ```APIDOC ## fn set_error_reply(&mut self, rcode: &str, xcode: Option<&str>, message: I) -> Result<(), SmtpReplyError> ### Description Configures an SMTP error reply. This method allows setting the SMTP return code, extended status code, and the associated message. ### Parameters - **rcode** (&str) - Required - The SMTP return code (e.g., "550"). - **xcode** (Option<&str>) - Required - The optional extended status code (e.g., "5.7.1"). - **message** (I) - Required - An iterator of messages to be sent as part of the reply. ### Returns - **Result<(), SmtpReplyError>** - Returns Ok(()) on success, or an SmtpReplyError if the configuration fails. ``` -------------------------------- ### Actions struct definition Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Actions.html The primary structure representing eom action flags. ```rust pub struct Actions(/* private fields */); ``` -------------------------------- ### insert_header Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=std%3A%3Avec Inserts a header at a specific index. Requires Actions::ADD_HEADER flag. ```APIDOC fn insert_header(index: i32, name: impl IntoCString, value: impl IntoCString) -> Future> ``` -------------------------------- ### Unsafe Pinning in Closures Source: https://docs.rs/indymilter/0.3.0/indymilter/type.CallbackFuture.html?search=u32+-%3E+bool Demonstrates the potential for undefined behavior when using Pin::new_unchecked on moved closure captures. ```rust use std::pin::Pin; use std::task::Context; use std::future::Future; fn move_pinned_closure(mut x: impl Future, cx: &mut Context<'_>) { // Create a closure that moves `x`, and then internally uses it in a pinned way. let mut closure = move || unsafe { let _ignore = Pin::new_unchecked(&mut x).poll(cx); }; // Call the closure, so the future can assume it has been pinned. closure(); // Move the closure somewhere else. This also moves `x`! let mut moved = closure; // Calling it again means we polled the future from two different locations, // violating the pinning API contract. moved(); // Potential UB ⚠️ } ``` -------------------------------- ### UnknownPayload Struct Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/message/command/struct.UnknownPayload.html The structure definition for UnknownPayload, which holds a CString argument. ```rust pub struct UnknownPayload { pub arg: CString, } ``` -------------------------------- ### Define TryFromByteError struct Source: https://docs.rs/indymilter/0.3.0/indymilter/message/struct.TryFromByteError.html?search= The definition of the TryFromByteError struct with private fields. ```rust pub struct TryFromByteError(/* private fields */); ``` -------------------------------- ### IntoCString Trait Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.IntoCString.html The core trait definition requiring the implementation of the into_c_string method. ```rust pub trait IntoCString { // Required method fn into_c_string(self) -> CString; } ``` -------------------------------- ### Define the Listener trait Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.Listener.html The core trait definition requiring an asynchronous I/O type and a poll_accept method. ```rust pub trait Listener { type Io: AsyncRead + AsyncWrite + Unpin + Send + 'static; // Required method fn poll_accept(&mut self, cx: &mut Context<'_>) -> Poll>; // Provided method fn accept(&mut self) -> ListenerAcceptFut<'_, Self> where Self: Sized { ... } } ``` -------------------------------- ### ReplyKind Enum Definition Source: https://docs.rs/indymilter/0.3.0/indymilter/message/reply/enum.ReplyKind.html?search= The enumeration of all possible reply kinds supported by the milter protocol. ```rust pub enum ReplyKind { Show 18 variants AddRcpt, DeleteRcpt, AddRcptExt, OptNeg, Accept, ReplaceBody, Continue, Discard, ChangeSender, AddHeader, InsertHeader, ChangeHeader, Progress, Quarantine, Reject, Skip, Tempfail, ReplyCode, } ``` -------------------------------- ### change_sender Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html Replaces the envelope sender. Requires the Actions::CHANGE_SENDER flag. ```APIDOC ## change_sender(mail, args) ### Description Replaces the envelope sender, with optional ESMTP arguments. This operation must be enabled with the `Actions::CHANGE_SENDER` flag. ### Parameters - **mail** (impl IntoCString) - The new sender address. - **args** (Option) - Optional ESMTP arguments. ### Returns - **Result<(), ActionError>** - Returns an empty result on success or an ActionError on failure. ``` -------------------------------- ### Write milter message signature Source: https://docs.rs/indymilter/0.3.0/indymilter/message/fn.write.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E The function requires a mutable reference to an AsyncWrite stream and a Message object. ```rust pub async fn write(stream: &mut S, msg: Message) -> Result<()> where S: AsyncWrite + Unpin, ``` -------------------------------- ### Write milter message to stream Source: https://docs.rs/indymilter/0.3.0/indymilter/message/fn.write.html Writes a milter protocol message to an asynchronous stream that implements AsyncWrite and Unpin. ```rust pub async fn write(stream: &mut S, msg: Message) -> Result<()> where S: AsyncWrite + Unpin, ``` -------------------------------- ### Define SmtpReply struct Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.SmtpReply.html?search= The definition of the SmtpReply struct with private fields. ```rust pub struct SmtpReply { /* private fields */ } ``` -------------------------------- ### change_sender Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=std%3A%3Avec Replaces the envelope sender with optional ESMTP arguments. Requires Actions::CHANGE_SENDER flag. ```APIDOC fn change_sender(mail: impl IntoCString, args: Option) -> Future> ``` -------------------------------- ### add_recipient Source: https://docs.rs/indymilter/0.3.0/indymilter/trait.ContextActions.html?search=std%3A%3Avec Adds an envelope recipient. Requires Actions::ADD_RCPT flag. ```APIDOC fn add_recipient(rcpt: impl IntoCString) -> Future> ``` -------------------------------- ### Retrieve macro value Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.Macros.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Look up a macro value by name. Single-character macros can be queried with or without curly braces. ```rust pub fn get(&self, name: &CStr) -> Option<&CStr> ``` -------------------------------- ### set_error_reply Source: https://docs.rs/indymilter/0.3.0/indymilter/struct.SmtpReply.html?search=std%3A%3Avec Configures an SMTP error reply for the current transaction. ```APIDOC ## fn set_error_reply(&mut self, rcode: &str, xcode: Option<&str>, message: I) -> Result<(), SmtpReplyError> ### Description Configures an SMTP error reply. This method allows setting the SMTP return code, an optional extended SMTP code, and a message body. ### Parameters - **rcode** (&str) - Required - The SMTP return code (e.g., "550"). - **xcode** (Option<&str>) - Required - The optional extended SMTP status code (e.g., "5.7.1"). - **message** (I) - Required - The error message, which must implement IntoIterator where items implement IntoCString. ### Returns - **Result<(), SmtpReplyError>** - Returns Ok(()) on success, or an SmtpReplyError if the configuration fails. ```