use imap::error::Result;
use imap::Session;
use std::{thread, time};
use super::config::Config;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum Secure {
No(u16),
Yes(u16),
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Email {
server: String,
user: String,
password: String,
#[serde(default = "Email::default_secure")]
secure: Secure,
#[serde(default = "Email::default_retry_max_count")]
retry_max_count: u8,
#[serde(default = "Email::default_retry_delay")]
retry_delay: u64,
}
#[derive(Debug)]
pub enum Imap {
Secured(Session<native_tls::TlsStream<std::net::TcpStream>>),
Insecured(Session<std::net::TcpStream>),
}
impl Imap {
pub fn append<S: AsRef<str>, B: AsRef<[u8]>>(&mut self, mailbox: S, content: B) -> Result<()> {
match self {
Imap::Secured(ref mut session) => session.append(mailbox, content),
Imap::Insecured(ref mut session) => session.append(mailbox, content),
}
}
}
impl Email {
pub fn append<S: AsRef<str>, B: AsRef<[u8]>>(&self, mailbox: &S, content: &B) -> Result<()> {
let mut count = 0;
loop {
count = count + 1;
let mut imap = self.start();
let result = imap.append(mailbox, content);
if result.is_err() {
if count > self.retry_max_count {
return result;
} else {
error!(
"Previous append attempt failed with {}. Retrying ({}/{})in {} s.!",
result.unwrap_err(),
count,
self.retry_max_count,
self.retry_delay
);
thread::sleep(time::Duration::from_secs(self.retry_delay));
}
} else {
return result;
}
}
}
pub fn default_secure() -> Secure {
Secure::Yes(993)
}
pub fn default_retry_max_count() -> u8 {
3
}
pub fn default_retry_delay() -> u64 {
1
}
pub fn default() -> Email {
Email {
server: "Set your email server address here".to_owned(),
user: "Set your imap server user name (it may be your email address or not)".to_owned(),
password: "Set your imap server password (yup, in clear, this is very bad)".to_owned(),
secure: Email::default_secure(),
retry_max_count: Email::default_retry_max_count(),
retry_delay: Email::default_retry_delay(),
}
}
pub fn start(&self) -> Imap {
match self.secure {
Secure::Yes(port) => self.start_secure(port),
Secure::No(port) => self.start_insecure(port),
}
}
fn start_insecure(&self, port: u16) -> Imap {
let client = imap::connect_insecure((self.server.as_str(), port))
.unwrap_or_else(|_| panic!("Couldn't connect to {}:{}", self.server, port));
let imap_session = client
.login(&self.user, &self.password)
.unwrap_or_else(|_| {
panic!(
"Couldn't isnecurely connect to {}:{} for login {}",
self.server, port, self.user
)
});
debug!(
"Successfully connected to INSECURE imap server {}",
self.server
);
Imap::Insecured(imap_session)
}
fn start_secure(&self, port: u16) -> Imap {
let tls = native_tls::TlsConnector::builder()
.build()
.expect("Couldn't create TLS connector");
let client = imap::connect((self.server.as_str(), port), &self.server, &tls)
.unwrap_or_else(|_| panic!("Couldn't connect to {}:{}", self.server, port));
let imap_session = client
.login(&self.user, &self.password)
.unwrap_or_else(|_| {
panic!(
"Couldn't securely connect to {}:{} for login {}",
self.server, port, self.user
)
});
debug!(
"Successfully connected to SECURE imap server {}",
self.server
);
Imap::Secured(imap_session)
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Settings {
#[serde(
skip_serializing_if = "Settings::is_false",
default = "Settings::default_false"
)]
pub do_not_save: bool,
#[serde(default = "Email::default")]
pub email: Email,
#[serde(default = )]
pub config: Config,
}
impl Settings {
pub fn is_false(value: &bool) -> bool {
!value
}
pub fn default_false() -> bool {
false
}
pub fn default() -> Settings {
Settings {
do_not_save: false,
email: Email::default(),
config: Config::new(),
}
}
}