Helper traits in callbacks

This commit is contained in:
David Bürgin 2022-03-01 09:08:50 +01:00
parent 2335c8bd93
commit 3e8375efef
6 changed files with 32 additions and 31 deletions

View file

@ -15,7 +15,7 @@ The minimum supported Rust version is now 1.56.1.
- Use <code>inet:<em>host</em>:<em>port</em></code> for a TCP socket.
- Use <code>unix:<em>path</em></code> for a UNIX domain socket.
* The command-line help information has changed its appearance slightly with the
update of the underlying Clap CLI library.
update of the underlying clap CLI library.
* The changelog is now maintained in a more structured format, similar to
https://keepachangelog.com.

4
Cargo.lock generated
View file

@ -83,9 +83,9 @@ dependencies = [
[[package]]
name = "clap"
version = "3.1.0"
version = "3.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5f1fea81f183005ced9e59cdb01737ef2423956dac5a6d731b06b2ecfaa3467"
checksum = "5177fac1ab67102d8989464efd043c6ff44191b1557ec1ddd489b4f7e1447e77"
dependencies = [
"atty",
"bitflags",

View file

@ -54,6 +54,22 @@ impl ConnectionMut for Option<Connection> {
}
}
trait MacrosExt {
fn get_string(&self, name: &CStr) -> Option<Cow<'_, str>>;
fn queue_id(&self) -> Cow<'_, str>;
}
impl MacrosExt for Macros {
fn get_string(&self, name: &CStr) -> Option<Cow<'_, str>> {
self.get(name).map(|v| v.to_string_lossy())
}
fn queue_id(&self) -> Cow<'_, str> {
self.get_string(c_str!("i"))
.unwrap_or_else(|| "NONE".into())
}
}
pub fn make_callbacks(config: Config) -> Callbacks<Connection> {
let config = Arc::new(config);
let config_connect = config.clone();
@ -148,7 +164,7 @@ async fn handle_mail(
smtp_args: Vec<CString>,
) -> Status {
if !config.auth_untrusted() {
if let Some(login) = lookup(&context.macros, c_str!("{auth_authen}")) {
if let Some(login) = context.macros.get_string(c_str!("{auth_authen}")) {
verbose!(config, "accepted message from sender authenticated as \"{}\"", login);
return Status::Accept;
}
@ -179,7 +195,7 @@ async fn handle_data(context: &mut Context<Connection>) -> Status {
let conn = context.data.connection();
let client = conn.client.as_mut().unwrap();
let id = queue_id(&context.macros);
let id = context.macros.queue_id();
if let Err(e) = client.connect() {
eprintln!("{}: failed to start spamc: {}", id, e);
@ -196,11 +212,11 @@ async fn handle_data(context: &mut Context<Connection>) -> Status {
let info = ReceivedInfo {
client_ip: conn.client_ip,
helo_host: conn.helo_host.as_deref(),
client_name_addr: lookup(&context.macros, c_str!("_")),
my_hostname: lookup(&context.macros, c_str!("j")),
mta: lookup(&context.macros, c_str!("v")),
tls: lookup(&context.macros, c_str!("{tls_version}")),
auth: lookup(&context.macros, c_str!("{auth_authen}")),
client_name_addr: context.macros.get_string(c_str!("_")),
my_hostname: context.macros.get_string(c_str!("j")),
mta: context.macros.get_string(c_str!("v")),
tls: context.macros.get_string(c_str!("{tls_version}")),
auth: context.macros.get_string(c_str!("{auth_authen}")),
queue_id: &id,
date_time: Local::now().to_rfc2822(),
};
@ -243,7 +259,7 @@ async fn handle_body(
let max = config.max_message_size();
if client.bytes_written() > max {
let id = queue_id(&context.macros);
let id = context.macros.queue_id();
verbose!(config, "{}: skipping rest of message larger than {} bytes", id, max);
client.skip_body();
Status::Skip
@ -256,7 +272,7 @@ async fn handle_eom(config: Arc<Config>, context: &mut EomContext<Connection>) -
let conn = context.data.connection();
let client = conn.client.take().unwrap();
let id = queue_id(&context.macros);
let id = context.macros.queue_id();
match client.process(&id, &mut context.reply, &context.actions, &config).await {
Ok(status) => status,
@ -280,11 +296,3 @@ async fn handle_close(context: &mut Context<Connection>) -> Status {
Status::Continue
}
fn queue_id(macros: &Macros) -> Cow<'_, str> {
lookup(macros, c_str!("i")).unwrap_or_else(|| "NONE".into())
}
fn lookup<'a>(macros: &'a Macros, name: &CStr) -> Option<Cow<'a, str>> {
macros.get(name).map(|v| v.to_string_lossy())
}

View file

@ -500,7 +500,7 @@ mod tests {
async fn quarantine<'cx, 'a>(
&'cx self,
_reason: impl IntoCString + Send + 'a,
_: impl IntoCString + Send + 'a,
) -> result::Result<(), ActionError> {
unimplemented!()
}

View file

@ -95,8 +95,6 @@ async fn main() {
}
};
// Install a signal handler for the `TERM` and `INT` (Control-C) signals.
let (shutdown_tx, shutdown) = oneshot::channel();
let signals = Signals::new(&[SIGTERM, SIGINT]).expect("failed to install signal handler");
@ -301,7 +299,7 @@ async fn handle_signals(mut signals: Signals, shutdown_milter: oneshot::Sender<(
let _ = shutdown_milter.send(());
break;
}
_ => unreachable!(),
_ => panic!("unexpected signal"),
}
}
}

View file

@ -12,7 +12,7 @@ use tokio::{
net::{TcpListener, ToSocketAddrs},
process::Command,
sync::oneshot,
task::{self, JoinHandle},
task::JoinHandle,
time::timeout,
};
@ -46,8 +46,7 @@ where
Ok(tokio::spawn(async move {
// This server expects and handles only a single connection, so that we
// can `join` this thread in the tests and detect panics. A panic can be
// triggered both in the handling code as well as due to the timeout.
// can `join` this task in the tests and detect errors and panics.
let (mut stream, _) = timeout(Duration::from_secs(10), listener.accept())
.await
.map_err(|e| io::Error::new(ErrorKind::Other, e))??;
@ -129,10 +128,6 @@ impl SpamAssassinMilter {
}
pub async fn shutdown(self) -> io::Result<()> {
for _ in 0..10 {
task::yield_now().await;
}
let _ = self.shutdown.send(());
self.milter_handle.await?