You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
7.8KB

  1. use super::*;
  2. use crate::backends::FolderHash;
  3. use std::collections::BTreeMap;
  4. use std::fs;
  5. use std::io;
  6. use std::ops::{Deref, DerefMut};
  7. use fnv::FnvHashMap;
  8. #[derive(Debug, Clone, Deserialize, Default, Serialize)]
  9. pub struct Collection {
  10. pub envelopes: FnvHashMap<EnvelopeHash, Envelope>,
  11. message_ids: FnvHashMap<Vec<u8>, EnvelopeHash>,
  12. date_index: BTreeMap<UnixTimestamp, EnvelopeHash>,
  13. subject_index: Option<BTreeMap<String, EnvelopeHash>>,
  14. pub threads: FnvHashMap<FolderHash, Threads>,
  15. sent_folder: Option<FolderHash>,
  16. }
  17. impl Drop for Collection {
  18. fn drop(&mut self) {
  19. let cache_dir: xdg::BaseDirectories =
  20. xdg::BaseDirectories::with_profile("meli", "threads".to_string()).unwrap();
  21. if let Ok(cached) = cache_dir.place_cache_file("threads") {
  22. /* place result in cache directory */
  23. let f = match fs::File::create(cached) {
  24. Ok(f) => f,
  25. Err(e) => {
  26. panic!("{}", e);
  27. }
  28. };
  29. let writer = io::BufWriter::new(f);
  30. bincode::serialize_into(writer, &self.threads).unwrap();
  31. }
  32. }
  33. }
  34. impl Collection {
  35. pub fn new(envelopes: FnvHashMap<EnvelopeHash, Envelope>) -> Collection {
  36. let date_index = BTreeMap::new();
  37. let subject_index = None;
  38. let message_ids = FnvHashMap::with_capacity_and_hasher(2048, Default::default());
  39. /* Scrap caching for now. When a cached threads file is loaded, we must remove/rehash the
  40. * thread nodes that shouldn't exist anymore (e.g. because their file moved from /new to
  41. * /cur, or it was deleted).
  42. */
  43. let threads = FnvHashMap::with_capacity_and_hasher(16, Default::default());
  44. Collection {
  45. envelopes,
  46. date_index,
  47. message_ids,
  48. subject_index,
  49. threads,
  50. sent_folder: None,
  51. }
  52. }
  53. pub fn len(&self) -> usize {
  54. self.envelopes.len()
  55. }
  56. pub fn is_empty(&self) -> bool {
  57. self.envelopes.is_empty()
  58. }
  59. pub fn remove(&mut self, envelope_hash: EnvelopeHash, folder_hash: FolderHash) {
  60. debug!("DEBUG: Removing {}", envelope_hash);
  61. self.envelopes.remove(&envelope_hash);
  62. self.threads
  63. .entry(folder_hash)
  64. .or_default()
  65. .remove(envelope_hash, &mut self.envelopes);
  66. }
  67. pub fn rename(
  68. &mut self,
  69. old_hash: EnvelopeHash,
  70. new_hash: EnvelopeHash,
  71. folder_hash: FolderHash,
  72. ) {
  73. if !self.envelopes.contains_key(&old_hash) {
  74. return;
  75. }
  76. let mut env = self.envelopes.remove(&old_hash).unwrap();
  77. env.set_hash(new_hash);
  78. self.message_ids
  79. .insert(env.message_id().raw().to_vec(), new_hash);
  80. self.envelopes.insert(new_hash, env);
  81. {
  82. if self
  83. .threads
  84. .entry(folder_hash)
  85. .or_default()
  86. .update_envelope(old_hash, new_hash, &self.envelopes)
  87. .is_ok()
  88. {
  89. return;
  90. }
  91. }
  92. /* envelope is not in threads, so insert it */
  93. let env = self.envelopes.entry(new_hash).or_default() as *mut Envelope;
  94. unsafe {
  95. self.threads
  96. .entry(folder_hash)
  97. .or_default()
  98. .insert(&mut (*env), &self.envelopes);
  99. }
  100. }
  101. pub fn merge(
  102. &mut self,
  103. mut envelopes: FnvHashMap<EnvelopeHash, Envelope>,
  104. folder_hash: FolderHash,
  105. mailbox: &mut Result<Mailbox>,
  106. sent_folder: Option<FolderHash>,
  107. ) {
  108. self.sent_folder = sent_folder;
  109. envelopes.retain(|&h, e| {
  110. if self.message_ids.contains_key(e.message_id().raw()) {
  111. /* skip duplicates until a better way to handle them is found. */
  112. //FIXME
  113. if let Ok(mailbox) = mailbox.as_mut() {
  114. mailbox.remove(h);
  115. }
  116. false
  117. } else {
  118. self.message_ids.insert(e.message_id().raw().to_vec(), h);
  119. true
  120. }
  121. });
  122. let mut new_threads = Threads::new(&mut envelopes);
  123. for (h, e) in envelopes {
  124. self.envelopes.insert(h, e);
  125. }
  126. let &mut Collection {
  127. ref mut threads,
  128. ref mut envelopes,
  129. ref sent_folder,
  130. ..
  131. } = self;
  132. for (t_fh, t) in threads.iter_mut() {
  133. if sent_folder.map(|f| f == folder_hash).unwrap_or(false) {
  134. let mut ordered_hash_set = new_threads
  135. .hash_set
  136. .iter()
  137. .cloned()
  138. .collect::<Vec<EnvelopeHash>>();
  139. ordered_hash_set.sort_by(|a, b| {
  140. envelopes[a]
  141. .date()
  142. .partial_cmp(&envelopes[b].date())
  143. .unwrap()
  144. });
  145. for h in ordered_hash_set {
  146. t.insert_reply(envelopes, h);
  147. }
  148. continue;
  149. }
  150. if sent_folder.map(|f| f == *t_fh).unwrap_or(false) {
  151. let mut ordered_hash_set =
  152. t.hash_set.iter().cloned().collect::<Vec<EnvelopeHash>>();
  153. ordered_hash_set.sort_by(|a, b| {
  154. envelopes[a]
  155. .date()
  156. .partial_cmp(&envelopes[b].date())
  157. .unwrap()
  158. });
  159. for h in ordered_hash_set {
  160. new_threads.insert_reply(envelopes, h);
  161. }
  162. }
  163. }
  164. threads.insert(folder_hash, new_threads);
  165. }
  166. pub fn update(&mut self, old_hash: EnvelopeHash, envelope: Envelope, folder_hash: FolderHash) {
  167. self.envelopes.remove(&old_hash);
  168. let new_hash = envelope.hash();
  169. self.message_ids
  170. .insert(envelope.message_id().raw().to_vec(), new_hash);
  171. self.envelopes.insert(new_hash, envelope);
  172. if self.sent_folder.map(|f| f == folder_hash).unwrap_or(false) {
  173. for (_, t) in self.threads.iter_mut() {
  174. t.update_envelope(old_hash, new_hash, &self.envelopes)
  175. .unwrap_or(());
  176. }
  177. }
  178. {
  179. if self
  180. .threads
  181. .entry(folder_hash)
  182. .or_default()
  183. .update_envelope(old_hash, new_hash, &self.envelopes)
  184. .is_ok()
  185. {
  186. return;
  187. }
  188. }
  189. /* envelope is not in threads, so insert it */
  190. let env = self.envelopes.entry(new_hash).or_default() as *mut Envelope;
  191. unsafe {
  192. self.threads
  193. .entry(folder_hash)
  194. .or_default()
  195. .insert(&mut (*env), &self.envelopes);
  196. }
  197. }
  198. pub fn insert(&mut self, envelope: Envelope, folder_hash: FolderHash) -> &Envelope {
  199. let hash = envelope.hash();
  200. self.message_ids
  201. .insert(envelope.message_id().raw().to_vec(), hash);
  202. self.envelopes.insert(hash, envelope);
  203. self.threads
  204. .entry(folder_hash)
  205. .or_default()
  206. .insert_reply(&mut self.envelopes, hash);
  207. &self.envelopes[&hash]
  208. }
  209. pub fn insert_reply(&mut self, env_hash: EnvelopeHash) {
  210. for (_, t) in self.threads.iter_mut() {
  211. t.insert_reply(&mut self.envelopes, env_hash);
  212. }
  213. }
  214. }
  215. impl Deref for Collection {
  216. type Target = FnvHashMap<EnvelopeHash, Envelope>;
  217. fn deref(&self) -> &FnvHashMap<EnvelopeHash, Envelope> {
  218. &self.envelopes
  219. }
  220. }
  221. impl DerefMut for Collection {
  222. fn deref_mut(&mut self) -> &mut FnvHashMap<EnvelopeHash, Envelope> {
  223. &mut self.envelopes
  224. }
  225. }