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.

304 lines
11KB

  1. /*
  2. * meli - imap module.
  3. *
  4. * Copyright 2017 - 2019 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. use super::*;
  22. use crate::backends::BackendOp;
  23. use crate::email::*;
  24. use crate::error::{MeliError, Result};
  25. use std::cell::Cell;
  26. use std::sync::{Arc, Mutex};
  27. /// `BackendOp` implementor for Imap
  28. #[derive(Debug, Clone)]
  29. pub struct ImapOp {
  30. uid: usize,
  31. bytes: Option<String>,
  32. headers: Option<String>,
  33. body: Option<String>,
  34. folder_path: String,
  35. flags: Cell<Option<Flag>>,
  36. connection: Arc<Mutex<ImapConnection>>,
  37. uid_store: Arc<UIDStore>,
  38. }
  39. impl ImapOp {
  40. pub fn new(
  41. uid: usize,
  42. folder_path: String,
  43. connection: Arc<Mutex<ImapConnection>>,
  44. uid_store: Arc<UIDStore>,
  45. ) -> Self {
  46. ImapOp {
  47. uid,
  48. connection,
  49. bytes: None,
  50. headers: None,
  51. body: None,
  52. folder_path,
  53. flags: Cell::new(None),
  54. uid_store,
  55. }
  56. }
  57. }
  58. impl BackendOp for ImapOp {
  59. fn description(&self) -> String {
  60. unimplemented!();
  61. }
  62. fn as_bytes(&mut self) -> Result<&[u8]> {
  63. if self.bytes.is_none() {
  64. let mut bytes_cache = self.uid_store.byte_cache.lock()?;
  65. let cache = bytes_cache.entry(self.uid).or_default();
  66. if cache.bytes.is_some() {
  67. self.bytes = cache.bytes.clone();
  68. } else {
  69. let mut response = String::with_capacity(8 * 1024);
  70. {
  71. let mut conn = self.connection.lock().unwrap();
  72. conn.send_command(format!("SELECT {}", self.folder_path).as_bytes())?;
  73. conn.read_response(&mut response)?;
  74. conn.send_command(format!("UID FETCH {} (FLAGS RFC822)", self.uid).as_bytes())?;
  75. conn.read_response(&mut response)?;
  76. }
  77. debug!(
  78. "fetch response is {} bytes and {} lines",
  79. response.len(),
  80. response.lines().collect::<Vec<&str>>().len()
  81. );
  82. match protocol_parser::uid_fetch_response(response.as_bytes())
  83. .to_full_result()
  84. .map_err(MeliError::from)
  85. {
  86. Ok(v) => {
  87. if v.len() != 1 {
  88. debug!("responses len is {}", v.len());
  89. /* TODO: Trigger cache invalidation here. */
  90. return Err(MeliError::new(format!(
  91. "message with UID {} was not found",
  92. self.uid
  93. )));
  94. }
  95. let (uid, flags, b) = v[0];
  96. assert_eq!(uid, self.uid);
  97. if flags.is_some() {
  98. self.flags.set(flags);
  99. cache.flags = flags;
  100. }
  101. cache.bytes = Some(unsafe { std::str::from_utf8_unchecked(b).to_string() });
  102. }
  103. Err(e) => return Err(e),
  104. }
  105. self.bytes = cache.bytes.clone();
  106. }
  107. }
  108. Ok(self.bytes.as_ref().unwrap().as_bytes())
  109. }
  110. fn fetch_headers(&mut self) -> Result<&[u8]> {
  111. if self.bytes.is_some() {
  112. let result =
  113. parser::headers_raw(self.bytes.as_ref().unwrap().as_bytes()).to_full_result()?;
  114. return Ok(result);
  115. }
  116. if self.headers.is_none() {
  117. let mut bytes_cache = self.uid_store.byte_cache.lock()?;
  118. let cache = bytes_cache.entry(self.uid).or_default();
  119. if cache.headers.is_some() {
  120. self.headers = cache.headers.clone();
  121. } else {
  122. let mut response = String::with_capacity(8 * 1024);
  123. let mut conn = self.connection.lock().unwrap();
  124. conn.send_command(
  125. format!("UID FETCH {} (FLAGS RFC822.HEADER)", self.uid).as_bytes(),
  126. )?;
  127. conn.read_response(&mut response)?;
  128. debug!(
  129. "fetch response is {} bytes and {} lines",
  130. response.len(),
  131. response.lines().collect::<Vec<&str>>().len()
  132. );
  133. match protocol_parser::uid_fetch_response(response.as_bytes())
  134. .to_full_result()
  135. .map_err(MeliError::from)
  136. {
  137. Ok(v) => {
  138. if v.len() != 1 {
  139. debug!("responses len is {}", v.len());
  140. /* TODO: Trigger cache invalidation here. */
  141. return Err(MeliError::new(format!(
  142. "message with UID {} was not found",
  143. self.uid
  144. )));
  145. }
  146. let (uid, flags, b) = v[0];
  147. assert_eq!(uid, self.uid);
  148. if flags.is_some() {
  149. self.flags.set(flags);
  150. cache.flags = flags;
  151. }
  152. cache.headers =
  153. Some(unsafe { std::str::from_utf8_unchecked(b).to_string() });
  154. }
  155. Err(e) => return Err(e),
  156. }
  157. self.headers = cache.headers.clone();
  158. }
  159. }
  160. Ok(self.headers.as_ref().unwrap().as_bytes())
  161. }
  162. fn fetch_body(&mut self) -> Result<&[u8]> {
  163. if self.bytes.is_some() {
  164. let result =
  165. parser::body_raw(self.bytes.as_ref().unwrap().as_bytes()).to_full_result()?;
  166. return Ok(result);
  167. }
  168. if self.body.is_none() {
  169. let mut bytes_cache = self.uid_store.byte_cache.lock()?;
  170. let cache = bytes_cache.entry(self.uid).or_default();
  171. if cache.body.is_some() {
  172. self.body = cache.body.clone();
  173. } else {
  174. let mut response = String::with_capacity(8 * 1024);
  175. let mut conn = self.connection.lock().unwrap();
  176. conn.send_command(
  177. format!("UID FETCH {} (FLAGS RFC822.TEXT)", self.uid).as_bytes(),
  178. )?;
  179. conn.read_response(&mut response)?;
  180. debug!(
  181. "fetch response is {} bytes and {} lines",
  182. response.len(),
  183. response.lines().collect::<Vec<&str>>().len()
  184. );
  185. match protocol_parser::uid_fetch_response(response.as_bytes())
  186. .to_full_result()
  187. .map_err(MeliError::from)
  188. {
  189. Ok(v) => {
  190. if v.len() != 1 {
  191. debug!("responses len is {}", v.len());
  192. /* TODO: Trigger cache invalidation here. */
  193. return Err(MeliError::new(format!(
  194. "message with UID {} was not found",
  195. self.uid
  196. )));
  197. }
  198. let (uid, flags, b) = v[0];
  199. assert_eq!(uid, self.uid);
  200. if flags.is_some() {
  201. self.flags.set(flags);
  202. }
  203. cache.body = Some(unsafe { std::str::from_utf8_unchecked(b).to_string() });
  204. }
  205. Err(e) => return Err(e),
  206. }
  207. self.body = cache.body.clone();
  208. }
  209. }
  210. Ok(self.body.as_ref().unwrap().as_bytes())
  211. }
  212. fn fetch_flags(&self) -> Flag {
  213. if self.flags.get().is_some() {
  214. return self.flags.get().unwrap();
  215. }
  216. let mut bytes_cache = self.uid_store.byte_cache.lock().unwrap();
  217. let cache = bytes_cache.entry(self.uid).or_default();
  218. if cache.flags.is_some() {
  219. self.flags.set(cache.flags);
  220. } else {
  221. let mut response = String::with_capacity(8 * 1024);
  222. let mut conn = self.connection.lock().unwrap();
  223. conn.send_command(format!("EXAMINE \"{}\"", &self.folder_path,).as_bytes())
  224. .unwrap();
  225. conn.read_response(&mut response).unwrap();
  226. conn.send_command(format!("UID FETCH {} FLAGS", self.uid).as_bytes())
  227. .unwrap();
  228. conn.read_response(&mut response).unwrap();
  229. debug!(
  230. "fetch response is {} bytes and {} lines",
  231. response.len(),
  232. response.lines().collect::<Vec<&str>>().len()
  233. );
  234. match protocol_parser::uid_fetch_flags_response(response.as_bytes())
  235. .to_full_result()
  236. .map_err(MeliError::from)
  237. {
  238. Ok(v) => {
  239. if v.len() != 1 {
  240. debug!("responses len is {}", v.len());
  241. /* TODO: Trigger cache invalidation here. */
  242. panic!(format!("message with UID {} was not found", self.uid));
  243. }
  244. let (uid, flags) = v[0];
  245. assert_eq!(uid, self.uid);
  246. cache.flags = Some(flags);
  247. self.flags.set(Some(flags));
  248. }
  249. Err(e) => Err(e).unwrap(),
  250. }
  251. }
  252. self.flags.get().unwrap()
  253. }
  254. fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
  255. let mut flags = self.fetch_flags();
  256. flags.set(f, value);
  257. let mut response = String::with_capacity(8 * 1024);
  258. let mut conn = self.connection.lock().unwrap();
  259. conn.send_command(format!("SELECT \"{}\"", &self.folder_path,).as_bytes())?;
  260. conn.read_response(&mut response)?;
  261. debug!(&response);
  262. conn.send_command(
  263. format!(
  264. "UID STORE {} FLAGS.SILENT ({})",
  265. self.uid,
  266. flags_to_imap_list!(flags)
  267. )
  268. .as_bytes(),
  269. )?;
  270. conn.read_response(&mut response)?;
  271. debug!(&response);
  272. match protocol_parser::uid_fetch_flags_response(response.as_bytes())
  273. .to_full_result()
  274. .map_err(MeliError::from)
  275. {
  276. Ok(v) => {
  277. if v.len() == 1 {
  278. debug!("responses len is {}", v.len());
  279. let (uid, flags) = v[0];
  280. assert_eq!(uid, self.uid);
  281. self.flags.set(Some(flags));
  282. }
  283. }
  284. Err(e) => Err(e).unwrap(),
  285. }
  286. let mut bytes_cache = self.uid_store.byte_cache.lock()?;
  287. let cache = bytes_cache.entry(self.uid).or_default();
  288. cache.flags = Some(flags);
  289. Ok(())
  290. }
  291. }