use crate::{
api::{
EngineResult, {Context, SharedObject},
},
get_global,
};
use rhai::plugin::{
mem, Dynamic, FnAccess, FnNamespace, ImmutableString, Module, NativeCallContext,
PluginFunction, RhaiResult, TypeId,
};
use vsmtp_common::Address;
pub use envelop::*;
use vsmtp_delivery::Deliver;
use super::Server;
#[rhai::plugin::export_module]
mod envelop {
#[rhai_fn(name = "rw_mail_from", return_raw)]
pub fn rewrite_mail_from_envelop_str(
ncc: NativeCallContext,
new_addr: &str,
) -> EngineResult<()> {
super::rewrite_mail_from_envelop(&mut get_global!(ncc, ctx), new_addr)
}
#[doc(hidden)]
#[rhai_fn(name = "rw_mail_from", return_raw)]
pub fn rewrite_mail_from_envelop_obj(
ncc: NativeCallContext,
new_addr: SharedObject,
) -> EngineResult<()> {
super::rewrite_mail_from_envelop(&mut get_global!(ncc, ctx), &new_addr.to_string())
}
#[rhai_fn(name = "rw_rcpt", return_raw)]
pub fn rewrite_rcpt_str_str(
ncc: NativeCallContext,
old_addr: &str,
new_addr: &str,
) -> EngineResult<()> {
super::rewrite_rcpt(
&mut get_global!(ncc, ctx),
get_global!(ncc, srv),
old_addr,
new_addr,
)
}
#[doc(hidden)]
#[rhai_fn(name = "rw_rcpt", return_raw)]
pub fn rewrite_rcpt_obj_str(
ncc: NativeCallContext,
old_addr: SharedObject,
new_addr: &str,
) -> EngineResult<()> {
super::rewrite_rcpt(
&mut get_global!(ncc, ctx),
get_global!(ncc, srv),
&old_addr.to_string(),
new_addr,
)
}
#[doc(hidden)]
#[rhai_fn(name = "rw_rcpt", return_raw)]
pub fn rewrite_rcpt_str_obj(
ncc: NativeCallContext,
old_addr: &str,
new_addr: SharedObject,
) -> EngineResult<()> {
super::rewrite_rcpt(
&mut get_global!(ncc, ctx),
get_global!(ncc, srv),
old_addr,
&new_addr.to_string(),
)
}
#[doc(hidden)]
#[rhai_fn(name = "rw_rcpt", return_raw)]
pub fn rewrite_rcpt_obj_obj(
ncc: NativeCallContext,
old_addr: SharedObject,
new_addr: SharedObject,
) -> EngineResult<()> {
super::rewrite_rcpt(
&mut get_global!(ncc, ctx),
get_global!(ncc, srv),
&old_addr.to_string(),
&new_addr.to_string(),
)
}
#[rhai_fn(name = "add_rcpt", return_raw)]
pub fn add_rcpt_envelop_str(ncc: NativeCallContext, new_addr: &str) -> EngineResult<()> {
super::add_rcpt_envelop(&mut get_global!(ncc, ctx), get_global!(ncc, srv), new_addr)
}
#[doc(hidden)]
#[rhai_fn(name = "add_rcpt", return_raw)]
pub fn add_rcpt_envelop_obj(
ncc: NativeCallContext,
new_addr: SharedObject,
) -> EngineResult<()> {
super::add_rcpt_envelop(
&mut get_global!(ncc, ctx),
get_global!(ncc, srv),
&new_addr.to_string(),
)
}
#[rhai_fn(name = "bcc", return_raw)]
pub fn bcc_str(ncc: NativeCallContext, new_addr: &str) -> EngineResult<()> {
super::add_rcpt_envelop_str(ncc, new_addr)
}
#[doc(hidden)]
#[rhai_fn(name = "bcc", return_raw)]
pub fn bcc_obj(ncc: NativeCallContext, new_addr: SharedObject) -> EngineResult<()> {
super::add_rcpt_envelop_obj(ncc, new_addr)
}
#[rhai_fn(name = "rm_rcpt", return_raw)]
pub fn remove_rcpt_envelop_str(ncc: NativeCallContext, addr: &str) -> EngineResult<()> {
super::remove_rcpt_envelop(&mut get_global!(ncc, ctx), addr)
}
#[doc(hidden)]
#[rhai_fn(name = "rm_rcpt", return_raw)]
pub fn remove_rcpt_envelop_obj(ncc: NativeCallContext, addr: SharedObject) -> EngineResult<()> {
super::remove_rcpt_envelop(&mut get_global!(ncc, ctx), &addr.to_string())
}
}
fn rewrite_mail_from_envelop(context: &mut Context, new_addr: &str) -> EngineResult<()> {
vsl_guard_ok!(context.write())
.set_reverse_path(Some(vsl_conversion_ok!(
"address",
<Address as std::str::FromStr>::from_str(new_addr)
)))
.map_err(|e| e.to_string().into())
}
#[allow(clippy::needless_pass_by_value)]
fn rewrite_rcpt(
context: &mut Context,
srv: Server,
old_addr: &str,
new_addr: &str,
) -> EngineResult<()> {
let old_addr = vsl_conversion_ok!(
"address",
<Address as std::str::FromStr>::from_str(old_addr)
);
let new_addr = vsl_conversion_ok!(
"address",
<Address as std::str::FromStr>::from_str(new_addr)
);
let mut context = vsl_guard_ok!(context.write());
context
.remove_forward_path(&old_addr)
.map_err::<Box<rhai::EvalAltResult>, _>(|e| e.to_string().into())?;
context
.add_forward_path(
new_addr,
std::sync::Arc::new(Deliver::new(
srv.resolvers.get_resolver_root(),
srv.config.clone(),
)),
)
.map_err::<Box<rhai::EvalAltResult>, _>(|e| e.to_string().into())?;
Ok(())
}
#[allow(clippy::needless_pass_by_value)]
fn add_rcpt_envelop(context: &mut Context, srv: Server, new_addr: &str) -> EngineResult<()> {
let rcpt = vsl_conversion_ok!(
"address",
<Address as std::str::FromStr>::from_str(new_addr)
);
let mut guard = vsl_guard_ok!(context.write());
guard
.add_forward_path(
rcpt,
std::sync::Arc::new(Deliver::new(
srv.resolvers.get_resolver_root(),
srv.config.clone(),
)),
)
.map_err(|err| format!("failed to run `add_rcpt_envelop`: {err}").into())
}
fn remove_rcpt_envelop(context: &mut Context, addr: &str) -> EngineResult<()> {
let addr = vsl_conversion_ok!("address", <Address as std::str::FromStr>::from_str(addr));
vsl_guard_ok!(context.write())
.remove_forward_path(&addr)
.map_err::<Box<rhai::EvalAltResult>, _>(|e| e.to_string().into())?;
Ok(())
}