🐝
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.

273 lines
7.1 KiB

4 years ago
4 years ago
  1. /*
  2. * meli - backends module
  3. *
  4. * Copyright 2017 Manos Pitsidianakis
  5. *
  6. * This file is part of meli.
  7. *
  8. * meli is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * meli is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with meli. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. pub mod imap;
  22. pub mod maildir;
  23. pub mod mbox;
  24. use crate::async_workers::*;
  25. use crate::conf::AccountSettings;
  26. use crate::error::Result;
  27. //use mailbox::backends::imap::ImapType;
  28. //use mailbox::backends::mbox::MboxType;
  29. use self::maildir::MaildirType;
  30. use super::email::{Envelope, EnvelopeHash, Flag};
  31. use std::fmt;
  32. use std::fmt::Debug;
  33. use std::ops::Deref;
  34. use fnv::FnvHashMap;
  35. use std;
  36. pub type BackendCreator = Box<Fn(&AccountSettings) -> Box<MailBackend>>;
  37. /// A hashmap containing all available mail backends.
  38. /// An abstraction over any available backends.
  39. pub struct Backends {
  40. map: FnvHashMap<std::string::String, Box<Fn() -> BackendCreator>>,
  41. }
  42. impl Default for Backends {
  43. fn default() -> Self {
  44. Backends::new()
  45. }
  46. }
  47. impl Backends {
  48. pub fn new() -> Self {
  49. let mut b = Backends {
  50. map: FnvHashMap::with_capacity_and_hasher(1, Default::default()),
  51. };
  52. b.register(
  53. "maildir".to_string(),
  54. Box::new(|| Box::new(|f| Box::new(MaildirType::new(f)))),
  55. );
  56. //b.register("mbox".to_string(), Box::new(|| Box::new(MboxType::new(""))));
  57. //b.register("imap".to_string(), Box::new(|| Box::new(ImapType::new(""))));
  58. b
  59. }
  60. pub fn get(&self, key: &str) -> BackendCreator {
  61. if !self.map.contains_key(key) {
  62. panic!("{} is not a valid mail backend", key);
  63. }
  64. self.map[key]()
  65. }
  66. pub fn register(&mut self, key: String, backend: Box<Fn() -> BackendCreator>) {
  67. if self.map.contains_key(&key) {
  68. panic!("{} is an already registered backend", key);
  69. }
  70. self.map.insert(key, backend);
  71. }
  72. }
  73. #[derive(Debug)]
  74. pub enum RefreshEventKind {
  75. Update(EnvelopeHash, Box<Envelope>),
  76. /// Rename(old_hash, new_hash)
  77. Rename(EnvelopeHash, EnvelopeHash),
  78. Create(Box<Envelope>),
  79. Remove(FolderHash),
  80. Rescan,
  81. }
  82. #[derive(Debug)]
  83. pub struct RefreshEvent {
  84. hash: FolderHash,
  85. kind: RefreshEventKind,
  86. }
  87. impl RefreshEvent {
  88. pub fn hash(&self) -> FolderHash {
  89. self.hash
  90. }
  91. pub fn kind(self) -> RefreshEventKind {
  92. /* consumes self! */
  93. self.kind
  94. }
  95. }
  96. /// A `RefreshEventConsumer` is a boxed closure that must be used to consume a `RefreshEvent` and
  97. /// send it to a UI provided channel. We need this level of abstraction to provide an interface for
  98. /// all users of mailbox refresh events.
  99. pub struct RefreshEventConsumer(Box<Fn(RefreshEvent) -> ()>);
  100. unsafe impl Send for RefreshEventConsumer {}
  101. unsafe impl Sync for RefreshEventConsumer {}
  102. impl RefreshEventConsumer {
  103. pub fn new(b: Box<Fn(RefreshEvent) -> ()>) -> Self {
  104. RefreshEventConsumer(b)
  105. }
  106. pub fn send(&self, r: RefreshEvent) {
  107. self.0(r);
  108. }
  109. }
  110. pub struct NotifyFn(Box<Fn(FolderHash) -> ()>);
  111. unsafe impl Send for NotifyFn {}
  112. unsafe impl Sync for NotifyFn {}
  113. impl fmt::Debug for NotifyFn {
  114. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  115. write!(f, "NotifyFn Box")
  116. }
  117. }
  118. impl From<Box<Fn(FolderHash) -> ()>> for NotifyFn {
  119. fn from(kind: Box<Fn(FolderHash) -> ()>) -> Self {
  120. NotifyFn(kind)
  121. }
  122. }
  123. impl NotifyFn {
  124. pub fn new(b: Box<Fn(FolderHash) -> ()>) -> Self {
  125. NotifyFn(b)
  126. }
  127. pub fn notify(&self, f: FolderHash) {
  128. self.0(f);
  129. }
  130. }
  131. pub trait MailBackend: ::std::fmt::Debug {
  132. fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>>;
  133. fn watch(&self, sender: RefreshEventConsumer) -> Result<()>;
  134. fn folders(&self) -> FnvHashMap<FolderHash, Folder>;
  135. fn operation(&self, hash: EnvelopeHash, folder_hash: FolderHash) -> Box<BackendOp>;
  136. fn save(&self, bytes: &[u8], folder: &str) -> Result<()>;
  137. //login function
  138. }
  139. /// A `BackendOp` manages common operations for the various mail backends. They only live for the
  140. /// duration of the operation. They are generated by the `operation` method of `Mailbackend` trait.
  141. ///
  142. /// # Motivation
  143. ///
  144. /// We need a way to do various operations on individual mails regardless of what backend they come
  145. /// from (eg local or imap).
  146. ///
  147. /// # Creation
  148. /// ```no_run
  149. /// /* Create operation from Backend */
  150. ///
  151. /// let op = backend.operation(message.hash(), mailbox.folder.hash());
  152. /// ```
  153. ///
  154. /// # Example
  155. /// ```
  156. /// use melib::mailbox::backends::{BackendOp};
  157. /// use melib::Result;
  158. /// use melib::{Envelope, Flag};
  159. ///
  160. /// #[derive(Debug)]
  161. /// struct FooOp {}
  162. ///
  163. /// impl BackendOp for FooOp {
  164. /// fn description(&self) -> String {
  165. /// "Foobar".to_string()
  166. /// }
  167. /// fn as_bytes(&mut self) -> Result<&[u8]> {
  168. /// unimplemented!()
  169. /// }
  170. /// fn fetch_headers(&mut self) -> Result<&[u8]> {
  171. /// unimplemented!()
  172. /// }
  173. /// fn fetch_body(&mut self) -> Result<&[u8]> {
  174. /// unimplemented!()
  175. /// }
  176. /// fn fetch_flags(&self) -> Flag {
  177. /// unimplemented!()
  178. /// }
  179. /// }
  180. ///
  181. /// let operation = Box::new(FooOp {});
  182. /// assert_eq!("Foobar", &operation.description());
  183. /// ```
  184. pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send {
  185. fn description(&self) -> String;
  186. fn as_bytes(&mut self) -> Result<&[u8]>;
  187. //fn delete(&self) -> ();
  188. //fn copy(&self
  189. fn fetch_headers(&mut self) -> Result<&[u8]>;
  190. fn fetch_body(&mut self) -> Result<&[u8]>;
  191. fn fetch_flags(&self) -> Flag;
  192. fn set_flag(&mut self, envelope: &mut Envelope, flag: Flag) -> Result<()>;
  193. }
  194. }
  195. }
  196. pub trait BackendFolder: Debug {
  197. fn hash(&self) -> FolderHash;
  198. fn name(&self) -> &str;
  199. fn change_name(&mut self, new_name: &str);
  200. fn clone(&self) -> Folder;
  201. fn children(&self) -> &Vec<FolderHash>;
  202. fn parent(&self) -> Option<FolderHash>;
  203. }
  204. #[derive(Debug)]
  205. struct DummyFolder {
  206. v: Vec<FolderHash>,
  207. }
  208. impl BackendFolder for DummyFolder {
  209. fn hash(&self) -> FolderHash {
  210. 0
  211. }
  212. fn name(&self) -> &str {
  213. ""
  214. }
  215. fn change_name(&mut self, _s: &str) {}
  216. fn clone(&self) -> Folder {
  217. folder_default()
  218. }
  219. fn children(&self) -> &Vec<FolderHash> {
  220. &self.v
  221. }
  222. fn parent(&self) -> Option<FolderHash> {
  223. None
  224. }
  225. }
  226. pub fn folder_default() -> Folder {
  227. Box::new(DummyFolder {
  228. v: Vec::with_capacity(0),
  229. })
  230. }
  231. pub type FolderHash = u64;
  232. pub type Folder = Box<dyn BackendFolder + Send>;
  233. impl Clone for Folder {
  234. fn clone(&self) -> Self {
  235. BackendFolder::clone(self.deref())
  236. }
  237. }
  238. impl Default for Folder {
  239. fn default() -> Self {
  240. folder_default()
  241. }
  242. }