use ipnetwork::IpNetworkError;
#[derive(Debug, PartialEq)]
pub enum SpfError {
InvalidSource,
SourceLengthExceeded,
LookupLimitExceeded,
HasNotBeenParsed,
WhiteSpaceSyntaxError,
InvalidSPF,
RedirectWithAllMechanism,
InvalidIPAddr(IpNetworkError),
}
impl std::fmt::Display for SpfError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SpfError::InvalidSource => write!(f, "Source string not valid."),
SpfError::SourceLengthExceeded => write!(f, "Spf record exceeds 255 characters."),
SpfError::LookupLimitExceeded => write!(f, "Too many DNS lookups."),
SpfError::HasNotBeenParsed => write!(f, "Source string has not been parsed."),
SpfError::WhiteSpaceSyntaxError => {
write!(
f,
"Spf contains two or more consecutive whitespace characters."
)
}
SpfError::InvalidSPF => write!(f, "Spf record is invalid."),
SpfError::RedirectWithAllMechanism => {
write!(f, "Redirect with unexpected 'All' Mechanism")
}
SpfError::InvalidIPAddr(err) => write!(f, "{}", err),
}
}
}
impl From<IpNetworkError> for SpfError {
fn from(err: IpNetworkError) -> Self {
SpfError::InvalidIPAddr(err)
}
}
impl std::error::Error for SpfError {}
impl SpfError {
pub fn is_spf_error(&self) -> bool {
matches!(self, Self::InvalidSource)
|| matches!(self, Self::SourceLengthExceeded)
|| matches!(self, Self::LookupLimitExceeded)
|| matches!(self, Self::HasNotBeenParsed)
|| matches!(self, Self::InvalidSPF)
|| matches!(self, Self::RedirectWithAllMechanism)
|| matches!(self, Self::InvalidIPAddr(_))
}
pub fn is_invalid_source(&self) -> bool {
matches!(self, Self::InvalidSource)
}
pub fn source_is_invalid(&self) -> bool {
matches!(self, Self::InvalidSource)
}
pub fn is_source_length_exceeded(&self) -> bool {
matches!(self, Self::SourceLengthExceeded)
}
pub fn source_length_exceeded(&self) -> bool {
matches!(self, Self::SourceLengthExceeded)
}
pub fn is_lookup_limit_exceeded(&self) -> bool {
matches!(self, Self::LookupLimitExceeded)
}
pub fn lookup_limit_exceeded(&self) -> bool {
matches!(self, Self::LookupLimitExceeded)
}
pub fn is_has_not_been_parsed(&self) -> bool {
matches!(self, Self::HasNotBeenParsed)
}
pub fn has_not_been_parsed(&self) -> bool {
matches!(self, Self::HasNotBeenParsed)
}
pub fn is_invalid_spf(&self) -> bool {
matches!(self, Self::InvalidSPF)
}
pub fn is_redirect_with_all_mechanism(&self) -> bool {
matches!(self, Self::RedirectWithAllMechanism)
}
pub fn is_invalid_ip_addr(&self) -> bool {
matches!(self, Self::InvalidIPAddr(_))
}
}
#[test]
fn is_any_spf_error() {
let err = SpfError::InvalidSource;
assert_eq!(err.is_spf_error(), true);
}
#[test]
fn is_invalid_source() {
let err = SpfError::InvalidSource;
assert_eq!(err.is_invalid_source(), true);
}
#[test]
fn is_source_length_exceeded() {
let err = SpfError::SourceLengthExceeded;
assert_eq!(err.is_source_length_exceeded(), true);
}
#[test]
fn is_lookup_limit_exceeded() {
let err = SpfError::LookupLimitExceeded;
assert_eq!(err.is_lookup_limit_exceeded(), true)
}
#[test]
fn is_has_not_been_parsed() {
let err = SpfError::HasNotBeenParsed;
assert_eq!(err.is_has_not_been_parsed(), true)
}
#[test]
fn is_invalid_spf() {
let err = SpfError::InvalidSPF;
assert_eq!(err.is_invalid_spf(), true)
}
#[test]
fn is_redirect_with_all_mechanism() {
let err = SpfError::RedirectWithAllMechanism;
assert_eq!(err.is_redirect_with_all_mechanism(), true)
}
#[test]
fn is_invalid_ip_addr() {
let bad_ip = "203.32.160.0/33"
.parse::<ipnetwork::IpNetwork>()
.unwrap_err();
let err = SpfError::InvalidIPAddr(bad_ip);
assert_eq!(err.is_invalid_ip_addr(), true)
}