use crate::{config::Config, parse, print, resolver::Resolver, trace};
use std::{
error::Error,
io::{stderr, Write},
net::IpAddr,
};
use viaspf::{lookup::Lookup, trace::Trace, Sender};
type RunResult<T> = Result<T, RunError>;
#[derive(Debug)]
pub enum RunError {
Boxed(Box<dyn Error>),
Internal(&'static str), }
impl PartialEq for RunError {
fn eq(&self, _: &Self) -> bool {
false
}
}
impl From<Box<dyn Error>> for RunError {
fn from(error: Box<dyn Error>) -> Self {
Self::Boxed(error)
}
}
impl From<&'static str> for RunError {
fn from(error: &'static str) -> Self {
Self::Internal(error)
}
}
pub async fn run_trace(
config: Config,
sender: Sender,
ip: IpAddr,
lookup: Option<Box<dyn Lookup>>,
) -> RunResult<()> {
let trace = run_query(sender, ip, &config, lookup).await?;
process_trace(trace, &config)?;
Ok(())
}
async fn run_query(
sender: Sender,
ip: IpAddr,
config: &Config,
lookup: Option<Box<dyn Lookup>>,
) -> RunResult<Trace> {
let vconfig = to_viaspf_config(config);
let helo_domain = config.helo_domain.as_ref();
let result = match lookup {
Some(resolver) => {
viaspf::evaluate_sender(&resolver, &vconfig, ip, &sender, helo_domain).await
}
None => {
let resolver = if config.system_resolver {
Resolver::new_with_system_config(config.timeout)?
} else {
Resolver::new(config.timeout)
};
viaspf::evaluate_sender(&resolver, &vconfig, ip, &sender, helo_domain).await
}
};
let trace = result.trace.ok_or("trace not available")?;
Ok(trace)
}
fn to_viaspf_config(config: &Config) -> viaspf::Config {
let mut builder = viaspf::Config::builder().capture_trace(true);
if let Some(max_lookups) = config.max_lookups {
builder = builder.max_lookups(max_lookups);
}
if let Some(max_void_lookups) = config.max_void_lookups {
builder = builder.max_void_lookups(max_void_lookups);
}
if let Some(hostname) = &config.hostname {
builder = builder.hostname(hostname);
}
builder.build()
}
fn process_trace(trace: Trace, config: &Config) -> RunResult<()> {
let trace = trace::build_trace_tree(trace, config)?;
if config.debug {
writeln!(stderr(), "{:#?}", trace.query_trace).map_err(Box::from)?;
}
let query = parse::parse_evaluated_query(trace)?;
print::print_evaluated_query(query, config).map_err(Box::from)?;
Ok(())
}