Initial commit

- rough filestructure
- first simplistic daemon
This commit is contained in:
malte
2025-11-06 11:38:20 +01:00
parent af8df2e62e
commit d843c08425
10 changed files with 1389 additions and 0 deletions
+173
View File
@@ -0,0 +1,173 @@
//
// Husk milter
//
// the actual daemon
//
use bytes::Bytes;
use std::ffi::CString;
use tokio::signal;
use tokio::net::TcpListener;
use indymilter::{
Actions,
Callbacks,
Context,
EomContext,
Macros,
NegotiateContext,
ProtoOpts,
SocketInfo,
Status,
Config,
ContextActions,
};
use crate::types::husk_context::HuskContext;
pub struct Daemon { }
impl Daemon {
pub async fn run() -> Result<(), ()> {
let listener = TcpListener::bind("localhost:3000")
.await
.expect(" opening milter socket");
let callbacks = Callbacks::new()
.on_negotiate(|cx, actions, opts| Box::pin(Self::handle_negotiate(cx, actions, opts)))
.on_connect(|cx, hostname, socket_info| Box::pin(Self::handle_connect(cx, hostname, socket_info)))
.on_helo(|cx, hostname| Box::pin(Self::handle_helo(cx, hostname)))
.on_mail(|cx, args| Box::pin(Self::handle_mail(cx, args)))
.on_rcpt(|cx, args| Box::pin(Self::handle_rcpt(cx, args)))
.on_data(|cx| Box::pin(Self::handle_data(cx)))
.on_header(|cx, name, value| Box::pin(Self::handle_header(cx, name, value)))
.on_eoh(|cx| Box::pin(Self::handle_eoh(cx)))
.on_body(|cx, chunk| Box::pin(Self::handle_body(cx, chunk)))
.on_eom(|cx| Box::pin(Self::handle_eom(cx)))
.on_abort(|cx| Box::pin(Self::handle_abort(cx)))
.on_close(|cx| Box::pin(Self::handle_close(cx)))
.on_unknown(|cx, arg| Box::pin(Self::handle_unknown(cx, arg)));
let config = Default::default();
indymilter::run(listener, callbacks, config, signal::ctrl_c())
.await
.expect("milter execution failed");
Ok(())
}
async fn handle_negotiate(
_cx: &mut NegotiateContext<HuskContext>,
actions: Actions,
opts: ProtoOpts,
) -> Status {
log::debug!("NEGOTIATE: actions: {actions:?} - opts: {opts:?}");
Status::AllOpts
}
async fn handle_connect(
_cx: &mut Context<HuskContext>,
hostname: CString,
socket_info: SocketInfo,
) -> Status {
log::debug!("CONNECT: hostname: {hostname:?} - socket_info: {socket_info:?}");
//Self::print_macros(&cx.macros);
Status::Continue
}
async fn handle_helo(_cx: &mut Context<HuskContext>, hostname: CString) -> Status {
log::debug!("HELO: hostname: {hostname:?}");
Status::Continue
}
async fn handle_mail(cx: &mut Context<HuskContext>, args: Vec<CString>) -> Status {
log::debug!("MAIL: {args:?}");
let sender = match args.first() {
Some(cs) => {
match cs.to_str() {
Ok(s) => s.to_string(),
_ => "corrupt".to_string()
}
},
None => { "missing".to_string() }
};
// setup Context
if let Some(mut context) = HuskContext::new() {
context.set_sender(sender);
cx.data = Some(context).take();
}
Status::Continue
}
async fn handle_rcpt(_cx: &mut Context<HuskContext>, args: Vec<CString>) -> Status {
log::debug!("RCPT: {args:?}");
Status::Continue
}
async fn handle_data(_cx: &mut Context<HuskContext>) -> Status {
log::debug!("DATA");
Status::Continue
}
async fn handle_header(_cx: &mut Context<HuskContext>, name: CString, value: CString) -> Status {
log::debug!("HEADER: {name:?} = {value:?}");
Status::Continue
}
async fn handle_eoh(_cx: &mut Context<HuskContext>) -> Status {
log::debug!("EOH");
Status::Continue
}
async fn handle_body(_cx: &mut Context<HuskContext>, chunk: Bytes) -> Status {
log::debug!("BODY: chunk with {:?} bytes received", &chunk.len());
Status::Continue
}
async fn handle_eom(cx: &mut EomContext<HuskContext>) -> Status {
log::debug!("EOM");
if let Some(ref mut context_data) = cx.data {
log::debug!("Mail from {:?} complete", context_data.sender);
}
Status::Continue
}
async fn handle_abort(_cx: &mut Context<HuskContext>) -> Status {
log::debug!("ABORT");
Status::Continue
}
async fn handle_close(_cx: &mut Context<HuskContext>) -> Status {
log::debug!("CLOSE");
Status::Continue
}
async fn handle_unknown(_cx: &mut Context<HuskContext>, arg: CString) -> Status {
log::debug!("UNKNOWN: {arg:?}");
Status::Continue
}
fn print_macros(macros: &Macros) {
println!(" macros: {:?}", macros.to_hash_map());
}
}