1use crate::analyze::AnalyzeEmails;
2#[cfg(feature = "imap")]
3use crate::imap::Imap;
4#[cfg(feature = "pop3")]
5use crate::pop3::Pop3;
6#[cfg(feature = "smtp")]
7use crate::smtp::Smtp;
8use serde::{Deserialize, Serialize};
9use std::collections::BTreeMap;
10use std::io::Error;
11use std::path::PathBuf;
12use std::{fs, io};
13
14#[cfg(feature = "imap")]
15mod imap;
16#[cfg(feature = "pop3")]
17mod pop3;
18#[cfg(feature = "smtp")]
19mod smtp;
20
21pub mod analyze;
22pub mod pools;
23
24#[derive(Clone, Debug)]
25pub struct Mail {
26 protocol: Protocol,
28 host: String,
30 port: u16,
32 name: String,
34 mail: String,
36 pass: String,
38 email_type: EmailType,
40}
41
42impl Mail {
43 pub fn new_new(config: Config) -> Result<Self, String> {
44 let default = config.default.clone();
45 let connection = config
46 .connections
47 .get(&default)
48 .ok_or_else(|| format!("默认配置不存在: {default}"))?
49 .clone();
50 Ok(Self {
51 protocol: connection.protocol,
52 host: connection.host,
53 port: connection.port,
54 name: connection.name,
55 mail: connection.mail,
56 pass: connection.pass,
57 email_type: connection.email_type,
58 })
59 }
60 pub fn new(protocol: &str, host: &str, port: u16, name: &str, mail: &str, pass: &str) -> Self {
61 Self {
62 protocol: Protocol::from(protocol),
63 host: host.to_string(),
64 port,
65 name: name.to_string(),
66 mail: mail.to_string(),
67 pass: pass.to_string(),
68 email_type: EmailType::from(mail),
69 }
70 }
71 pub fn analyze(data: Vec<u8>, debug: bool) -> io::Result<AnalyzeEmails> {
73 AnalyzeEmails::new(data, debug)
74 }
75 pub fn receive(&mut self) -> Box<dyn Receive> {
77 match self.protocol {
78 #[cfg(feature = "pop3")]
79 Protocol::POP3 => Box::new(Pop3::new(
80 self.host.clone(),
81 self.port,
82 self.name.clone(),
83 self.mail.clone(),
84 self.pass.clone(),
85 self.email_type.clone(),
86 )),
87 #[cfg(feature = "smtp")]
88 Protocol::Smtp => Box::new(Smtp::new(
89 self.host.clone(),
90 self.port,
91 self.name.clone(),
92 self.mail.clone(),
93 self.pass.clone(),
94 self.email_type.clone(),
95 )),
96 #[cfg(feature = "imap")]
97 Protocol::Imap => Box::new(Imap::new(
98 self.host.clone(),
99 self.port,
100 self.name.clone(),
101 self.mail.clone(),
102 self.pass.clone(),
103 self.email_type.clone(),
104 )),
105 _ => Box::new(UnsupportedReceive {
106 protocol: self.protocol.clone(),
107 }),
108 }
109 }
110 pub fn sender(&mut self) -> Box<dyn Sender> {
112 match self.protocol {
113 #[cfg(feature = "pop3")]
114 Protocol::POP3 => Box::new(Pop3::new(
115 self.host.clone(),
116 self.port,
117 self.name.clone(),
118 self.mail.clone(),
119 self.pass.clone(),
120 self.email_type.clone(),
121 )),
122 #[cfg(feature = "smtp")]
123 Protocol::Smtp => Box::new(Smtp::new(
124 self.host.clone(),
125 self.port,
126 self.name.clone(),
127 self.mail.clone(),
128 self.pass.clone(),
129 self.email_type.clone(),
130 )),
131 #[cfg(feature = "imap")]
132 Protocol::Imap => Box::new(Imap::new(
133 self.host.clone(),
134 self.port,
135 self.name.clone(),
136 self.mail.clone(),
137 self.pass.clone(),
138 self.email_type.clone(),
139 )),
140 _ => Box::new(UnsupportedSender {
141 protocol: self.protocol.clone(),
142 }),
143 }
144 }
145}
146
147pub trait Receive {
148 fn get_total(&mut self) -> Result<usize, Error>;
150 fn get_id_list(&mut self) -> Result<Vec<String>, Error>;
152 fn get_id_info(&mut self, id: &str) -> Result<(Vec<u8>, usize, String), Error>;
155 fn del_id(&mut self, id: &str) -> Result<bool, Error>;
157
158 fn get_uid_list(&mut self) -> Result<Vec<String>, Error> {
162 self.get_id_list()
163 }
164
165 fn get_new_since(&mut self, _last_uid: &str) -> Result<Vec<String>, Error> {
169 Err(Error::other("此协议不支持增量查询"))
170 }
171
172 fn get_validity(&mut self) -> Result<Option<u64>, Error> {
176 Ok(None)
177 }
178
179 fn get_max_uid(&mut self) -> Result<Option<u64>, Error> {
181 Ok(None)
182 }
183
184 fn get_uidl_map(&mut self) -> Result<Vec<(String, String)>, Error> {
187 Err(Error::other("此协议不支持 UIDL"))
188 }
189}
190
191pub trait Sender {
192 fn send(&mut self) -> Result<(Vec<u8>, usize, String), Error>;
195
196 fn set_from(&mut self, name: &str) -> &mut dyn Sender;
200
201 fn set_to(&mut self, name: &str, mail: &str) -> &mut dyn Sender;
205 fn set_cc(&mut self, name: &str, mail: &str) -> &mut dyn Sender;
209 fn set_subject(&mut self, subject: &str) -> &mut dyn Sender;
211 fn set_body(&mut self, text: &str, html: &str) -> &mut dyn Sender;
213 fn set_file(&mut self, name: &str, data: Vec<u8>, content_type: &str) -> &mut dyn Sender;
215}
216
217struct UnsupportedReceive {
218 protocol: Protocol,
219}
220
221impl UnsupportedReceive {
222 fn err(&self, action: &str) -> Error {
223 Error::other(format!("{action} 不支持协议: {:?}", self.protocol))
224 }
225}
226
227impl Receive for UnsupportedReceive {
228 fn get_total(&mut self) -> Result<usize, Error> {
229 Err(self.err("获取邮件总数"))
230 }
231
232 fn get_id_list(&mut self) -> Result<Vec<String>, Error> {
233 Err(self.err("获取邮件ID列表"))
234 }
235
236 fn get_id_info(&mut self, _id: &str) -> Result<(Vec<u8>, usize, String), Error> {
237 Err(self.err("获取邮件内容"))
238 }
239
240 fn del_id(&mut self, _id: &str) -> Result<bool, Error> {
241 Err(self.err("删除邮件"))
242 }
243}
244
245struct UnsupportedSender {
246 protocol: Protocol,
247}
248
249impl UnsupportedSender {
250 fn err(&self, action: &str) -> Error {
251 Error::other(format!("{action} 不支持协议: {:?}", self.protocol))
252 }
253}
254
255impl Sender for UnsupportedSender {
256 fn send(&mut self) -> Result<(Vec<u8>, usize, String), Error> {
257 Err(self.err("发送邮件"))
258 }
259
260 fn set_from(&mut self, _name: &str) -> &mut dyn Sender {
261 self
262 }
263
264 fn set_to(&mut self, _name: &str, _mail: &str) -> &mut dyn Sender {
265 self
266 }
267
268 fn set_cc(&mut self, _name: &str, _mail: &str) -> &mut dyn Sender {
269 self
270 }
271
272 fn set_subject(&mut self, _subject: &str) -> &mut dyn Sender {
273 self
274 }
275
276 fn set_body(&mut self, _text: &str, _html: &str) -> &mut dyn Sender {
277 self
278 }
279
280 fn set_file(&mut self, _name: &str, _data: Vec<u8>, _content_type: &str) -> &mut dyn Sender {
281 self
282 }
283}
284
285#[derive(Clone, Debug, Deserialize, Serialize)]
286enum Protocol {
287 POP3,
288 Smtp,
289 Imap,
290 None,
291}
292
293impl Protocol {
294 pub fn from(name: &str) -> Self {
295 let name = name.to_lowercase();
296 match name.as_str() {
297 "pop3" => Protocol::POP3,
298 "imap" => Protocol::Imap,
299 "smtp" => Protocol::Smtp,
300 _ => Protocol::None,
301 }
302 }
303}
304
305#[derive(Clone, Debug, Deserialize, Serialize)]
306enum EmailType {
307 Google,
308 Qq,
309 None,
310}
311impl EmailType {
312 pub fn from(email: &str) -> Self {
313 match email {
314 x if x.contains("@gmail.com") => EmailType::Google,
315 x if x.contains("@qq.com") => EmailType::Qq,
316 _ => EmailType::None,
317 }
318 }
319}
320
321#[derive(Clone, Debug, Deserialize, Serialize)]
322pub struct Config {
323 default: String,
324 connections: BTreeMap<String, Connection>,
325}
326impl Default for Config {
327 fn default() -> Self {
328 Self::new()
329 }
330}
331
332impl Config {
333 pub fn create(config_file: PathBuf, pkg_name: bool) -> Config {
334 #[derive(Clone, Debug, Deserialize, Serialize)]
335 pub struct ConfigNew {
336 pub br_email: Config,
337 }
338 impl ConfigNew {
339 pub fn new() -> ConfigNew {
340 let mut connections = BTreeMap::new();
341 connections.insert("my_name".to_string(), Connection::default());
342 Self {
343 br_email: Config {
344 default: "my_name".to_string(),
345 connections,
346 },
347 }
348 }
349 }
350 match fs::read_to_string(config_file.clone()) {
351 Ok(e) => {
352 if pkg_name {
353 let data = ConfigNew::new();
354 toml::from_str::<ConfigNew>(&e)
355 .unwrap_or_else(|_| {
356 let toml = toml::to_string(&data).unwrap();
357 let toml = format!("{e}\r\n{toml}");
358 let _ = fs::write(config_file.to_str().unwrap(), toml);
359 data
360 })
361 .br_email
362 } else {
363 let data = Config::new();
364 toml::from_str::<Config>(&e).unwrap_or_else(|_| {
365 let toml = toml::to_string(&data).unwrap();
366 let toml = format!("{e}\r\n{toml}");
367 let _ = fs::write(config_file.to_str().unwrap(), toml);
368 data
369 })
370 }
371 }
372 Err(_) => {
373 if pkg_name {
374 let data = ConfigNew::new();
375 fs::create_dir_all(config_file.parent().unwrap()).unwrap();
376 let toml = toml::to_string(&data).unwrap();
377 let _ = fs::write(config_file.to_str().unwrap(), toml);
378 data.br_email
379 } else {
380 let data = Config::new();
381 fs::create_dir_all(config_file.parent().unwrap()).unwrap();
382 let toml = toml::to_string(&data).unwrap();
383 let _ = fs::write(config_file.to_str().unwrap(), toml);
384 data
385 }
386 }
387 }
388 }
389 pub fn new() -> Self {
390 let mut connections = BTreeMap::new();
391 connections.insert("my_name".to_string(), Connection::default());
392 Self {
393 default: "my_name".to_string(),
394 connections,
395 }
396 }
397}
398#[derive(Clone, Debug, Deserialize, Serialize)]
399struct Connection {
400 protocol: Protocol,
402 host: String,
404 port: u16,
406 name: String,
408 mail: String,
410 pass: String,
412 email_type: EmailType,
414}
415impl Connection {
416 pub fn default() -> Connection {
417 Self {
418 protocol: Protocol::Smtp,
419 host: "smtp.exmail.qq.com".to_string(),
420 port: 25,
421 name: "发件人名".to_string(),
422 mail: "xxx@qq.com".to_string(),
423 pass: "*******".to_string(),
424 email_type: EmailType::Qq,
425 }
426 }
427}