possible fix(imap): split connection and stream locks

This commit is contained in:
dignifiedquire
2019-07-16 10:57:21 +02:00
parent cdfc8c6fa7
commit c8290de628

View File

@@ -32,7 +32,8 @@ pub struct Imap {
precheck_imf: dc_precheck_imf_t, precheck_imf: dc_precheck_imf_t,
receive_imf: dc_receive_imf_t, receive_imf: dc_receive_imf_t,
session: Arc<Mutex<(Option<Session>, Option<net::TcpStream>)>>, session: Arc<Mutex<Option<Session>>>,
stream: Arc<RwLock<Option<net::TcpStream>>>,
connected: Arc<Mutex<bool>>, connected: Arc<Mutex<bool>>,
} }
@@ -350,7 +351,8 @@ impl Imap {
receive_imf: dc_receive_imf_t, receive_imf: dc_receive_imf_t,
) -> Self { ) -> Self {
Imap { Imap {
session: Arc::new(Mutex::new((None, None))), session: Arc::new(Mutex::new(None)),
stream: Arc::new(RwLock::new(None)),
config: Arc::new(RwLock::new(ImapConfig::default())), config: Arc::new(RwLock::new(ImapConfig::default())),
watch: Arc::new((Mutex::new(false), Condvar::new())), watch: Arc::new((Mutex::new(false), Condvar::new())),
get_config, get_config,
@@ -378,7 +380,7 @@ impl Imap {
self.unsetup_handle(context); self.unsetup_handle(context);
} }
if self.is_connected() && self.session.lock().unwrap().1.is_some() { if self.is_connected() && self.stream.read().unwrap().is_some() {
self.config.write().unwrap().should_reconnect = false; self.config.write().unwrap().should_reconnect = false;
return 1; return 1;
} }
@@ -453,7 +455,8 @@ impl Imap {
match login_res { match login_res {
Ok((session, stream)) => { Ok((session, stream)) => {
*self.session.lock().unwrap() = (Some(session), Some(stream)); *self.session.lock().unwrap() = Some(session);
*self.stream.write().unwrap() = Some(stream);
1 1
} }
Err((err, _)) => { Err((err, _)) => {
@@ -466,7 +469,7 @@ impl Imap {
} }
fn unsetup_handle(&self, context: &Context) { fn unsetup_handle(&self, context: &Context) {
let session = self.session.lock().unwrap().0.take(); let session = self.session.lock().unwrap().take();
if session.is_some() { if session.is_some() {
match session.unwrap().close() { match session.unwrap().close() {
Ok(_) => {} Ok(_) => {}
@@ -475,7 +478,7 @@ impl Imap {
} }
} }
} }
let stream = self.session.lock().unwrap().1.take(); let stream = self.stream.write().unwrap().take();
if stream.is_some() { if stream.is_some() {
match stream.unwrap().shutdown(net::Shutdown::Both) { match stream.unwrap().shutdown(net::Shutdown::Both) {
Ok(_) => {} Ok(_) => {}
@@ -537,7 +540,7 @@ impl Imap {
return 0; return 0;
} }
match self.session.lock().unwrap().0 { match &mut *self.session.lock().unwrap() {
Some(ref mut session) => { Some(ref mut session) => {
if let Ok(caps) = session.capabilities() { if let Ok(caps) = session.capabilities() {
let can_idle = caps.has("IDLE"); let can_idle = caps.has("IDLE");
@@ -615,7 +618,7 @@ impl Imap {
} }
fn select_folder<S: AsRef<str>>(&self, context: &Context, folder: Option<S>) -> usize { fn select_folder<S: AsRef<str>>(&self, context: &Context, folder: Option<S>) -> usize {
if self.session.lock().unwrap().0.is_none() { if self.session.lock().unwrap().is_none() {
let mut cfg = self.config.write().unwrap(); let mut cfg = self.config.write().unwrap();
cfg.selected_folder = None; cfg.selected_folder = None;
cfg.selected_folder_needs_expunge = false; cfg.selected_folder_needs_expunge = false;
@@ -639,7 +642,7 @@ impl Imap {
// A CLOSE-SELECT is considerably faster than an EXPUNGE-SELECT, see // A CLOSE-SELECT is considerably faster than an EXPUNGE-SELECT, see
// https://tools.ietf.org/html/rfc3501#section-6.4.2 // https://tools.ietf.org/html/rfc3501#section-6.4.2
if let Some(ref mut session) = self.session.lock().unwrap().0 { if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
match session.close() { match session.close() {
Ok(_) => {} Ok(_) => {}
Err(err) => { Err(err) => {
@@ -655,7 +658,7 @@ impl Imap {
// select new folder // select new folder
if let Some(ref folder) = folder { if let Some(ref folder) = folder {
if let Some(ref mut session) = self.session.lock().unwrap().0 { if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
match session.select(folder) { match session.select(folder) {
Ok(mailbox) => { Ok(mailbox) => {
let mut config = self.config.write().unwrap(); let mut config = self.config.write().unwrap();
@@ -761,7 +764,7 @@ impl Imap {
return 0; return 0;
} }
let list = if let Some(ref mut session) = self.session.lock().unwrap().0 { let list = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
// `FETCH <message sequence number> (UID)` // `FETCH <message sequence number> (UID)`
let set = format!("{}", mailbox.exists); let set = format!("{}", mailbox.exists);
match session.fetch(set, PREFETCH_FLAGS) { match session.fetch(set, PREFETCH_FLAGS) {
@@ -805,7 +808,7 @@ impl Imap {
let mut read_errors = 0; let mut read_errors = 0;
let mut new_last_seen_uid = 0; let mut new_last_seen_uid = 0;
let list = if let Some(ref mut session) = self.session.lock().unwrap().0 { let list = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
// fetch messages with larger UID than the last one seen // fetch messages with larger UID than the last one seen
// (`UID FETCH lastseenuid+1:*)`, see RFC 4549 // (`UID FETCH lastseenuid+1:*)`, see RFC 4549
let set = format!("{}:*", last_seen_uid + 1); let set = format!("{}:*", last_seen_uid + 1);
@@ -928,7 +931,7 @@ impl Imap {
let set = format!("{}", server_uid); let set = format!("{}", server_uid);
let msgs = if let Some(ref mut session) = self.session.lock().unwrap().0 { let msgs = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
match session.uid_fetch(set, BODY_FLAGS) { match session.uid_fetch(set, BODY_FLAGS) {
Ok(msgs) => msgs, Ok(msgs) => msgs,
Err(err) => { Err(err) => {
@@ -1027,7 +1030,7 @@ impl Imap {
std::thread::spawn(move || { std::thread::spawn(move || {
let &(ref lock, ref cvar) = &*v; let &(ref lock, ref cvar) = &*v;
if let Some(ref mut session) = session.lock().unwrap().0 { if let Some(ref mut session) = &mut *session.lock().unwrap() {
let mut idle = match session.idle() { let mut idle = match session.idle() {
Ok(idle) => idle, Ok(idle) => idle,
Err(err) => { Err(err) => {
@@ -1205,7 +1208,7 @@ impl Imap {
folder.as_ref() folder.as_ref()
); );
} else { } else {
let moved = if let Some(ref mut session) = self.session.lock().unwrap().0 { let moved = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
match session.uid_mv(&set, &dest_folder) { match session.uid_mv(&set, &dest_folder) {
Ok(_) => { Ok(_) => {
res = DC_SUCCESS; res = DC_SUCCESS;
@@ -1230,7 +1233,7 @@ impl Imap {
}; };
if !moved { if !moved {
let copied = if let Some(ref mut session) = self.session.lock().unwrap().0 { let copied = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
match session.uid_copy(&set, &dest_folder) { match session.uid_copy(&set, &dest_folder) {
Ok(_) => true, Ok(_) => true,
Err(err) => { Err(err) => {
@@ -1275,7 +1278,7 @@ impl Imap {
if server_uid == 0 { if server_uid == 0 {
return 0; return 0;
} }
if let Some(ref mut session) = self.session.lock().unwrap().0 { if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
let set = format!("{}", server_uid); let set = format!("{}", server_uid);
let query = format!("+FLAGS ({})", flag.as_ref()); let query = format!("+FLAGS ({})", flag.as_ref());
match session.uid_store(&set, &query) { match session.uid_store(&set, &query) {
@@ -1387,18 +1390,18 @@ impl Imap {
.expect("just selected folder"); .expect("just selected folder");
if can_create_flag { if can_create_flag {
let fetched_msgs = if let Some(ref mut session) = self.session.lock().unwrap().0 let fetched_msgs =
{ if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
match session.uid_fetch(set, FETCH_FLAGS) { match session.uid_fetch(set, FETCH_FLAGS) {
Ok(res) => Some(res), Ok(res) => Some(res),
Err(err) => { Err(err) => {
eprintln!("fetch error: {:?}", err); eprintln!("fetch error: {:?}", err);
None None
}
} }
} } else {
} else { unreachable!();
unreachable!(); };
};
if let Some(msgs) = fetched_msgs { if let Some(msgs) = fetched_msgs {
let flag_set = msgs let flag_set = msgs
@@ -1479,7 +1482,7 @@ impl Imap {
); );
} else { } else {
let set = format!("{}", server_uid); let set = format!("{}", server_uid);
if let Some(ref mut session) = self.session.lock().unwrap().0 { if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
match session.uid_fetch(set, PREFETCH_FLAGS) { match session.uid_fetch(set, PREFETCH_FLAGS) {
Ok(msgs) => { Ok(msgs) => {
if msgs.is_empty() if msgs.is_empty()
@@ -1561,7 +1564,7 @@ impl Imap {
if mvbox_folder.is_none() && 0 != (flags as usize & DC_CREATE_MVBOX) { if mvbox_folder.is_none() && 0 != (flags as usize & DC_CREATE_MVBOX) {
info!(context, 0, "Creating MVBOX-folder \"DeltaChat\"...",); info!(context, 0, "Creating MVBOX-folder \"DeltaChat\"...",);
if let Some(ref mut session) = self.session.lock().unwrap().0 { if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
match session.create("DeltaChat") { match session.create("DeltaChat") {
Ok(_) => { Ok(_) => {
mvbox_folder = Some("DeltaChat".into()); mvbox_folder = Some("DeltaChat".into());
@@ -1616,7 +1619,7 @@ impl Imap {
&self, &self,
context: &Context, context: &Context,
) -> Option<imap::types::ZeroCopy<Vec<imap::types::Name>>> { ) -> Option<imap::types::ZeroCopy<Vec<imap::types::Name>>> {
if let Some(ref mut session) = self.session.lock().unwrap().0 { if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
// TODO: use xlist when available // TODO: use xlist when available
match session.list(Some(""), Some("*")) { match session.list(Some(""), Some("*")) {
Ok(list) => { Ok(list) => {