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.

614 lines
19KB

  1. /*
  2. * meli - email 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. /*!
  22. * Email parsing, handling, sending etc.
  23. */
  24. use fnv::FnvHashMap;
  25. mod compose;
  26. pub use self::compose::*;
  27. mod mailto;
  28. pub use mailto::*;
  29. mod attachment_types;
  30. pub mod attachments;
  31. pub use crate::attachments::*;
  32. mod address;
  33. pub mod parser;
  34. use crate::parser::BytesExt;
  35. pub use address::*;
  36. pub mod signatures;
  37. use crate::backends::BackendOp;
  38. use crate::error::{MeliError, Result};
  39. use crate::thread::ThreadHash;
  40. use std::borrow::Cow;
  41. use std::cmp::Ordering;
  42. use std::collections::hash_map::DefaultHasher;
  43. use std::fmt;
  44. use std::hash::Hasher;
  45. use std::option::Option;
  46. use std::str;
  47. use std::string::String;
  48. use chrono;
  49. use chrono::TimeZone;
  50. bitflags! {
  51. #[derive(Default, Serialize, Deserialize)]
  52. pub struct Flag: u8 {
  53. const PASSED = 0b0000_0001;
  54. const REPLIED = 0b0000_0010;
  55. const SEEN = 0b0000_0100;
  56. const TRASHED = 0b0000_1000;
  57. const DRAFT = 0b0001_0000;
  58. const FLAGGED = 0b0010_0000;
  59. }
  60. }
  61. #[derive(Debug, Clone, Default)]
  62. pub struct EnvelopeWrapper {
  63. envelope: Envelope,
  64. buffer: Vec<u8>,
  65. }
  66. use std::ops::Deref;
  67. impl Deref for EnvelopeWrapper {
  68. type Target = Envelope;
  69. fn deref(&self) -> &Envelope {
  70. &self.envelope
  71. }
  72. }
  73. impl EnvelopeWrapper {
  74. pub fn new(buffer: Vec<u8>) -> Result<Self> {
  75. Ok(EnvelopeWrapper {
  76. envelope: Envelope::from_bytes(&buffer, None)?,
  77. buffer,
  78. })
  79. }
  80. pub fn update(&mut self, new_buffer: Vec<u8>) {
  81. // TODO: Propagate error.
  82. if let Ok(e) = EnvelopeWrapper::new(new_buffer) {
  83. *self = e;
  84. }
  85. }
  86. pub fn envelope(&self) -> &Envelope {
  87. &self.envelope
  88. }
  89. pub fn buffer(&self) -> &[u8] {
  90. &self.buffer
  91. }
  92. }
  93. pub type UnixTimestamp = u64;
  94. pub type EnvelopeHash = u64;
  95. /// `Envelope` represents all the data of an email we need to know.
  96. ///
  97. /// Attachments (the email's body) is parsed on demand with `body`.
  98. ///
  99. /// Access to the underlying email object in the account's backend (for example the file or the
  100. /// entry in an IMAP server) is given through `operation_token`. For more information see
  101. /// `BackendOp`.
  102. #[derive(Clone, Default, Serialize, Deserialize)]
  103. pub struct Envelope {
  104. date: String,
  105. from: Vec<Address>,
  106. to: Vec<Address>,
  107. cc: Vec<Address>,
  108. bcc: Vec<Address>,
  109. subject: Option<Vec<u8>>,
  110. message_id: MessageID,
  111. in_reply_to: Option<MessageID>,
  112. references: Option<References>,
  113. other_headers: FnvHashMap<String, String>,
  114. timestamp: UnixTimestamp,
  115. thread: ThreadHash,
  116. hash: EnvelopeHash,
  117. flags: Flag,
  118. has_attachments: bool,
  119. }
  120. impl fmt::Debug for Envelope {
  121. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  122. write!(f, "Envelope {{\n\tsubject: {}\n\tdate: {},\n\tfrom:{:#?},\n\tto {:#?},\n\tmessage_id: {},\n\tin_reply_to: {:?}\n\treferences: {:#?},\n\thash: {}\n}}",
  123. self.subject(),
  124. self.date,
  125. self.from,
  126. self.to,
  127. self.message_id_display(),
  128. self.in_reply_to_display(),
  129. self.references,
  130. self.hash)
  131. }
  132. }
  133. impl Envelope {
  134. pub fn new(hash: EnvelopeHash) -> Self {
  135. Envelope {
  136. date: String::new(),
  137. from: Vec::new(),
  138. to: Vec::new(),
  139. cc: Vec::new(),
  140. bcc: Vec::new(),
  141. subject: None,
  142. message_id: MessageID::default(),
  143. in_reply_to: None,
  144. references: None,
  145. other_headers: FnvHashMap::default(),
  146. timestamp: 0,
  147. thread: ThreadHash::null(),
  148. hash,
  149. has_attachments: false,
  150. flags: Flag::default(),
  151. }
  152. }
  153. pub fn set_hash(&mut self, new_hash: EnvelopeHash) {
  154. self.hash = new_hash;
  155. }
  156. pub fn from_bytes(bytes: &[u8], flags: Option<Flag>) -> Result<Envelope> {
  157. let mut h = DefaultHasher::new();
  158. h.write(bytes);
  159. let mut e = Envelope::new(h.finish());
  160. let res = e.populate_headers(bytes).ok();
  161. if res.is_some() {
  162. if let Some(f) = flags {
  163. e.flags = f;
  164. }
  165. return Ok(e);
  166. }
  167. Err(MeliError::new("Couldn't parse mail."))
  168. }
  169. pub fn from_token(mut operation: Box<dyn BackendOp>, hash: EnvelopeHash) -> Option<Envelope> {
  170. let mut e = Envelope::new(hash);
  171. e.flags = operation.fetch_flags();
  172. if let Ok(bytes) = operation.as_bytes() {
  173. let res = e.populate_headers(bytes).ok();
  174. if res.is_some() {
  175. return Some(e);
  176. }
  177. }
  178. None
  179. }
  180. pub fn hash(&self) -> EnvelopeHash {
  181. self.hash
  182. }
  183. pub fn populate_headers(&mut self, bytes: &[u8]) -> Result<()> {
  184. let (headers, body) = match parser::mail(bytes).to_full_result() {
  185. Ok(v) => v,
  186. Err(e) => {
  187. debug!("error in parsing mail\n{:?}\n", e);
  188. let error_msg = String::from("Mail cannot be shown because of errors.");
  189. return Err(MeliError::new(error_msg));
  190. }
  191. };
  192. let mut in_reply_to = None;
  193. for (name, value) in headers {
  194. if value.len() == 1 && value.is_empty() {
  195. continue;
  196. }
  197. if name.eq_ignore_ascii_case(b"to") {
  198. let parse_result = parser::rfc2822address_list(value);
  199. if parse_result.is_done() {
  200. let value = parse_result.to_full_result().unwrap();
  201. self.set_to(value);
  202. };
  203. } else if name.eq_ignore_ascii_case(b"cc") {
  204. let parse_result = parser::rfc2822address_list(value);
  205. if parse_result.is_done() {
  206. let value = parse_result.to_full_result().unwrap();
  207. self.set_cc(value);
  208. };
  209. } else if name.eq_ignore_ascii_case(b"bcc") {
  210. let parse_result = parser::rfc2822address_list(value);
  211. if parse_result.is_done() {
  212. let value = parse_result.to_full_result().unwrap();
  213. self.set_bcc(value);
  214. };
  215. } else if name.eq_ignore_ascii_case(b"from") {
  216. let parse_result = parser::rfc2822address_list(value);
  217. if parse_result.is_done() {
  218. let value = parse_result.to_full_result().unwrap();
  219. self.set_from(value);
  220. }
  221. } else if name.eq_ignore_ascii_case(b"subject") {
  222. let parse_result = parser::phrase(value.trim());
  223. if parse_result.is_done() {
  224. let value = parse_result.to_full_result().unwrap();
  225. self.set_subject(value);
  226. };
  227. } else if name.eq_ignore_ascii_case(b"message-id") {
  228. self.set_message_id(value);
  229. } else if name.eq_ignore_ascii_case(b"references") {
  230. {
  231. let parse_result = parser::references(value);
  232. if parse_result.is_done() {
  233. for v in parse_result.to_full_result().unwrap() {
  234. self.push_references(v);
  235. }
  236. }
  237. }
  238. self.set_references(value);
  239. } else if name.eq_ignore_ascii_case(b"in-reply-to") {
  240. self.set_in_reply_to(value);
  241. in_reply_to = Some(value);
  242. } else if name.eq_ignore_ascii_case(b"date") {
  243. let parse_result = parser::phrase(value);
  244. if parse_result.is_done() {
  245. let value = parse_result.to_full_result().unwrap();
  246. self.set_date(value.as_slice());
  247. } else {
  248. self.set_date(value);
  249. }
  250. } else if name.eq_ignore_ascii_case(b"content-type") {
  251. match parser::content_type(value).to_full_result() {
  252. Ok((ct, cst, ref params))
  253. if ct.eq_ignore_ascii_case(b"multipart")
  254. && cst.eq_ignore_ascii_case(b"mixed") =>
  255. {
  256. let mut builder = AttachmentBuilder::default();
  257. builder.set_content_type_from_bytes(value);
  258. let mut boundary = None;
  259. for (n, v) in params {
  260. if n == b"boundary" {
  261. boundary = Some(v);
  262. break;
  263. }
  264. }
  265. if let Some(boundary) = boundary {
  266. self.has_attachments =
  267. Attachment::check_if_has_attachments_quick(body, boundary);
  268. } else {
  269. debug!("{:?} has no boundary field set in multipart/mixed content-type field.", &self);
  270. }
  271. }
  272. _ => {}
  273. }
  274. } else {
  275. self.other_headers.insert(
  276. String::from_utf8_lossy(name).into(),
  277. String::from_utf8_lossy(value).into(),
  278. );
  279. }
  280. }
  281. /*
  282. * https://tools.ietf.org/html/rfc5322#section-3.6.4
  283. *
  284. * if self.message_id.is_none() ...
  285. */
  286. if let Some(ref mut x) = in_reply_to {
  287. self.push_references(x);
  288. }
  289. if let Some(d) = parser::date(&self.date.as_bytes()) {
  290. self.set_datetime(d);
  291. }
  292. if self.message_id.raw().is_empty() {
  293. let hash = self.hash;
  294. self.set_message_id(format!("<{:x}>", hash).as_bytes());
  295. }
  296. if self.references.is_some() {
  297. if let Some(pos) = self
  298. .references
  299. .as_ref()
  300. .map(|r| &r.refs)
  301. .unwrap()
  302. .iter()
  303. .position(|r| r == &self.message_id)
  304. {
  305. self.references.as_mut().unwrap().refs.remove(pos);
  306. }
  307. }
  308. Ok(())
  309. }
  310. pub fn populate_headers_from_token(&mut self, mut operation: Box<dyn BackendOp>) -> Result<()> {
  311. let headers = operation.fetch_headers()?;
  312. self.populate_headers(headers)
  313. }
  314. pub fn date(&self) -> UnixTimestamp {
  315. self.timestamp
  316. }
  317. pub fn datetime(&self) -> chrono::DateTime<chrono::FixedOffset> {
  318. if let Some(d) = parser::date(&self.date.as_bytes()) {
  319. return d;
  320. }
  321. chrono::FixedOffset::west(0)
  322. .ymd(1970, 1, 1)
  323. .and_hms(0, 0, 0)
  324. }
  325. pub fn date_as_str(&self) -> &str {
  326. &self.date
  327. }
  328. pub fn from(&self) -> &Vec<Address> {
  329. &self.from
  330. }
  331. pub fn field_bcc_to_string(&self) -> String {
  332. let _strings: Vec<String> = self.bcc.iter().map(|a| format!("{}", a)).collect();
  333. _strings.join(", ")
  334. }
  335. pub fn field_cc_to_string(&self) -> String {
  336. let _strings: Vec<String> = self.cc.iter().map(|a| format!("{}", a)).collect();
  337. _strings.join(", ")
  338. }
  339. pub fn field_from_to_string(&self) -> String {
  340. let _strings: Vec<String> = self.from().iter().map(|a| format!("{}", a)).collect();
  341. _strings.join(", ")
  342. }
  343. pub fn to(&self) -> &Vec<Address> {
  344. &self.to
  345. }
  346. pub fn field_to_to_string(&self) -> String {
  347. let _strings: Vec<String> = self.to.iter().map(|a| format!("{}", a)).collect();
  348. _strings.join(", ")
  349. }
  350. pub fn field_references_to_string(&self) -> String {
  351. let _strings: Vec<String> = self.references().iter().map(|a| a.to_string()).collect();
  352. _strings.join(", ")
  353. }
  354. /// Requests bytes from backend and thus can fail
  355. pub fn bytes(&self, mut operation: Box<dyn BackendOp>) -> Result<Vec<u8>> {
  356. operation.as_bytes().map(|v| v.to_vec())
  357. }
  358. pub fn body_bytes(&self, bytes: &[u8]) -> Attachment {
  359. let builder = AttachmentBuilder::new(bytes);
  360. builder.build()
  361. }
  362. /// Requests bytes from backend and thus can fail
  363. pub fn headers<'a>(&self, bytes: &'a [u8]) -> Result<Vec<(&'a str, &'a str)>> {
  364. let ret = parser::headers(bytes).to_full_result()?;
  365. let len = ret.len();
  366. ret.into_iter()
  367. .try_fold(Vec::with_capacity(len), |mut acc, (a, b)| {
  368. Ok({
  369. acc.push((std::str::from_utf8(a)?, std::str::from_utf8(b)?));
  370. acc
  371. })
  372. })
  373. }
  374. /// Requests bytes from backend and thus can fail
  375. pub fn body(&self, mut operation: Box<dyn BackendOp>) -> Result<Attachment> {
  376. debug!("searching body for {:?}", self.message_id_display());
  377. let file = operation.as_bytes()?;
  378. Ok(self.body_bytes(file))
  379. }
  380. pub fn subject(&self) -> Cow<str> {
  381. match self.subject {
  382. Some(ref s) => String::from_utf8_lossy(s),
  383. _ => Cow::from(String::new()),
  384. }
  385. }
  386. pub fn in_reply_to(&self) -> Option<&MessageID> {
  387. self.in_reply_to.as_ref()
  388. }
  389. pub fn in_reply_to_display(&self) -> Option<Cow<str>> {
  390. if let Some(ref m) = self.in_reply_to {
  391. Some(String::from_utf8_lossy(m.val()))
  392. } else {
  393. None
  394. }
  395. }
  396. pub fn in_reply_to_raw(&self) -> Option<Cow<str>> {
  397. if let Some(ref m) = self.in_reply_to {
  398. Some(String::from_utf8_lossy(m.raw()))
  399. } else {
  400. None
  401. }
  402. }
  403. pub fn message_id(&self) -> &MessageID {
  404. &self.message_id
  405. }
  406. pub fn message_id_display(&self) -> Cow<str> {
  407. String::from_utf8_lossy(self.message_id.val())
  408. }
  409. pub fn message_id_raw(&self) -> Cow<str> {
  410. String::from_utf8_lossy(self.message_id.raw())
  411. }
  412. pub fn set_date(&mut self, new_val: &[u8]) {
  413. self.date = String::from_utf8_lossy(new_val).into_owned();
  414. }
  415. pub fn set_bcc(&mut self, new_val: Vec<Address>) {
  416. self.bcc = new_val;
  417. }
  418. pub fn set_cc(&mut self, new_val: Vec<Address>) {
  419. self.cc = new_val;
  420. }
  421. pub fn set_from(&mut self, new_val: Vec<Address>) {
  422. self.from = new_val;
  423. }
  424. pub fn set_to(&mut self, new_val: Vec<Address>) {
  425. self.to = new_val;
  426. }
  427. pub fn set_in_reply_to(&mut self, new_val: &[u8]) {
  428. let slice = match parser::message_id(new_val).to_full_result() {
  429. Ok(v) => v,
  430. Err(_) => {
  431. self.in_reply_to = None;
  432. return;
  433. }
  434. };
  435. self.in_reply_to = Some(MessageID::new(new_val, slice));
  436. }
  437. pub fn set_subject(&mut self, new_val: Vec<u8>) {
  438. self.subject = Some(new_val);
  439. }
  440. pub fn set_message_id(&mut self, new_val: &[u8]) {
  441. let slice = match parser::message_id(new_val).to_full_result() {
  442. Ok(v) => v,
  443. Err(e) => {
  444. debug!(e);
  445. return;
  446. }
  447. };
  448. self.message_id = MessageID::new(new_val, slice);
  449. }
  450. pub fn push_references(&mut self, new_val: &[u8]) {
  451. let slice = match parser::message_id(new_val).to_full_result() {
  452. Ok(v) => v,
  453. Err(e) => {
  454. debug!(e);
  455. return;
  456. }
  457. };
  458. let new_ref = MessageID::new(new_val, slice);
  459. match self.references {
  460. Some(ref mut s) => {
  461. if s.refs.contains(&new_ref) {
  462. if s.refs[s.refs.len() - 1] != new_ref {
  463. if let Some(index) = s.refs.iter().position(|x| *x == new_ref) {
  464. s.refs.remove(index);
  465. } else {
  466. panic!();
  467. }
  468. } else {
  469. return;
  470. }
  471. }
  472. s.refs.push(new_ref);
  473. }
  474. None => {
  475. let v = vec![new_ref];
  476. self.references = Some(References {
  477. raw: "".into(),
  478. refs: v,
  479. });
  480. }
  481. }
  482. }
  483. pub fn set_references(&mut self, new_val: &[u8]) {
  484. match self.references {
  485. Some(ref mut s) => {
  486. s.raw = new_val.into();
  487. }
  488. None => {
  489. self.references = Some(References {
  490. raw: new_val.into(),
  491. refs: Vec::new(),
  492. });
  493. }
  494. }
  495. }
  496. pub fn references(&self) -> Vec<&MessageID> {
  497. match self.references {
  498. Some(ref s) => s
  499. .refs
  500. .iter()
  501. .fold(Vec::with_capacity(s.refs.len()), |mut acc, x| {
  502. acc.push(x);
  503. acc
  504. }),
  505. None => Vec::new(),
  506. }
  507. }
  508. pub fn other_headers(&self) -> &FnvHashMap<String, String> {
  509. &self.other_headers
  510. }
  511. pub fn other_headers_mut(&mut self) -> &mut FnvHashMap<String, String> {
  512. &mut self.other_headers
  513. }
  514. pub fn thread(&self) -> ThreadHash {
  515. self.thread
  516. }
  517. pub fn set_thread(&mut self, new_val: ThreadHash) {
  518. self.thread = new_val;
  519. }
  520. pub fn set_datetime(&mut self, new_val: chrono::DateTime<chrono::FixedOffset>) {
  521. self.timestamp = new_val.timestamp() as UnixTimestamp;
  522. }
  523. pub fn set_flag(
  524. &mut self,
  525. f: Flag,
  526. value: bool,
  527. mut operation: Box<dyn BackendOp>,
  528. ) -> Result<()> {
  529. self.flags.set(f, value);
  530. operation.set_flag(self, f, value)
  531. }
  532. pub fn set_flags(&mut self, f: Flag) {
  533. self.flags = f;
  534. }
  535. pub fn flags(&self) -> Flag {
  536. self.flags
  537. }
  538. pub fn set_seen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> {
  539. if !self.flags.contains(Flag::SEEN) {
  540. self.set_flag(Flag::SEEN, true, operation)
  541. } else {
  542. Ok(())
  543. }
  544. }
  545. pub fn set_unseen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> {
  546. if self.flags.contains(Flag::SEEN) {
  547. self.set_flag(Flag::SEEN, false, operation)
  548. } else {
  549. Ok(())
  550. }
  551. }
  552. pub fn is_seen(&self) -> bool {
  553. self.flags.contains(Flag::SEEN)
  554. }
  555. pub fn has_attachments(&self) -> bool {
  556. self.has_attachments
  557. }
  558. }
  559. impl Eq for Envelope {}
  560. impl Ord for Envelope {
  561. fn cmp(&self, other: &Envelope) -> Ordering {
  562. self.datetime().cmp(&other.datetime())
  563. }
  564. }
  565. impl PartialOrd for Envelope {
  566. fn partial_cmp(&self, other: &Envelope) -> Option<Ordering> {
  567. Some(self.cmp(other))
  568. }
  569. }
  570. impl PartialEq for Envelope {
  571. fn eq(&self, other: &Envelope) -> bool {
  572. self.hash == other.hash
  573. }
  574. }