1use std::collections::BTreeMap;
2use std::{fs, io};
3use std::io::Error;
4use std::path::PathBuf;
5use serde::{Deserialize, Serialize};
6use crate::analyze::AnalyzeEmails;
7#[cfg(feature = "imap")]
8use crate::imap::Imap;
9#[cfg(feature = "pop3")]
10use crate::pop3::Pop3;
11#[cfg(feature = "smtp")]
12use crate::smtp::Smtp;
13
14#[cfg(feature = "pop3")]
15mod pop3;
16#[cfg(feature = "imap")]
17mod imap;
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 connection = config.connections.get(&*config.default).unwrap().clone();
45 Ok(Self {
46 protocol: connection.protocol,
47 host: connection.host,
48 port: connection.port,
49 name: connection.name,
50 mail: connection.mail,
51 pass: connection.pass,
52 email_type: connection.email_type,
53 })
54 }
55 pub fn new(protocol: &str, host: &str, port: u16, name: &str, mail: &str, pass: &str) -> Self {
56 Self {
57 protocol: Protocol::from(protocol),
58 host: host.to_string(),
59 port,
60 name: name.to_string(),
61 mail: mail.to_string(),
62 pass: pass.to_string(),
63 email_type: EmailType::from(mail),
64 }
65 }
66 pub fn analyze(data: Vec<u8>, debug: bool) -> io::Result<AnalyzeEmails> {
68 AnalyzeEmails::new(data, debug)
69 }
70 pub fn receive(&mut self) -> Box<dyn Receive> {
72 match self.protocol {
73 #[cfg(feature = "pop3")]
74 Protocol::POP3 => Box::new(Pop3::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
75 #[cfg(feature = "smtp")]
76 Protocol::Smtp => Box::new(Smtp::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
77 #[cfg(feature = "imap")]
78 Protocol::Imap => Box::new(Imap::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
79 _ => todo!()
80 }
81 }
82 pub fn sender(&mut self) -> Box<dyn Sender> {
84 match self.protocol {
85 #[cfg(feature = "pop3")]
86 Protocol::POP3 => Box::new(Pop3::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
87 #[cfg(feature = "smtp")]
88 Protocol::Smtp => Box::new(Smtp::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
89 #[cfg(feature = "imap")]
90 Protocol::Imap => Box::new(Imap::new(self.host.clone(), self.port, self.name.clone(), self.mail.clone(), self.pass.clone(), self.email_type.clone())),
91 _ => todo!()
92 }
93 }
94}
95
96pub trait Receive {
97 fn get_total(&mut self) -> Result<usize, Error>;
99 fn get_id_list(&mut self) -> Result<Vec<String>, Error>;
101 fn get_id_info(&mut self, id: &str) -> Result<(Vec<u8>, usize, String), Error>;
104 fn del_id(&mut self, id: &str) -> Result<bool, Error>;
106}
107
108pub trait Sender {
109 fn send(&mut self) -> Result<(Vec<u8>, usize, String), Error>;
112
113 fn set_from(&mut self, name: &str) -> &mut dyn Sender;
117
118 fn set_to(&mut self, name: &str, mail: &str) -> &mut dyn Sender;
122 fn set_cc(&mut self, name: &str, mail: &str) -> &mut dyn Sender;
126 fn set_subject(&mut self, subject: &str) -> &mut dyn Sender;
128 fn set_body(&mut self, text: &str, html: &str) -> &mut dyn Sender;
130 fn set_file(&mut self, name: &str, data: Vec<u8>, content_type: &str) -> &mut dyn Sender;
132}
133
134#[derive(Clone, Debug, Deserialize, Serialize)]
135enum Protocol {
136 POP3,
137 Smtp,
138 Imap,
139 None,
140}
141
142impl Protocol {
143 pub fn from(name: &str) -> Self {
144 let name = name.to_lowercase();
145 match name.as_str() {
146 "pop3" => Protocol::POP3,
147 "imap" => Protocol::Imap,
148 "smtp" => Protocol::Smtp,
149 _ => Protocol::None,
150 }
151 }
152}
153
154#[derive(Clone, Debug, Deserialize, Serialize)]
155enum EmailType {
156 Google,
157 Qq,
158 None,
159}
160impl EmailType {
161 pub fn from(email: &str) -> Self {
162 match email {
163 x if x.contains("@gmail.com") => EmailType::Google,
164 x if x.contains("@qq.com") => EmailType::Qq,
165 _ => EmailType::None,
166 }
167 }
168}
169
170#[derive(Clone, Debug, Deserialize, Serialize)]
171pub struct Config {
172 default: String,
173 connections: BTreeMap<String, Connection>,
174}
175impl Default for Config {
176 fn default() -> Self {
177 Self::new()
178 }
179}
180
181impl Config {
182 pub fn create(config_file: PathBuf, pkg_name: bool) -> Config {
183 #[derive(Clone, Debug, Deserialize, Serialize)]
184 pub struct ConfigNew {
185 pub br_email: Config,
186 }
187 impl ConfigNew {
188 pub fn new() -> ConfigNew {
189 let mut connections = BTreeMap::new();
190 connections.insert("my_name".to_string(), Connection::default());
191 Self {
192 br_email: Config {
193 default: "my_name".to_string(),
194 connections,
195 },
196 }
197 }
198 }
199 match fs::read_to_string(config_file.clone()) {
200 Ok(e) => {
201 if pkg_name {
202 let data = ConfigNew::new();
203 toml::from_str::<ConfigNew>(&e).unwrap_or_else(|_| {
204 let toml = toml::to_string(&data).unwrap();
205 let toml = format!("{e}\r\n{toml}");
206 let _ = fs::write(config_file.to_str().unwrap(), toml);
207 data
208 }).br_email
209 } else {
210 let data = Config::new();
211 toml::from_str::<Config>(&e).unwrap_or_else(|_| {
212 let toml = toml::to_string(&data).unwrap();
213 let toml = format!("{e}\r\n{toml}");
214 let _ = fs::write(config_file.to_str().unwrap(), toml);
215 data
216 })
217 }
218 }
219 Err(_) => {
220 if pkg_name {
221 let data = ConfigNew::new();
222 fs::create_dir_all(config_file.parent().unwrap()).unwrap();
223 let toml = toml::to_string(&data).unwrap();
224 let _ = fs::write(config_file.to_str().unwrap(), toml);
225 data.br_email
226 } else {
227 let data = Config::new();
228 fs::create_dir_all(config_file.parent().unwrap()).unwrap();
229 let toml = toml::to_string(&data).unwrap();
230 let _ = fs::write(config_file.to_str().unwrap(), toml);
231 data
232 }
233 }
234 }
235 }
236 pub fn new() -> Self {
237 let mut connections = BTreeMap::new();
238 connections.insert("my_name".to_string(), Connection::default());
239 Self{
240 default: "my_name".to_string(),
241 connections,
242 }
243 }
244}
245#[derive(Clone, Debug, Deserialize, Serialize)]
246struct Connection {
247 protocol: Protocol,
249 host: String,
251 port: u16,
253 name: String,
255 mail: String,
257 pass: String,
259 email_type: EmailType,
261}
262impl Connection {
263 pub fn default() -> Connection {
264 Self {
265 protocol: Protocol::Smtp,
266 host: "smtp.exmail.qq.com".to_string(),
267 port: 25,
268 name: "发件人名".to_string(),
269 mail: "xxx@qq.com".to_string(),
270 pass: "*******".to_string(),
271 email_type: EmailType::Qq,
272 }
273 }
274}