kumo_dmarc/types/
results.rs

1use crate::types::identifier::Identifier;
2use crate::types::policy::Policy;
3use crate::types::policy_override::PolicyOverrideReason;
4use instant_xml::{FromXml, ToXml};
5use kumo_spf::SpfDisposition;
6use serde::Serialize;
7use std::fmt;
8use std::net::IpAddr;
9
10#[derive(Debug, Eq, FromXml, PartialEq, ToXml)]
11#[xml(scalar, rename_all = "lowercase")]
12pub enum SpfScope {
13    Helo,
14    Mfrom,
15}
16
17#[derive(Debug, Eq, FromXml, PartialEq, ToXml)]
18#[xml(rename = "spf")]
19pub struct SpfAuthResult {
20    domain: String,
21    scope: SpfScope,
22    result: SpfDisposition,
23}
24
25#[derive(Debug, Eq, PartialEq, ToXml)]
26#[xml(rename = "auth_results")]
27pub struct AuthResults {
28    dkim: Vec<DkimAuthResult>,
29    spf: Vec<SpfAuthResult>,
30}
31
32#[derive(Debug, Eq, PartialEq, ToXml)]
33#[xml(rename = "record")]
34pub struct Results {
35    row: Row,
36    identifiers: Identifier,
37    auth_results: AuthResults,
38}
39
40#[derive(Debug, Eq, PartialEq, ToXml)]
41#[xml(scalar, rename_all = "lowercase")]
42pub enum DkimResult {
43    None,
44    Pass,
45    Fail,
46    Policy,
47    Neutral,
48    TempError,
49    PermError,
50}
51
52#[derive(Debug, Eq, PartialEq, ToXml)]
53pub struct DkimAuthResult {
54    domain: String,
55    selector: Option<String>,
56    result: DkimResult,
57    human_result: Option<String>,
58}
59
60#[derive(Debug, Eq, PartialEq, Clone, Copy, ToXml, Serialize)]
61#[xml(scalar, rename_all = "lowercase")]
62pub enum DmarcResult {
63    Pass,
64    Fail,
65}
66
67impl DmarcResult {
68    pub fn as_str(&self) -> &'static str {
69        match self {
70            Self::Pass => "pass",
71            Self::Fail => "fail",
72        }
73    }
74}
75
76impl fmt::Display for DmarcResult {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        write!(f, "{}", self.as_str())
79    }
80}
81
82// A coverage of both success and various failure modes
83#[derive(Debug, Eq, PartialEq, ToXml, Serialize, Clone, Copy)]
84#[xml(scalar)]
85pub enum Disposition {
86    Pass,
87    None,
88    Quarantine,
89    Reject,
90    TempError,
91    PermError,
92}
93
94impl ToString for Disposition {
95    fn to_string(&self) -> String {
96        match self {
97            Disposition::None => "None".to_string(),
98            Disposition::Pass => "Pass".to_string(),
99            Disposition::Quarantine => "Quarantine".to_string(),
100            Disposition::Reject => "Reject".to_string(),
101            Disposition::TempError => "TempError".to_string(),
102            Disposition::PermError => "PermError".to_string(),
103        }
104    }
105}
106
107impl Into<Disposition> for Policy {
108    fn into(self) -> Disposition {
109        match self {
110            Policy::None => Disposition::None,
111            Policy::Quarantine => Disposition::Quarantine,
112            Policy::Reject => Disposition::Reject,
113        }
114    }
115}
116
117// A synthetic type to bundle the result with a reason
118#[derive(Debug, Eq, PartialEq, ToXml, Serialize)]
119#[xml(rename_all = "lowercase")]
120pub struct DispositionWithContext {
121    pub result: Disposition,
122    pub context: String,
123}
124
125#[derive(Debug, Eq, PartialEq, ToXml)]
126#[xml(rename = "policy_evaluated")]
127pub struct PolicyEvaluated {
128    disposition: Policy,
129    dkim: DmarcResult,
130    spf: DmarcResult,
131    reason: Vec<PolicyOverrideReason>,
132}
133
134#[derive(Debug, Eq, PartialEq, ToXml)]
135#[xml(rename = "row")]
136pub struct Row {
137    source_ip: IpAddr,
138    count: u64,
139    policy_evaluated: PolicyEvaluated,
140}