postfix_log_parser/events/
pickup.rs

1//! Pickup邮件拾取模块
2//!
3//! 处理Postfix pickup守护进程的事件,负责从maildrop目录拾取本地提交的邮件
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7
8/// Pickup邮件拾取事件
9///
10/// 记录pickup守护进程从maildrop目录拾取邮件的活动
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12pub struct PickupEvent {
13    /// 事件发生时间戳(UTC时间)
14    pub timestamp: DateTime<Utc>,
15
16    /// 进程ID(可选)
17    /// pickup进程的系统标识符
18    pub pid: Option<u32>,
19
20    /// 事件类型(配置警告或邮件拾取)
21    pub event_type: PickupEventType,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
25pub enum PickupEventType {
26    /// 配置覆盖警告
27    ConfigOverrideWarning {
28        file_path: String,
29        line_number: u32,
30        parameter_name: String,
31        parameter_value: String,
32    },
33    /// 邮件拾取事件
34    MailPickup {
35        queue_id: String,
36        uid: u32,
37        sender: String,
38    },
39}
40
41impl PickupEvent {
42    pub fn new(timestamp: DateTime<Utc>, pid: Option<u32>, event_type: PickupEventType) -> Self {
43        Self {
44            timestamp,
45            pid,
46            event_type,
47        }
48    }
49
50    /// 创建配置覆盖警告事件
51    pub fn config_override_warning(
52        timestamp: DateTime<Utc>,
53        pid: Option<u32>,
54        file_path: String,
55        line_number: u32,
56        parameter_name: String,
57        parameter_value: String,
58    ) -> Self {
59        Self::new(
60            timestamp,
61            pid,
62            PickupEventType::ConfigOverrideWarning {
63                file_path,
64                line_number,
65                parameter_name,
66                parameter_value,
67            },
68        )
69    }
70
71    /// 创建邮件拾取事件
72    pub fn mail_pickup(
73        timestamp: DateTime<Utc>,
74        pid: Option<u32>,
75        queue_id: String,
76        uid: u32,
77        sender: String,
78    ) -> Self {
79        Self::new(
80            timestamp,
81            pid,
82            PickupEventType::MailPickup {
83                queue_id,
84                uid,
85                sender,
86            },
87        )
88    }
89
90    /// 获取事件严重性
91    pub fn severity(&self) -> &'static str {
92        match &self.event_type {
93            PickupEventType::ConfigOverrideWarning { .. } => "warning",
94            PickupEventType::MailPickup { .. } => "info",
95        }
96    }
97
98    /// 获取参数名称(仅配置覆盖警告)
99    pub fn parameter_name(&self) -> Option<&str> {
100        match &self.event_type {
101            PickupEventType::ConfigOverrideWarning { parameter_name, .. } => Some(parameter_name),
102            _ => None,
103        }
104    }
105
106    /// 获取队列ID(仅邮件拾取事件)
107    pub fn queue_id(&self) -> Option<&str> {
108        match &self.event_type {
109            PickupEventType::MailPickup { queue_id, .. } => Some(queue_id),
110            _ => None,
111        }
112    }
113
114    /// 获取发件人(仅邮件拾取事件)
115    pub fn sender(&self) -> Option<&str> {
116        match &self.event_type {
117            PickupEventType::MailPickup { sender, .. } => Some(sender),
118            _ => None,
119        }
120    }
121
122    /// 获取UID(仅邮件拾取事件)
123    pub fn uid(&self) -> Option<u32> {
124        match &self.event_type {
125            PickupEventType::MailPickup { uid, .. } => Some(*uid),
126            _ => None,
127        }
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134    use chrono::Utc;
135
136    #[test]
137    fn test_config_override_warning_event() {
138        let timestamp = Utc::now();
139        let event = PickupEvent::config_override_warning(
140            timestamp,
141            Some(76),
142            "/etc/postfix/main.cf".to_string(),
143            820,
144            "smtpd_recipient_restrictions".to_string(),
145            "check_client_access pcre:/etc/postfix/filter_trusted".to_string(),
146        );
147
148        assert_eq!(event.timestamp, timestamp);
149        assert_eq!(event.pid, Some(76));
150        assert_eq!(event.severity(), "warning");
151        assert_eq!(event.parameter_name(), Some("smtpd_recipient_restrictions"));
152        assert_eq!(event.queue_id(), None);
153        assert_eq!(event.sender(), None);
154        assert_eq!(event.uid(), None);
155
156        match event.event_type {
157            PickupEventType::ConfigOverrideWarning {
158                file_path,
159                line_number,
160                parameter_name,
161                parameter_value,
162            } => {
163                assert_eq!(file_path, "/etc/postfix/main.cf");
164                assert_eq!(line_number, 820);
165                assert_eq!(parameter_name, "smtpd_recipient_restrictions");
166                assert!(parameter_value.contains("check_client_access"));
167            }
168            _ => panic!("Expected ConfigOverrideWarning"),
169        }
170    }
171
172    #[test]
173    fn test_mail_pickup_event() {
174        let timestamp = Utc::now();
175        let event = PickupEvent::mail_pickup(
176            timestamp,
177            Some(76),
178            "226751E20F00".to_string(),
179            0,
180            "<root>".to_string(),
181        );
182
183        assert_eq!(event.timestamp, timestamp);
184        assert_eq!(event.pid, Some(76));
185        assert_eq!(event.severity(), "info");
186        assert_eq!(event.parameter_name(), None);
187        assert_eq!(event.queue_id(), Some("226751E20F00"));
188        assert_eq!(event.sender(), Some("<root>"));
189        assert_eq!(event.uid(), Some(0));
190
191        match event.event_type {
192            PickupEventType::MailPickup {
193                queue_id,
194                uid,
195                sender,
196            } => {
197                assert_eq!(queue_id, "226751E20F00");
198                assert_eq!(uid, 0);
199                assert_eq!(sender, "<root>");
200            }
201            _ => panic!("Expected MailPickup"),
202        }
203    }
204
205    #[test]
206    fn test_event_equality() {
207        let timestamp = Utc::now();
208        let event1 = PickupEvent::config_override_warning(
209            timestamp,
210            Some(76),
211            "/etc/postfix/main.cf".to_string(),
212            806,
213            "smtpd_client_message_rate_limit".to_string(),
214            "0".to_string(),
215        );
216
217        let event2 = PickupEvent::config_override_warning(
218            timestamp,
219            Some(76),
220            "/etc/postfix/main.cf".to_string(),
221            806,
222            "smtpd_client_message_rate_limit".to_string(),
223            "0".to_string(),
224        );
225
226        assert_eq!(event1, event2);
227    }
228}