1use std::collections::HashMap;
2use std::fmt::Debug;
3use std::io as std_io;
4use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
5
6use hostname::get_hostname;
7use native_tls::{self, TlsConnector as NativeTlsConnector, TlsConnectorBuilder};
8
9use crate::{
10 ascii::IgnoreAsciiCaseStr,
11 data_types::{AddressLiteral, Capability, Domain, EhloParam},
12};
13
14#[derive(Debug, Clone)]
28pub enum ClientId {
29 Domain(Domain),
31 AddressLiteral(AddressLiteral),
34}
35
36impl ClientId {
37 pub fn localhost() -> Self {
43 Self::from(Ipv4Addr::new(127, 0, 0, 1))
45 }
46
47 pub fn hostname() -> Self {
53 Self::try_hostname().unwrap_or_else(Self::localhost)
54 }
55
56 pub fn try_hostname() -> Option<Self> {
63 get_hostname().map(|name| {
64 let domain = Domain::new_unchecked(name);
66 ClientId::Domain(domain)
67 })
68 }
69}
70
71impl From<Domain> for ClientId {
72 fn from(dm: Domain) -> Self {
73 ClientId::Domain(dm)
74 }
75}
76
77impl From<AddressLiteral> for ClientId {
78 fn from(adl: AddressLiteral) -> Self {
79 ClientId::AddressLiteral(adl)
80 }
81}
82
83impl From<IpAddr> for ClientId {
84 fn from(saddr: IpAddr) -> Self {
85 let adl = AddressLiteral::from(saddr);
86 ClientId::from(adl)
87 }
88}
89
90impl From<Ipv4Addr> for ClientId {
91 fn from(saddr: Ipv4Addr) -> Self {
92 let adl = AddressLiteral::from(saddr);
93 ClientId::from(adl)
94 }
95}
96
97impl From<Ipv6Addr> for ClientId {
98 fn from(saddr: Ipv6Addr) -> Self {
99 let adl = AddressLiteral::from(saddr);
100 ClientId::from(adl)
101 }
102}
103
104#[derive(Debug, Clone, PartialEq)]
114pub struct TlsConfig<S = DefaultTlsSetup>
115where
116 S: SetupTls,
117{
118 pub domain: Domain,
120 pub setup: S,
122}
123
124impl From<Domain> for TlsConfig {
125 fn from(domain: Domain) -> Self {
126 TlsConfig {
127 domain,
128 setup: DefaultTlsSetup,
129 }
130 }
131}
132
133pub trait SetupTls: Debug + Send + 'static {
135 fn setup(self, builder: TlsConnectorBuilder) -> Result<NativeTlsConnector, native_tls::Error>;
137}
138
139#[derive(Debug, Clone, PartialEq)]
141pub struct DefaultTlsSetup;
142
143impl SetupTls for DefaultTlsSetup {
144 fn setup(self, builder: TlsConnectorBuilder) -> Result<NativeTlsConnector, native_tls::Error> {
145 builder.build()
146 }
147}
148
149impl<F: 'static> SetupTls for F
150where
151 F: Send + Debug + FnOnce(TlsConnectorBuilder) -> Result<NativeTlsConnector, native_tls::Error>,
152{
153 fn setup(self, builder: TlsConnectorBuilder) -> Result<NativeTlsConnector, native_tls::Error> {
154 (self)(builder)
155 }
156}
157
158macro_rules! alttry {
160 ($block:block => $emap:expr) => {{
161 let func = move || -> Result<_, _> { $block };
162 match func() {
163 Ok(ok) => ok,
164 Err(err) => {
165 #[allow(clippy::redundant_closure_call)]
166 return ($emap)(err);
167 }
168 }
169 }};
170}
171
172pub(crate) fn map_tls_err(err: native_tls::Error) -> std_io::Error {
173 std_io::Error::new(std_io::ErrorKind::Other, err)
174}
175
176#[derive(Debug, Clone)]
181pub struct EhloData {
182 domain: Domain,
183 data: HashMap<Capability, Vec<EhloParam>>,
184}
185
186impl EhloData {
187 pub fn new(domain: Domain, data: HashMap<Capability, Vec<EhloParam>>) -> Self {
190 EhloData { domain, data }
191 }
192
193 pub fn has_capability<A>(&self, cap: A) -> bool
195 where
196 A: AsRef<str>,
197 {
198 self.data
199 .contains_key(<&IgnoreAsciiCaseStr>::from(cap.as_ref()))
200 }
201
202 pub fn get_capability_params<A>(&self, cap: A) -> Option<&[EhloParam]>
204 where
205 A: AsRef<str>,
206 {
207 self.data
208 .get(<&IgnoreAsciiCaseStr>::from(cap.as_ref()))
209 .map(|vec| &**vec)
210 }
211
212 pub fn capability_map(&self) -> &HashMap<Capability, Vec<EhloParam>> {
214 &self.data
215 }
216
217 pub fn domain(&self) -> &Domain {
219 &self.domain
220 }
221}
222
223impl From<(Domain, HashMap<Capability, Vec<EhloParam>>)> for EhloData {
224 fn from((domain, map): (Domain, HashMap<Capability, Vec<EhloParam>>)) -> Self {
225 EhloData::new(domain, map)
226 }
227}
228
229impl Into<(Domain, HashMap<Capability, Vec<EhloParam>>)> for EhloData {
230 fn into(self) -> (Domain, HashMap<Capability, Vec<EhloParam>>) {
231 let EhloData { domain, data } = self;
232 (domain, data)
233 }
234}