use std::io;
use async_trait::async_trait;
use thiserror::Error;
use miltr_common::{
actions::{Action, Continue},
commands::{Body, Connect, Header, Helo, Macro, Mail, Recipient, Unknown},
modifications::ModificationResponse,
optneg::OptNeg,
ProtocolError,
};
#[async_trait]
pub trait Milter: Send {
type Error: Send;
#[doc(alias = "SMFIC_OPTNEG")]
#[doc(alias = "xxfi_negotiate")]
async fn option_negotiation(&mut self, theirs: OptNeg) -> Result<OptNeg, Error<Self::Error>> {
let mut ours = OptNeg::default();
ours = ours
.merge_compatible(&theirs)
.map_err(ProtocolError::CompatibilityError)?;
Ok(ours)
}
#[doc(alias = "SMFIC_MACRO")]
async fn macro_(&mut self, _macro: Macro) -> Result<(), Self::Error> {
Ok(())
}
#[doc(alias = "SMFIC_CONNECT")]
#[doc(alias = "xxfi_connect")]
async fn connect(&mut self, _connect_info: Connect) -> Result<Action, Self::Error> {
Ok(Continue.into())
}
#[doc(alias = "SMFIC_HELO")]
#[doc(alias = "xxfi_helo")]
async fn helo(&mut self, _helo: Helo) -> Result<Action, Self::Error> {
Ok(Continue.into())
}
#[doc(alias = "SMFIC_MAIL")]
#[doc(alias = "from")]
#[doc(alias = "xxfi_envfrom")]
async fn mail(&mut self, _mail: Mail) -> Result<Action, Self::Error> {
Ok(Continue.into())
}
#[doc(alias = "SMFIC_RCPT")]
#[doc(alias = "to")]
#[doc(alias = "xxfi_envrcpt")]
async fn rcpt(&mut self, _recipient: Recipient) -> Result<Action, Self::Error> {
Ok(Continue.into())
}
#[doc(alias = "SMFIC_DATA")]
#[doc(alias = "xxfi_data")]
async fn data(&mut self) -> Result<Action, Self::Error> {
Ok(Continue.into())
}
#[doc(alias = "SMFIC_HEADER")]
#[doc(alias = "xxfi_header")]
async fn header(&mut self, _header: Header) -> Result<Action, Self::Error> {
Ok(Continue.into())
}
#[doc(alias = "SMFIC_EOH")]
#[doc(alias = "xxfi_eoh")]
async fn end_of_header(&mut self) -> Result<Action, Self::Error> {
Ok(Continue.into())
}
#[doc(alias = "SMFIC_BODY")]
#[doc(alias = "xxfi_body")]
async fn body(&mut self, _body: Body) -> Result<Action, Self::Error> {
Ok(Continue.into())
}
#[doc(alias = "SMFIC_BODYEOB")]
#[doc(alias = "xxfi_eom")]
async fn end_of_body(&mut self) -> Result<ModificationResponse, Self::Error> {
Ok(ModificationResponse::empty_continue())
}
#[doc(alias = "SMFIC_UNKNOWN")]
#[doc(alias = "xxfi_unknown")]
async fn unknown(&mut self, _cmd: Unknown) -> Result<Action, Self::Error> {
Ok(Continue.into())
}
#[doc(alias = "SMFIC_ABORT")]
#[doc(alias = "xxfi_abort")]
async fn abort(&mut self) -> Result<(), Self::Error>;
#[doc(alias = "SMFIC_QUIT")]
#[doc(alias = "xxfi_close")]
async fn quit(&mut self) -> Result<(), Self::Error> {
Ok(())
}
#[doc(alias = "SMFIC_QUIT_NC")]
async fn quit_nc(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug, Error)]
pub enum Error<ImplError> {
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Codec(#[from] ProtocolError),
#[error(transparent)]
Impl {
source: ImplError,
},
}
impl<AppError> Error<AppError> {
pub(crate) fn from_app_error(source: AppError) -> Self {
Self::Impl { source }
}
}