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.

attachments.rs 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. /*
  2. * meli - attachments 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. use crate::email::parser;
  22. use crate::email::parser::BytesExt;
  23. use crate::email::EnvelopeWrapper;
  24. use data_encoding::BASE64_MIME;
  25. use std::fmt;
  26. use std::str;
  27. pub use crate::email::attachment_types::*;
  28. /*
  29. *
  30. * Data
  31. * Text { content: Vec<u8> }
  32. * Multipart
  33. */
  34. // TODO: Add example.
  35. //
  36. #[derive(Default, PartialEq)]
  37. pub struct AttachmentBuilder {
  38. content_type: ContentType,
  39. content_transfer_encoding: ContentTransferEncoding,
  40. raw: Vec<u8>,
  41. }
  42. #[derive(Clone, Serialize, Deserialize, PartialEq)]
  43. pub struct Attachment {
  44. content_type: ContentType,
  45. content_transfer_encoding: ContentTransferEncoding,
  46. raw: Vec<u8>,
  47. }
  48. impl fmt::Debug for Attachment {
  49. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  50. write!(f, "Attachment {{\n content_type: {:?},\n content_transfer_encoding: {:?},\n raw: Vec of {} bytes\n, body:\n{}\n}}",
  51. self.content_type,
  52. self.content_transfer_encoding,
  53. self.raw.len(),
  54. {
  55. let mut text = Vec::with_capacity(4096);
  56. self.get_text_recursive(&mut text);
  57. std::str::from_utf8(&text).map(std::string::ToString::to_string).unwrap_or_else(|e| format!("Unicode error {}", e))
  58. }
  59. )
  60. }
  61. }
  62. impl AttachmentBuilder {
  63. pub fn new(content: &[u8]) -> Self {
  64. AttachmentBuilder {
  65. content_type: Default::default(),
  66. content_transfer_encoding: ContentTransferEncoding::_7Bit,
  67. raw: content.to_vec(),
  68. }
  69. }
  70. pub fn content_type(&mut self) -> &ContentType {
  71. &self.content_type
  72. }
  73. pub fn set_content_type(&mut self, value: &[u8]) -> &Self {
  74. match parser::content_type(value).to_full_result() {
  75. Ok((ct, cst, params)) => {
  76. if ct.eq_ignore_ascii_case(b"multipart") {
  77. let mut boundary = None;
  78. for (n, v) in params {
  79. if n.eq_ignore_ascii_case(b"boundary") {
  80. boundary = Some(v);
  81. break;
  82. }
  83. }
  84. assert!(boundary.is_some());
  85. let _boundary = boundary.unwrap();
  86. let offset =
  87. (_boundary.as_ptr() as usize).wrapping_sub(value.as_ptr() as usize);
  88. let boundary = SliceBuild::new(offset, _boundary.len());
  89. let subattachments = Self::subattachments(&self.raw, boundary.get(&value));
  90. // Invalid mail or wrong assumption?
  91. // assert!(!subattachments.is_empty());
  92. self.content_type = ContentType::Multipart {
  93. boundary,
  94. kind: if cst.eq_ignore_ascii_case(b"mixed") {
  95. MultipartType::Mixed
  96. } else if cst.eq_ignore_ascii_case(b"alternative") {
  97. MultipartType::Alternative
  98. } else if cst.eq_ignore_ascii_case(b"digest") {
  99. MultipartType::Digest
  100. } else if cst.eq_ignore_ascii_case(b"signed") {
  101. MultipartType::Signed
  102. } else {
  103. Default::default()
  104. },
  105. subattachments,
  106. };
  107. } else if ct.eq_ignore_ascii_case(b"text") {
  108. self.content_type = ContentType::Text {
  109. kind: Text::Plain,
  110. charset: Charset::UTF8,
  111. };
  112. for (n, v) in params {
  113. if n.eq_ignore_ascii_case(b"charset") {
  114. if let ContentType::Text {
  115. charset: ref mut c, ..
  116. } = self.content_type
  117. {
  118. *c = Charset::from(v);
  119. }
  120. break;
  121. }
  122. }
  123. if cst.eq_ignore_ascii_case(b"html") {
  124. if let ContentType::Text {
  125. kind: ref mut k, ..
  126. } = self.content_type
  127. {
  128. *k = Text::Html;
  129. }
  130. } else if !cst.eq_ignore_ascii_case(b"plain") {
  131. if let ContentType::Text {
  132. kind: ref mut k, ..
  133. } = self.content_type
  134. {
  135. *k = Text::Other { tag: cst.into() };
  136. }
  137. }
  138. } else if ct.eq_ignore_ascii_case(b"message") && cst.eq_ignore_ascii_case(b"rfc822")
  139. {
  140. self.content_type = ContentType::MessageRfc822;
  141. } else if ct.eq_ignore_ascii_case(b"application")
  142. && cst.eq_ignore_ascii_case(b"pgp-signature")
  143. {
  144. self.content_type = ContentType::PGPSignature;
  145. } else {
  146. let mut tag: Vec<u8> = Vec::with_capacity(ct.len() + cst.len() + 1);
  147. tag.extend(ct);
  148. tag.push(b'/');
  149. tag.extend(cst);
  150. self.content_type = ContentType::Unsupported { tag };
  151. }
  152. }
  153. Err(v) => {
  154. debug!("parsing error in content_type: {:?} {:?}", value, v);
  155. }
  156. }
  157. self
  158. }
  159. pub fn set_content_transfer_encoding(&mut self, value: &[u8]) -> &Self {
  160. self.content_transfer_encoding = if value.eq_ignore_ascii_case(b"base64") {
  161. ContentTransferEncoding::Base64
  162. } else if value.eq_ignore_ascii_case(b"7bit") {
  163. ContentTransferEncoding::_7Bit
  164. } else if value.eq_ignore_ascii_case(b"8bit") {
  165. ContentTransferEncoding::_8Bit
  166. } else if value.eq_ignore_ascii_case(b"quoted-printable") {
  167. ContentTransferEncoding::QuotedPrintable
  168. } else {
  169. ContentTransferEncoding::Other {
  170. tag: value.to_ascii_lowercase(),
  171. }
  172. };
  173. self
  174. }
  175. /*
  176. fn decode(&self) -> Vec<u8> {
  177. // TODO merge this and standalone decode() function
  178. let charset = match self.content_type {
  179. ContentType::Text { charset: c, .. } => c,
  180. _ => Default::default(),
  181. };
  182. let bytes = match self.content_transfer_encoding {
  183. ContentTransferEncoding::Base64 => match BASE64_MIME.decode(&self.raw) {
  184. Ok(v) => v,
  185. _ => self.raw.to_vec(),
  186. },
  187. ContentTransferEncoding::QuotedPrintable => parser::quoted_printable_bytes(&self.raw)
  188. .to_full_result()
  189. .unwrap(),
  190. ContentTransferEncoding::_7Bit
  191. | ContentTransferEncoding::_8Bit
  192. | ContentTransferEncoding::Other { .. } => self.raw.to_vec(),
  193. };
  194. if let Ok(b) = parser::decode_charset(&bytes, charset) {
  195. b.into_bytes()
  196. } else {
  197. self.raw.to_vec()
  198. }
  199. }
  200. */
  201. pub fn build(self) -> Attachment {
  202. Attachment {
  203. content_type: self.content_type,
  204. content_transfer_encoding: self.content_transfer_encoding,
  205. raw: self.raw,
  206. }
  207. }
  208. pub fn subattachments(raw: &[u8], boundary: &[u8]) -> Vec<Attachment> {
  209. match parser::attachments(raw, boundary).to_full_result() {
  210. Ok(attachments) => {
  211. let mut vec = Vec::with_capacity(attachments.len());
  212. for a in attachments {
  213. let mut builder = AttachmentBuilder::default();
  214. let (headers, body) = match parser::attachment(&a).to_full_result() {
  215. Ok(v) => v,
  216. Err(_) => {
  217. debug!("error in parsing attachment");
  218. debug!("\n-------------------------------");
  219. debug!("{}\n", ::std::string::String::from_utf8_lossy(a));
  220. debug!("-------------------------------\n");
  221. continue;
  222. }
  223. };
  224. let body_slice = {
  225. let offset = (body.as_ptr() as usize).wrapping_sub(a.as_ptr() as usize);
  226. SliceBuild::new(offset, body.len())
  227. };
  228. builder.raw = body_slice.get(a).ltrim().into();
  229. for (name, value) in headers {
  230. if name.eq_ignore_ascii_case(b"content-type") {
  231. builder.set_content_type(value);
  232. } else if name.eq_ignore_ascii_case(b"content-transfer-encoding") {
  233. builder.set_content_transfer_encoding(value);
  234. }
  235. }
  236. vec.push(builder.build());
  237. }
  238. vec
  239. }
  240. a => {
  241. debug!(
  242. "error {:?}\n\traw: {:?}\n\tboundary: {:?}",
  243. a,
  244. str::from_utf8(raw).unwrap(),
  245. boundary
  246. );
  247. Vec::new()
  248. }
  249. }
  250. }
  251. }
  252. impl fmt::Display for Attachment {
  253. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  254. match self.content_type {
  255. ContentType::MessageRfc822 => match EnvelopeWrapper::new(self.bytes().to_vec()) {
  256. Ok(wrapper) => write!(
  257. f,
  258. "message/rfc822: {} - {} - {}",
  259. wrapper.date(),
  260. wrapper.field_from_to_string(),
  261. wrapper.subject()
  262. ),
  263. Err(e) => write!(f, "{}", e),
  264. },
  265. ContentType::PGPSignature => write!(f, "pgp signature {}", self.mime_type()),
  266. ContentType::Unsupported { .. } => {
  267. write!(f, "Data attachment of type {}", self.mime_type())
  268. }
  269. ContentType::Text { .. } => write!(f, "Text attachment of type {}", self.mime_type()),
  270. ContentType::Multipart {
  271. subattachments: ref sub_att_vec,
  272. ..
  273. } => write!(
  274. f,
  275. "{} attachment with {} subs",
  276. self.mime_type(),
  277. sub_att_vec.len()
  278. ),
  279. }
  280. }
  281. }
  282. impl Attachment {
  283. pub fn new(
  284. content_type: ContentType,
  285. content_transfer_encoding: ContentTransferEncoding,
  286. raw: Vec<u8>,
  287. ) -> Self {
  288. Attachment {
  289. content_type,
  290. content_transfer_encoding,
  291. raw,
  292. }
  293. }
  294. pub fn bytes(&self) -> &[u8] {
  295. &self.raw
  296. }
  297. fn get_text_recursive(&self, text: &mut Vec<u8>) {
  298. match self.content_type {
  299. ContentType::Text { .. } => {
  300. text.extend(decode(self, None));
  301. }
  302. ContentType::Multipart {
  303. ref kind,
  304. ref subattachments,
  305. ..
  306. } => match kind {
  307. MultipartType::Alternative => {
  308. for a in subattachments {
  309. if let ContentType::Text {
  310. kind: Text::Plain, ..
  311. } = a.content_type
  312. {
  313. a.get_text_recursive(text);
  314. break;
  315. }
  316. }
  317. }
  318. _ => {
  319. for a in subattachments {
  320. a.get_text_recursive(text)
  321. }
  322. }
  323. },
  324. _ => {}
  325. }
  326. }
  327. pub fn text(&self) -> String {
  328. let mut text = Vec::with_capacity(self.raw.len());
  329. self.get_text_recursive(&mut text);
  330. String::from_utf8_lossy(text.as_slice().trim()).into()
  331. }
  332. pub fn description(&self) -> Vec<String> {
  333. self.attachments().iter().map(Attachment::text).collect()
  334. }
  335. pub fn mime_type(&self) -> String {
  336. format!("{}", self.content_type).to_string()
  337. }
  338. pub fn attachments(&self) -> Vec<Attachment> {
  339. let mut ret = Vec::new();
  340. fn count_recursive(att: &Attachment, ret: &mut Vec<Attachment>) {
  341. match att.content_type {
  342. ContentType::Multipart {
  343. subattachments: ref sub_att_vec,
  344. ..
  345. } => {
  346. ret.push(att.clone());
  347. // FIXME: Wrong count
  348. for a in sub_att_vec {
  349. count_recursive(a, ret);
  350. }
  351. }
  352. _ => ret.push(att.clone()),
  353. }
  354. }
  355. count_recursive(&self, &mut ret);
  356. ret
  357. }
  358. pub fn count_attachments(&self) -> usize {
  359. self.attachments().len()
  360. }
  361. pub fn content_type(&self) -> &ContentType {
  362. &self.content_type
  363. }
  364. pub fn content_transfer_encoding(&self) -> &ContentTransferEncoding {
  365. &self.content_transfer_encoding
  366. }
  367. pub fn is_text(&self) -> bool {
  368. match self.content_type {
  369. ContentType::Text { .. } => true,
  370. _ => false,
  371. }
  372. }
  373. pub fn is_html(&self) -> bool {
  374. match self.content_type {
  375. ContentType::Text {
  376. kind: Text::Html, ..
  377. } => true,
  378. ContentType::Text {
  379. kind: Text::Plain, ..
  380. } => false,
  381. ContentType::Multipart {
  382. kind: MultipartType::Alternative,
  383. ref subattachments,
  384. ..
  385. } => {
  386. for a in subattachments.iter() {
  387. if let ContentType::Text {
  388. kind: Text::Plain, ..
  389. } = a.content_type
  390. {
  391. return false;
  392. }
  393. }
  394. true
  395. }
  396. ContentType::Multipart {
  397. kind: MultipartType::Signed,
  398. ref subattachments,
  399. ..
  400. } => subattachments
  401. .iter()
  402. .find(|s| s.content_type != ContentType::PGPSignature)
  403. .map(Attachment::is_html)
  404. .unwrap_or(false),
  405. ContentType::Multipart {
  406. ref subattachments, ..
  407. } => subattachments
  408. .iter()
  409. .fold(true, |acc, a| match &a.content_type {
  410. ContentType::Text {
  411. kind: Text::Plain, ..
  412. } => false,
  413. ContentType::Text {
  414. kind: Text::Html, ..
  415. } => acc,
  416. ContentType::Multipart {
  417. kind: MultipartType::Alternative,
  418. ..
  419. } => a.is_html(),
  420. _ => acc,
  421. }),
  422. _ => false,
  423. }
  424. }
  425. }
  426. pub fn interpret_format_flowed(_t: &str) -> String {
  427. //let mut n = String::with_capacity(t.len());
  428. unimplemented!()
  429. }
  430. fn decode_rfc822(_raw: &[u8]) -> Attachment {
  431. let builder = AttachmentBuilder::new(b"");
  432. builder.build()
  433. /*
  434. debug!("raw is\n{:?}", str::from_utf8(raw).unwrap());
  435. let e = match Envelope::from_bytes(raw) {
  436. Some(e) => e,
  437. None => {
  438. debug!("error in parsing mail");
  439. let error_msg = b"Mail cannot be shown because of errors.";
  440. let mut builder = AttachmentBuilder::new(error_msg);
  441. return builder.build();
  442. }
  443. };
  444. e.body(None)
  445. */
  446. }
  447. type Filter<'a> = Box<FnMut(&'a Attachment, &mut Vec<u8>) -> () + 'a>;
  448. fn decode_rec_helper<'a>(a: &'a Attachment, filter: &mut Option<Filter<'a>>) -> Vec<u8> {
  449. match a.content_type {
  450. ContentType::Unsupported { .. } => Vec::new(),
  451. ContentType::Text { .. } => decode_helper(a, filter),
  452. ContentType::PGPSignature => a.content_type.to_string().into_bytes(),
  453. ContentType::MessageRfc822 => {
  454. let temp = decode_rfc822(&a.raw);
  455. decode_rec(&temp, None)
  456. }
  457. ContentType::Multipart {
  458. ref kind,
  459. ref subattachments,
  460. ..
  461. } => match kind {
  462. MultipartType::Alternative => {
  463. for a in subattachments {
  464. if let ContentType::Text {
  465. kind: Text::Plain, ..
  466. } = a.content_type
  467. {
  468. return decode_helper(a, filter);
  469. }
  470. }
  471. decode_helper(a, filter)
  472. }
  473. _ => {
  474. let mut vec = Vec::new();
  475. for a in subattachments {
  476. vec.extend(decode_rec_helper(a, filter));
  477. }
  478. vec
  479. }
  480. },
  481. }
  482. }
  483. pub fn decode_rec<'a>(a: &'a Attachment, mut filter: Option<Filter<'a>>) -> Vec<u8> {
  484. decode_rec_helper(a, &mut filter)
  485. }
  486. fn decode_helper<'a>(a: &'a Attachment, filter: &mut Option<Filter<'a>>) -> Vec<u8> {
  487. let charset = match a.content_type {
  488. ContentType::Text { charset: c, .. } => c,
  489. _ => Default::default(),
  490. };
  491. let bytes = match a.content_transfer_encoding {
  492. ContentTransferEncoding::Base64 => match BASE64_MIME.decode(a.bytes()) {
  493. Ok(v) => v,
  494. _ => a.bytes().to_vec(),
  495. },
  496. ContentTransferEncoding::QuotedPrintable => parser::quoted_printable_bytes(a.bytes())
  497. .to_full_result()
  498. .unwrap(),
  499. ContentTransferEncoding::_7Bit
  500. | ContentTransferEncoding::_8Bit
  501. | ContentTransferEncoding::Other { .. } => a.bytes().to_vec(),
  502. };
  503. let mut ret = if a.content_type.is_text() {
  504. if let Ok(v) = parser::decode_charset(&bytes, charset) {
  505. v.into_bytes()
  506. } else {
  507. a.bytes().to_vec()
  508. }
  509. } else {
  510. bytes.to_vec()
  511. };
  512. if let Some(filter) = filter {
  513. filter(a, &mut ret);
  514. }
  515. ret
  516. }
  517. pub fn decode<'a>(a: &'a Attachment, mut filter: Option<Filter<'a>>) -> Vec<u8> {
  518. decode_helper(a, &mut filter)
  519. }