melib: {create,delete}_folder returns updated folders

Potential parent folders will have their children fields updated, so
just return all folders.
memfd
Manos Pitsidianakis 2020-02-22 10:57:59 +02:00
parent 9a46e58029
commit f38d03e43a
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
6 changed files with 88 additions and 55 deletions

View File

@ -272,11 +272,17 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
unimplemented!() unimplemented!()
} }
fn create_folder(&mut self, _path: String) -> Result<Folder> { fn create_folder(
&mut self,
_path: String,
) -> Result<(FolderHash, FnvHashMap<FolderHash, Folder>)> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn delete_folder(&mut self, _folder_hash: FolderHash) -> Result<()> { fn delete_folder(
&mut self,
_folder_hash: FolderHash,
) -> Result<FnvHashMap<FolderHash, Folder>> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }

View File

@ -442,7 +442,10 @@ impl MailBackend for ImapType {
} }
} }
fn create_folder(&mut self, mut path: String) -> Result<Folder> { fn create_folder(
&mut self,
mut path: String,
) -> Result<(FolderHash, FnvHashMap<FolderHash, Folder>)> {
/* Must transform path to something the IMAP server will accept /* Must transform path to something the IMAP server will accept
* *
* Each root mailbox has a hierarchy delimeter reported by the LIST entry. All paths * Each root mailbox has a hierarchy delimeter reported by the LIST entry. All paths
@ -487,16 +490,13 @@ impl MailBackend for ImapType {
} }
let ret: Result<()> = ImapResponse::from(&response).into(); let ret: Result<()> = ImapResponse::from(&response).into();
ret?; ret?;
let new_hash = get_path_hash!(path.as_str());
folders.clear(); folders.clear();
drop(folders); drop(folders);
self.folders().map_err(|err| format!("Mailbox create was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err))?; Ok((new_hash, self.folders().map_err(|err| MeliError::new(format!("Mailbox create was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err)))?))
let new_hash = get_path_hash!(path.as_str());
Ok(BackendFolder::clone(
&self.folders.read().unwrap()[&new_hash],
))
} }
fn delete_folder(&mut self, folder_hash: FolderHash) -> Result<()> { fn delete_folder(&mut self, folder_hash: FolderHash) -> Result<FnvHashMap<FolderHash, Folder>> {
let mut folders = self.folders.write().unwrap(); let mut folders = self.folders.write().unwrap();
let permissions = folders[&folder_hash].permissions(); let permissions = folders[&folder_hash].permissions();
if !permissions.delete_mailbox { if !permissions.delete_mailbox {
@ -541,12 +541,10 @@ impl MailBackend for ImapType {
conn_lck.read_response(&mut response)?; conn_lck.read_response(&mut response)?;
} }
let ret: Result<()> = ImapResponse::from(&response).into(); let ret: Result<()> = ImapResponse::from(&response).into();
if ret.is_ok() { ret?;
folders.clear(); folders.clear();
drop(folders); drop(folders);
self.folders().map_err(|err| format!("Mailbox delete was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err))?; self.folders().map_err(|err| format!("Mailbox delete was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", response, err).into())
}
ret
} }
fn set_folder_subscription(&mut self, folder_hash: FolderHash, new_val: bool) -> Result<()> { fn set_folder_subscription(&mut self, folder_hash: FolderHash, new_val: bool) -> Result<()> {

View File

@ -636,7 +636,10 @@ impl MailBackend for MaildirType {
self self
} }
fn create_folder(&mut self, new_path: String) -> Result<Folder> { fn create_folder(
&mut self,
new_path: String,
) -> Result<(FolderHash, FnvHashMap<FolderHash, Folder>)> {
let mut path = self.path.clone(); let mut path = self.path.clone();
path.push(&new_path); path.push(&new_path);
if !path.starts_with(&self.path) { if !path.starts_with(&self.path) {
@ -655,6 +658,11 @@ impl MailBackend for MaildirType {
}); });
let folder_hash = get_path_hash!(&path); let folder_hash = get_path_hash!(&path);
if let Some(parent) = parent {
self.folders
.entry(parent)
.and_modify(|entry| entry.children.push(folder_hash));
}
let new_folder = MaildirFolder { let new_folder = MaildirFolder {
hash: folder_hash, hash: folder_hash,
path: PathBuf::from(&new_path), path: PathBuf::from(&new_path),
@ -669,12 +677,14 @@ impl MailBackend for MaildirType {
total: Default::default(), total: Default::default(),
}; };
let ret = BackendFolder::clone(debug!(&new_folder));
self.folders.insert(folder_hash, new_folder); self.folders.insert(folder_hash, new_folder);
Ok(ret) Ok((folder_hash, self.folders()?))
} }
fn delete_folder(&mut self, _folder_hash: FolderHash) -> Result<()> { fn delete_folder(
&mut self,
_folder_hash: FolderHash,
) -> Result<FnvHashMap<FolderHash, Folder>> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }

View File

@ -354,16 +354,12 @@ impl Collection {
self.message_ids self.message_ids
.insert(envelope.message_id().raw().to_vec(), hash); .insert(envelope.message_id().raw().to_vec(), hash);
self.envelopes.write().unwrap().insert(hash, envelope); self.envelopes.write().unwrap().insert(hash, envelope);
if !self self.threads
.threads
.entry(folder_hash) .entry(folder_hash)
.or_default() .or_default()
.insert_reply(&mut self.envelopes, hash) .insert(&mut self.envelopes, hash);
{ if self.sent_folder.map(|f| f == folder_hash).unwrap_or(false) {
self.threads self.insert_reply(hash);
.entry(folder_hash)
.or_default()
.insert(&mut self.envelopes, hash);
} }
} }

View File

@ -865,7 +865,7 @@ impl Account {
} }
match op { match op {
FolderOperation::Create(path) => { FolderOperation::Create(path) => {
let mut folder = self let (folder_hash, mut folders) = self
.backend .backend
.write() .write()
.unwrap() .unwrap()
@ -873,40 +873,51 @@ impl Account {
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxCreate(( .send(ThreadEvent::UIEvent(UIEvent::MailboxCreate((
self.index, self.index,
folder.hash(), folder_hash,
)))) ))))
.unwrap(); .unwrap();
let mut new = FileFolderConf::default(); let mut new = FileFolderConf::default();
new.folder_conf.subscribe = super::ToggleFlag::InternalVal(true); new.folder_conf.subscribe = super::ToggleFlag::InternalVal(true);
new.folder_conf.usage = if folder.special_usage() != SpecialUsageMailbox::Normal { new.folder_conf.usage =
Some(folder.special_usage()) if folders[&folder_hash].special_usage() != SpecialUsageMailbox::Normal {
} else { Some(folders[&folder_hash].special_usage())
let tmp = SpecialUsageMailbox::detect_usage(folder.name()); } else {
if tmp != Some(SpecialUsageMailbox::Normal) && tmp != None { let tmp = SpecialUsageMailbox::detect_usage(folders[&folder_hash].name());
let _ = folder.set_special_usage(tmp.unwrap()); if tmp != Some(SpecialUsageMailbox::Normal) && tmp != None {
} folders.entry(folder_hash).and_modify(|entry| {
tmp let _ = entry.set_special_usage(tmp.unwrap());
}; });
}
tmp
};
/* if new folder has parent, we need to update its children field */
if let Some(parent_hash) = folders[&folder_hash].parent() {
self.folder_entries.entry(parent_hash).and_modify(|parent| {
parent.ref_folder = folders.remove(&parent_hash).unwrap();
});
}
let folder_hash = folder.hash();
self.folder_entries.insert( self.folder_entries.insert(
folder_hash, folder_hash,
FolderEntry { FolderEntry {
name: folder.path().to_string(), name: folders[&folder_hash].path().to_string(),
status: MailboxStatus::Parsing(0, 0), status: MailboxStatus::Parsing(0, 0),
conf: new, conf: new,
worker: Account::new_worker( worker: Account::new_worker(
folder.clone(), folders[&folder_hash].clone(),
&mut self.backend, &mut self.backend,
&self.work_context, &self.work_context,
self.notify_fn.clone(), self.notify_fn.clone(),
), ),
ref_folder: folder, ref_folder: folders.remove(&folder_hash).unwrap(),
}, },
); );
self.collection self.collection
.threads .threads
.insert(folder_hash, Threads::default()); .insert(folder_hash, Threads::default());
self.collection
.mailboxes
.insert(folder_hash, Default::default());
build_folders_order( build_folders_order(
&mut self.tree, &mut self.tree,
&self.folder_entries, &self.folder_entries,
@ -927,7 +938,7 @@ impl Account {
} else { } else {
return Err(MeliError::new("Mailbox with that path not found.")); return Err(MeliError::new("Mailbox with that path not found."));
}; };
self.backend.write().unwrap().delete_folder(folder_hash)?; let mut folders = self.backend.write().unwrap().delete_folder(folder_hash)?;
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxDelete(( .send(ThreadEvent::UIEvent(UIEvent::MailboxDelete((
self.index, self.index,
@ -944,8 +955,24 @@ impl Account {
self.sent_folder = None; self.sent_folder = None;
} }
self.collection.threads.remove(&folder_hash); self.collection.threads.remove(&folder_hash);
/* if deleted folder had parent, we need to update its children field */
if let Some(parent_hash) = self
.folder_entries
.remove(&folder_hash)
.unwrap()
.ref_folder
.parent()
{
self.folder_entries.entry(parent_hash).and_modify(|parent| {
parent.ref_folder = folders.remove(&parent_hash).unwrap();
});
}
self.collection.mailboxes.remove(&folder_hash); self.collection.mailboxes.remove(&folder_hash);
self.folder_entries.remove(&folder_hash); build_folders_order(
&mut self.tree,
&self.folder_entries,
&mut self.folders_order,
);
// FIXME Kill worker as well // FIXME Kill worker as well
// FIXME remove from settings as well // FIXME remove from settings as well
@ -1063,7 +1090,6 @@ fn build_folders_order(
folder_entries: &FnvHashMap<FolderHash, FolderEntry>, folder_entries: &FnvHashMap<FolderHash, FolderEntry>,
folders_order: &mut Vec<FolderHash>, folders_order: &mut Vec<FolderHash>,
) { ) {
let mut stack: SmallVec<[FolderHash; 8]> = SmallVec::new();
tree.clear(); tree.clear();
folders_order.clear(); folders_order.clear();
for (h, f) in folder_entries.iter() { for (h, f) in folder_entries.iter() {
@ -1079,20 +1105,14 @@ fn build_folders_order(
depth, depth,
}; };
for &c in folder_entries[&h].ref_folder.children() { for &c in folder_entries[&h].ref_folder.children() {
node.children.push(rec(c, folder_entries, depth + 1)); if folder_entries.contains_key(&c) {
node.children.push(rec(c, folder_entries, depth + 1));
}
} }
node node
}; };
tree.push(rec(*h, &folder_entries, 0)); tree.push(rec(*h, &folder_entries, 0));
for &c in f.ref_folder.children() {
stack.push(c);
}
while let Some(next) = stack.pop() {
for c in folder_entries[&next].ref_folder.children() {
stack.push(*c);
}
}
} }
} }

View File

@ -213,7 +213,10 @@ impl MailBackend for PluginBackend {
fn save(&self, _bytes: &[u8], _folder: &str, _flags: Option<Flag>) -> Result<()> { fn save(&self, _bytes: &[u8], _folder: &str, _flags: Option<Flag>) -> Result<()> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn create_folder(&mut self, _name: String) -> Result<Folder> { fn create_folder(
&mut self,
_name: String,
) -> Result<(FolderHash, FnvHashMap<FolderHash, Folder>)> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> { fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> {