summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2019-09-21 21:02:35 +0300
committerManos Pitsidianakis <el13635@mail.ntua.gr>2019-09-21 21:29:33 +0300
commitee82ae175a93957744659a68e1a7b78a49326e73 (patch)
tree3259d7d9ae9c12ea24065360e69cdd221dec68cf
parent9563007069122e5bbbadb8d1a8750a9eecf1f65a (diff)
imap: add support for imaps connections
Take port value and a `use_starttls` flag from the configuration file.
-rw-r--r--melib/src/backends/imap.rs56
-rw-r--r--melib/src/backends/imap/connection.rs136
2 files changed, 74 insertions, 118 deletions
diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs
index 0a5173a4..74cc7937 100644
--- a/melib/src/backends/imap.rs
+++ b/melib/src/backends/imap.rs
@@ -55,15 +55,22 @@ pub struct EnvelopeCache {
flags: Option<Flag>,
}
+#[derive(Debug, Clone)]
+pub struct ImapServerConf {
+ pub server_hostname: String,
+ pub server_username: String,
+ pub server_password: String,
+ pub server_port: u16,
+ pub use_starttls: bool,
+ pub danger_accept_invalid_certs: bool,
+}
+
type Capabilities = FnvHashSet<Vec<u8>>;
#[derive(Debug)]
pub struct ImapType {
account_name: String,
- server_hostname: String,
- server_username: String,
- server_password: String,
- danger_accept_invalid_certs: bool,
connection: Arc<Mutex<ImapConnection>>,
+ server_conf: ImapServerConf,
folders: FnvHashMap<FolderHash, ImapFolder>,
hash_index: Arc<Mutex<FnvHashMap<EnvelopeHash, (UID, FolderHash)>>>,
@@ -180,12 +187,7 @@ impl MailBackend for ImapType {
.capabilities
.contains(&b"IDLE"[0..]);
let folders = self.folders.clone();
- let conn = ImapConnection::new_connection(
- self.server_hostname.clone(),
- self.server_username.clone(),
- self.server_password.clone(),
- self.danger_accept_invalid_certs,
- );
+ let conn = ImapConnection::new_connection(&self.server_conf);
let main_conn = self.connection.clone();
let hash_index = self.hash_index.clone();
let uid_index = self.uid_index.clone();
@@ -394,23 +396,32 @@ impl ImapType {
let server_hostname = get_conf_val!(s["server_hostname"]);
let server_username = get_conf_val!(s["server_username"]);
let server_password = get_conf_val!(s["server_password"]);
+ let server_port = get_conf_val!(s["server_port"], 143);
+ let use_starttls = get_conf_val!(s["use_starttls"], {
+ if server_port == 993 {
+ false
+ } else {
+ true
+ }
+ });
let danger_accept_invalid_certs: bool =
get_conf_val!(s["danger_accept_invalid_certs"], false);
- let connection = ImapConnection::new_connection(
- server_hostname.to_string(),
- server_username.to_string(),
- server_password.to_string(),
+ let server_conf = ImapServerConf {
+ server_hostname: server_hostname.to_string(),
+ server_username: server_username.to_string(),
+ server_password: server_password.to_string(),
+ server_port,
+ use_starttls,
danger_accept_invalid_certs,
- );
+ };
+ let connection = ImapConnection::new_connection(&server_conf);
let mut m = ImapType {
account_name: s.name().to_string(),
- server_hostname: get_conf_val!(s["server_hostname"]).to_string(),
- server_username: get_conf_val!(s["server_username"]).to_string(),
- server_password: get_conf_val!(s["server_password"]).to_string(),
+ server_conf,
+
folders: Default::default(),
connection: Arc::new(Mutex::new(connection)),
- danger_accept_invalid_certs,
hash_index: Default::default(),
uid_index: Default::default(),
byte_cache: Default::default(),
@@ -430,12 +441,7 @@ impl ImapType {
}
pub fn shell(&mut self) {
- let mut conn = ImapConnection::new_connection(
- self.server_hostname.clone(),
- self.server_username.clone(),
- self.server_password.clone(),
- self.danger_accept_invalid_certs,
- );
+ let mut conn = ImapConnection::new_connection(&self.server_conf);
let mut res = String::with_capacity(8 * 1024);
conn.read_response(&mut res).unwrap();
debug!("out: {}", &res);
diff --git a/melib/src/backends/imap/connection.rs b/melib/src/backends/imap/connection.rs
index 9144a764..6f087e3c 100644
--- a/melib/src/backends/imap/connection.rs
+++ b/melib/src/backends/imap/connection.rs
@@ -30,7 +30,7 @@ use std::iter::FromIterator;
use std::net::SocketAddr;
use super::protocol_parser;
-use super::Capabilities;
+use super::{Capabilities, ImapServerConf};
#[derive(Debug)]
pub struct ImapStream {
@@ -41,10 +41,7 @@ pub struct ImapStream {
#[derive(Debug)]
pub struct ImapConnection {
pub stream: Result<ImapStream>,
- server_hostname: String,
- server_username: String,
- server_password: String,
- danger_accept_invalid_certs: bool,
+ pub server_conf: ImapServerConf,
pub capabilities: Capabilities,
}
@@ -145,23 +142,18 @@ impl ImapStream {
Ok(())
}
- pub fn new_connection(
- server_hostname: &str,
- server_username: &str,
- server_password: &str,
- danger_accept_invalid_certs: bool,
- ) -> Result<(Capabilities, ImapStream)> {
+ pub fn new_connection(server_conf: &ImapServerConf) -> Result<(Capabilities, ImapStream)> {
use std::io::prelude::*;
use std::net::TcpStream;
- let path = &server_hostname;
+ let path = &server_conf.server_hostname;
let mut connector = TlsConnector::builder();
- if danger_accept_invalid_certs {
+ if server_conf.danger_accept_invalid_certs {
connector.danger_accept_invalid_certs(true);
}
let connector = connector.build()?;
- let addr = if let Ok(a) = lookup_ipv4(path, 143) {
+ let addr = if let Ok(a) = lookup_ipv4(path, server_conf.server_port) {
a
} else {
return Err(MeliError::new(format!(
@@ -172,33 +164,35 @@ impl ImapStream {
let mut socket = TcpStream::connect(&addr)?;
let cmd_id = 0;
- socket.write_all(format!("M{} STARTTLS\r\n", cmd_id).as_bytes())?;
-
- let mut buf = vec![0; 1024];
- let mut response = String::with_capacity(1024);
- let mut cap_flag = false;
- loop {
- let len = socket.read(&mut buf)?;
- response.push_str(unsafe { std::str::from_utf8_unchecked(&buf[0..len]) });
- if !cap_flag {
- if response.starts_with("* OK [CAPABILITY") {
- cap_flag = true;
- if let Some(pos) = response.as_bytes().find(b"\r\n") {
- response.drain(0..pos + 2);
+ if server_conf.use_starttls {
+ socket.write_all(format!("M{} STARTTLS\r\n", cmd_id).as_bytes())?;
+
+ let mut buf = vec![0; 1024];
+ let mut response = String::with_capacity(1024);
+ let mut cap_flag = false;
+ loop {
+ let len = socket.read(&mut buf)?;
+ response.push_str(unsafe { std::str::from_utf8_unchecked(&buf[0..len]) });
+ if !cap_flag {
+ if response.starts_with("* OK [CAPABILITY") {
+ cap_flag = true;
+ if let Some(pos) = response.as_bytes().find(b"\r\n") {
+ response.drain(0..pos + 2);
+ }
+ } else if response.starts_with("* OK ") && response.find("\r\n").is_some() {
+ if let Some(pos) = response.as_bytes().find(b"\r\n") {
+ response.drain(0..pos + 2);
+ }
}
- } else if response.starts_with("* OK ") && response.find("\r\n").is_some() {
+ } else if response.starts_with("* OK [CAPABILITY") {
if let Some(pos) = response.as_bytes().find(b"\r\n") {
response.drain(0..pos + 2);
}
}
- } else if response.starts_with("* OK [CAPABILITY") {
- if let Some(pos) = response.as_bytes().find(b"\r\n") {
- response.drain(0..pos + 2);
+ if cap_flag && response == "M0 OK Begin TLS negotiation now.\r\n" {
+ break;
}
}
- if cap_flag && response == "M0 OK Begin TLS negotiation now.\r\n" {
- break;
- }
}
socket
@@ -228,7 +222,11 @@ impl ImapStream {
};
let mut ret = ImapStream { cmd_id, stream };
ret.send_command(
- format!("LOGIN \"{}\" \"{}\"", &server_username, &server_password).as_bytes(),
+ format!(
+ "LOGIN \"{}\" \"{}\"",
+ &server_conf.server_username, &server_conf.server_password
+ )
+ .as_bytes(),
)?;
let mut res = String::with_capacity(8 * 1024);
ret.read_lines(&mut res, String::new())?;
@@ -240,18 +238,10 @@ impl ImapStream {
}
impl ImapConnection {
- pub fn new_connection(
- server_hostname: String,
- server_username: String,
- server_password: String,
- danger_accept_invalid_certs: bool,
- ) -> ImapConnection {
+ pub fn new_connection(server_conf: &ImapServerConf) -> ImapConnection {
ImapConnection {
stream: Err(MeliError::new("Offline".to_string())),
- server_hostname,
- server_username,
- server_password,
- danger_accept_invalid_certs,
+ server_conf: server_conf.clone(),
capabilities: Capabilities::default(),
}
}
@@ -260,12 +250,7 @@ impl ImapConnection {
if let Ok(ref mut stream) = self.stream {
return stream.read_response(ret);
}
- let (capabilities, mut stream) = ImapStream::new_connection(
- &self.server_hostname,
- &self.server_username,
- &self.server_password,
- self.danger_accept_invalid_certs,
- )?;
+ let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
let ret = stream.read_response(ret);
if ret.is_ok() {
self.stream = Ok(stream);
@@ -278,12 +263,7 @@ impl ImapConnection {
if let Ok(ref mut stream) = self.stream {
return stream.read_lines(ret, termination_string);
}
- let (capabilities, mut stream) = ImapStream::new_connection(
- &self.server_hostname,
- &self.server_username,
- &self.server_password,
- self.danger_accept_invalid_certs,
- )?;
+ let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
let ret = stream.read_lines(ret, termination_string);
if ret.is_ok() {
self.stream = Ok(stream);
@@ -296,12 +276,7 @@ impl ImapConnection {
if let Ok(ref mut stream) = self.stream {
return stream.wait_for_continuation_request();
}
- let (capabilities, mut stream) = ImapStream::new_connection(
- &self.server_hostname,
- &self.server_username,
- &self.server_password,
- self.danger_accept_invalid_certs,
- )?;
+ let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
let ret = stream.wait_for_continuation_request();
if ret.is_ok() {
self.stream = Ok(stream);
@@ -314,12 +289,7 @@ impl ImapConnection {
if let Ok(ref mut stream) = self.stream {
return stream.send_command(command);
}
- let (capabilities, mut stream) = ImapStream::new_connection(
- &self.server_hostname,
- &self.server_username,
- &self.server_password,
- self.danger_accept_invalid_certs,
- )?;
+ let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
let ret = stream.send_command(command);
if ret.is_ok() {
self.stream = Ok(stream);
@@ -332,12 +302,7 @@ impl ImapConnection {
if let Ok(ref mut stream) = self.stream {
return stream.send_literal(data);
}
- let (capabilities, mut stream) = ImapStream::new_connection(
- &self.server_hostname,
- &self.server_username,
- &self.server_password,
- self.danger_accept_invalid_certs,
- )?;
+ let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
let ret = stream.send_literal(data);
if ret.is_ok() {
self.stream = Ok(stream);
@@ -350,12 +315,7 @@ impl ImapConnection {
if let Ok(ref mut stream) = self.stream {
return stream.send_raw(raw);
}
- let (capabilities, mut stream) = ImapStream::new_connection(
- &self.server_hostname,
- &self.server_username,
- &self.server_password,
- self.danger_accept_invalid_certs,
- )?;
+ let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
let ret = stream.send_raw(raw);
if ret.is_ok() {
@@ -369,12 +329,7 @@ impl ImapConnection {
if let Ok(ref mut stream) = self.stream {
return stream.set_nonblocking(val);
}
- let (capabilities, mut stream) = ImapStream::new_connection(
- &self.server_hostname,
- &self.server_username,
- &self.server_password,
- self.danger_accept_invalid_certs,
- )?;
+ let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
let ret = stream.set_nonblocking(val);
if ret.is_ok() {
self.stream = Ok(stream);
@@ -423,12 +378,7 @@ impl Iterator for ImapBlockingConnection {
} = self;
loop {
if conn.stream.is_err() {
- if let Ok((_, stream)) = ImapStream::new_connection(
- &conn.server_hostname,
- &conn.server_username,
- &conn.server_password,
- conn.danger_accept_invalid_certs,
- ) {
+ if let Ok((_, stream)) = ImapStream::new_connection(&conn.server_conf) {
conn.stream = Ok(stream);
} else {
debug!(&conn.stream);