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.

738 lines
25KB

  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::address::StrBuilder;
  22. use crate::email::parser;
  23. use crate::email::parser::BytesExt;
  24. use crate::email::EnvelopeWrapper;
  25. use core::fmt;
  26. use core::str;
  27. use data_encoding::BASE64_MIME;
  28. pub use crate::email::attachment_types::*;
  29. #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
  30. pub struct AttachmentBuilder {
  31. pub content_type: ContentType,
  32. pub content_transfer_encoding: ContentTransferEncoding,
  33. pub raw: Vec<u8>,
  34. pub body: StrBuilder,
  35. }
  36. impl AttachmentBuilder {
  37. pub fn new(content: &[u8]) -> Self {
  38. let (headers, body) = match parser::attachment(content).to_full_result() {
  39. Ok(v) => v,
  40. Err(_) => {
  41. debug!("error in parsing attachment");
  42. debug!("\n-------------------------------");
  43. debug!("{}\n", ::std::string::String::from_utf8_lossy(content));
  44. debug!("-------------------------------\n");
  45. return AttachmentBuilder {
  46. content_type: Default::default(),
  47. content_transfer_encoding: ContentTransferEncoding::_7Bit,
  48. raw: content.to_vec(),
  49. body: StrBuilder {
  50. length: content.len(),
  51. offset: 0,
  52. },
  53. };
  54. }
  55. };
  56. let raw = content.into();
  57. let body = StrBuilder {
  58. offset: content.len() - body.len(),
  59. length: body.len(),
  60. };
  61. let mut builder = AttachmentBuilder {
  62. raw,
  63. body,
  64. ..Default::default()
  65. };
  66. for (name, value) in headers {
  67. if name.eq_ignore_ascii_case(b"content-type") {
  68. builder.set_content_type_from_bytes(value);
  69. } else if name.eq_ignore_ascii_case(b"content-transfer-encoding") {
  70. builder.set_content_transfer_encoding(ContentTransferEncoding::from(value));
  71. }
  72. }
  73. builder
  74. }
  75. pub fn raw(&self) -> &[u8] {
  76. &self.raw
  77. }
  78. pub fn body(&self) -> &[u8] {
  79. self.body.display_bytes(&self.raw)
  80. }
  81. pub fn set_raw(&mut self, raw: Vec<u8>) -> &mut Self {
  82. self.raw = raw;
  83. self
  84. }
  85. pub fn set_content_type(&mut self, val: ContentType) -> &mut Self {
  86. self.content_type = val;
  87. self
  88. }
  89. pub fn content_type(&self) -> &ContentType {
  90. &self.content_type
  91. }
  92. pub fn set_content_transfer_encoding(&mut self, val: ContentTransferEncoding) -> &mut Self {
  93. self.content_transfer_encoding = val;
  94. self
  95. }
  96. pub fn content_transfer_encoding(&self) -> &ContentTransferEncoding {
  97. &self.content_transfer_encoding
  98. }
  99. pub fn set_content_type_from_bytes(&mut self, value: &[u8]) -> &mut Self {
  100. match parser::content_type(value).to_full_result() {
  101. Ok((ct, cst, params)) => {
  102. if ct.eq_ignore_ascii_case(b"multipart") {
  103. let mut boundary = None;
  104. for (n, v) in params {
  105. if n.eq_ignore_ascii_case(b"boundary") {
  106. boundary = Some(v);
  107. break;
  108. }
  109. }
  110. assert!(boundary.is_some());
  111. let boundary = boundary.unwrap().to_vec();
  112. let parts = Self::parts(self.body(), &boundary);
  113. self.content_type = ContentType::Multipart {
  114. boundary,
  115. kind: MultipartType::from(cst),
  116. parts,
  117. };
  118. } else if ct.eq_ignore_ascii_case(b"text") {
  119. self.content_type = ContentType::Text {
  120. kind: Text::Plain,
  121. charset: Charset::UTF8,
  122. };
  123. for (n, v) in params {
  124. if n.eq_ignore_ascii_case(b"charset") {
  125. if let ContentType::Text {
  126. charset: ref mut c, ..
  127. } = self.content_type
  128. {
  129. *c = Charset::from(v);
  130. }
  131. break;
  132. }
  133. }
  134. if cst.eq_ignore_ascii_case(b"html") {
  135. if let ContentType::Text {
  136. kind: ref mut k, ..
  137. } = self.content_type
  138. {
  139. *k = Text::Html;
  140. }
  141. } else if !cst.eq_ignore_ascii_case(b"plain") {
  142. if let ContentType::Text {
  143. kind: ref mut k, ..
  144. } = self.content_type
  145. {
  146. *k = Text::Other { tag: cst.into() };
  147. }
  148. }
  149. } else if ct.eq_ignore_ascii_case(b"message") && cst.eq_ignore_ascii_case(b"rfc822")
  150. {
  151. self.content_type = ContentType::MessageRfc822;
  152. } else if ct.eq_ignore_ascii_case(b"application")
  153. && cst.eq_ignore_ascii_case(b"pgp-signature")
  154. {
  155. self.content_type = ContentType::PGPSignature;
  156. } else {
  157. let mut name: Option<String> = None;
  158. for (n, v) in params {
  159. if n.eq_ignore_ascii_case(b"name") {
  160. name = Some(String::from_utf8_lossy(v).into());
  161. break;
  162. }
  163. }
  164. let mut tag: Vec<u8> = Vec::with_capacity(ct.len() + cst.len() + 1);
  165. tag.extend(ct);
  166. tag.push(b'/');
  167. tag.extend(cst);
  168. self.content_type = ContentType::Other { tag, name };
  169. }
  170. }
  171. Err(e) => {
  172. debug!(
  173. "parsing error in content_type: {:?} {:?}",
  174. String::from_utf8_lossy(value),
  175. e
  176. );
  177. }
  178. }
  179. self
  180. }
  181. pub fn build(self) -> Attachment {
  182. Attachment {
  183. content_type: self.content_type,
  184. content_transfer_encoding: self.content_transfer_encoding,
  185. raw: self.raw,
  186. body: self.body,
  187. }
  188. }
  189. pub fn parts(raw: &[u8], boundary: &[u8]) -> Vec<Attachment> {
  190. if raw.is_empty() {
  191. return Vec::new();
  192. }
  193. match parser::parts(raw, boundary).to_full_result() {
  194. Ok(attachments) => {
  195. let mut vec = Vec::with_capacity(attachments.len());
  196. for a in attachments {
  197. let mut builder = AttachmentBuilder::default();
  198. let (headers, body) = match parser::attachment(&a).to_full_result() {
  199. Ok(v) => v,
  200. Err(_) => {
  201. debug!("error in parsing attachment");
  202. debug!("\n-------------------------------");
  203. debug!("{}\n", ::std::string::String::from_utf8_lossy(a));
  204. debug!("-------------------------------\n");
  205. continue;
  206. }
  207. };
  208. builder.raw = a.into();
  209. builder.body = StrBuilder {
  210. offset: a.len() - body.len(),
  211. length: body.len(),
  212. };
  213. for (name, value) in headers {
  214. if name.eq_ignore_ascii_case(b"content-type") {
  215. builder.set_content_type_from_bytes(value);
  216. } else if name.eq_ignore_ascii_case(b"content-transfer-encoding") {
  217. builder.set_content_transfer_encoding(ContentTransferEncoding::from(
  218. value,
  219. ));
  220. }
  221. }
  222. vec.push(builder.build());
  223. }
  224. vec
  225. }
  226. a => {
  227. debug!(
  228. "error {:?}\n\traw: {:?}\n\tboundary: {:?}",
  229. a,
  230. str::from_utf8(raw).unwrap(),
  231. boundary
  232. );
  233. Vec::new()
  234. }
  235. }
  236. }
  237. }
  238. impl From<Attachment> for AttachmentBuilder {
  239. fn from(val: Attachment) -> Self {
  240. let Attachment {
  241. content_type,
  242. content_transfer_encoding,
  243. raw,
  244. body,
  245. } = val;
  246. AttachmentBuilder {
  247. content_type,
  248. content_transfer_encoding,
  249. raw,
  250. body,
  251. }
  252. }
  253. }
  254. impl From<AttachmentBuilder> for Attachment {
  255. fn from(val: AttachmentBuilder) -> Self {
  256. let AttachmentBuilder {
  257. content_type,
  258. content_transfer_encoding,
  259. raw,
  260. body,
  261. } = val;
  262. Attachment {
  263. content_type,
  264. content_transfer_encoding,
  265. raw,
  266. body,
  267. }
  268. }
  269. }
  270. /// Immutable attachment type.
  271. #[derive(Clone, Serialize, Deserialize, PartialEq)]
  272. pub struct Attachment {
  273. pub content_type: ContentType,
  274. pub content_transfer_encoding: ContentTransferEncoding,
  275. pub raw: Vec<u8>,
  276. pub body: StrBuilder,
  277. }
  278. impl fmt::Debug for Attachment {
  279. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  280. write!(f, "Attachment {{\n content_type: {:?},\n content_transfer_encoding: {:?},\n raw: Vec of {} bytes\n, body:\n{}\n}}",
  281. self.content_type,
  282. self.content_transfer_encoding,
  283. self.raw.len(),
  284. {
  285. let mut text = Vec::with_capacity(4096);
  286. self.get_text_recursive(&mut text);
  287. std::str::from_utf8(&text).map(std::string::ToString::to_string).unwrap_or_else(|e| format!("Unicode error {}", e))
  288. }
  289. )
  290. }
  291. }
  292. impl fmt::Display for Attachment {
  293. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  294. match self.content_type {
  295. ContentType::MessageRfc822 => {
  296. match EnvelopeWrapper::new(self.body.display_bytes(&self.raw).to_vec()) {
  297. Ok(wrapper) => write!(
  298. f,
  299. "message/rfc822: {} - {} - {}",
  300. wrapper.date(),
  301. wrapper.field_from_to_string(),
  302. wrapper.subject()
  303. ),
  304. Err(e) => write!(f, "{}", e),
  305. }
  306. }
  307. ContentType::PGPSignature => write!(f, "pgp signature {}", self.mime_type()),
  308. ContentType::OctetStream { ref name } => {
  309. write!(f, "{}", name.clone().unwrap_or_else(|| self.mime_type()))
  310. }
  311. ContentType::Other { .. } => write!(f, "Data attachment of type {}", self.mime_type()),
  312. ContentType::Text { .. } => write!(f, "Text attachment of type {}", self.mime_type()),
  313. ContentType::Multipart {
  314. parts: ref sub_att_vec,
  315. ..
  316. } => write!(
  317. f,
  318. "{} attachment with {} subs",
  319. self.mime_type(),
  320. sub_att_vec.len()
  321. ),
  322. }
  323. }
  324. }
  325. impl Attachment {
  326. pub fn new(
  327. content_type: ContentType,
  328. content_transfer_encoding: ContentTransferEncoding,
  329. raw: Vec<u8>,
  330. ) -> Self {
  331. Attachment {
  332. content_type,
  333. content_transfer_encoding,
  334. body: StrBuilder {
  335. length: raw.len(),
  336. offset: 0,
  337. },
  338. raw,
  339. }
  340. }
  341. pub fn raw(&self) -> &[u8] {
  342. &self.raw
  343. }
  344. pub fn body(&self) -> &[u8] {
  345. self.body.display_bytes(&self.raw)
  346. }
  347. pub fn part_boundaries(&self) -> Vec<StrBuilder> {
  348. if self.raw.is_empty() {
  349. return Vec::new();
  350. }
  351. match self.content_type {
  352. ContentType::Multipart { ref boundary, .. } => {
  353. match parser::multipart_parts(self.body(), boundary).to_full_result() {
  354. Ok(v) => v,
  355. Err(e) => {
  356. debug!("error in parsing attachment");
  357. debug!("\n-------------------------------");
  358. debug!("{}\n", ::std::string::String::from_utf8_lossy(&self.raw));
  359. debug!("-------------------------------\n");
  360. debug!("{:?}\n", e);
  361. Vec::new()
  362. }
  363. }
  364. }
  365. _ => Vec::new(),
  366. }
  367. }
  368. /* Call on the body of a multipart/mixed Envelope to check if there are attachments without
  369. * completely parsing them */
  370. pub fn check_if_has_attachments_quick(bytes: &[u8], boundary: &[u8]) -> bool {
  371. if bytes.is_empty() {
  372. return false;
  373. }
  374. // FIXME: check if any part is multipart/mixed as well
  375. match parser::multipart_parts(bytes, boundary).to_full_result() {
  376. Ok(parts) => {
  377. for p in parts {
  378. for (n, v) in crate::email::parser::HeaderIterator(p.display_bytes(bytes)) {
  379. if !n.eq_ignore_ascii_case(b"content-type") && !v.starts_with(b"text/") {
  380. return true;
  381. }
  382. }
  383. }
  384. }
  385. Err(e) => {
  386. debug!("error in parsing multipart_parts");
  387. debug!("\n-------------------------------");
  388. debug!("{}\n", ::std::string::String::from_utf8_lossy(bytes));
  389. debug!("-------------------------------\n");
  390. debug!("{:?}\n", e);
  391. }
  392. }
  393. false
  394. }
  395. fn get_text_recursive(&self, text: &mut Vec<u8>) {
  396. match self.content_type {
  397. ContentType::Text { .. } | ContentType::PGPSignature => {
  398. text.extend(decode(self, None));
  399. }
  400. ContentType::Multipart {
  401. ref kind,
  402. ref parts,
  403. ..
  404. } => match kind {
  405. MultipartType::Alternative => {
  406. for a in parts {
  407. if let ContentType::Text {
  408. kind: Text::Plain, ..
  409. } = a.content_type
  410. {
  411. a.get_text_recursive(text);
  412. break;
  413. }
  414. }
  415. }
  416. _ => {
  417. for a in parts {
  418. a.get_text_recursive(text)
  419. }
  420. }
  421. },
  422. _ => {}
  423. }
  424. }
  425. pub fn text(&self) -> String {
  426. let mut text = Vec::with_capacity(self.body.length);
  427. self.get_text_recursive(&mut text);
  428. String::from_utf8_lossy(text.as_slice().trim()).into()
  429. }
  430. pub fn description(&self) -> Vec<String> {
  431. self.attachments().iter().map(Attachment::text).collect()
  432. }
  433. pub fn mime_type(&self) -> String {
  434. format!("{}", self.content_type).to_string()
  435. }
  436. pub fn attachments(&self) -> Vec<Attachment> {
  437. let mut ret = Vec::new();
  438. fn count_recursive(att: &Attachment, ret: &mut Vec<Attachment>) {
  439. match att.content_type {
  440. ContentType::Multipart {
  441. parts: ref sub_att_vec,
  442. ..
  443. } => {
  444. ret.push(att.clone());
  445. // FIXME: Wrong count
  446. for a in sub_att_vec {
  447. count_recursive(a, ret);
  448. }
  449. }
  450. _ => ret.push(att.clone()),
  451. }
  452. }
  453. count_recursive(&self, &mut ret);
  454. ret
  455. }
  456. pub fn count_attachments(&self) -> usize {
  457. self.attachments().len()
  458. }
  459. pub fn content_type(&self) -> &ContentType {
  460. &self.content_type
  461. }
  462. pub fn content_transfer_encoding(&self) -> &ContentTransferEncoding {
  463. &self.content_transfer_encoding
  464. }
  465. pub fn is_text(&self) -> bool {
  466. match self.content_type {
  467. ContentType::Text { .. } => true,
  468. _ => false,
  469. }
  470. }
  471. pub fn is_html(&self) -> bool {
  472. match self.content_type {
  473. ContentType::Text {
  474. kind: Text::Html, ..
  475. } => true,
  476. ContentType::Text {
  477. kind: Text::Plain, ..
  478. } => false,
  479. ContentType::Multipart {
  480. kind: MultipartType::Alternative,
  481. ref parts,
  482. ..
  483. } => {
  484. for a in parts.iter() {
  485. if let ContentType::Text {
  486. kind: Text::Plain, ..
  487. } = a.content_type
  488. {
  489. return false;
  490. }
  491. }
  492. true
  493. }
  494. ContentType::Multipart {
  495. kind: MultipartType::Signed,
  496. ref parts,
  497. ..
  498. } => parts
  499. .iter()
  500. .find(|s| s.content_type != ContentType::PGPSignature)
  501. .map(Attachment::is_html)
  502. .unwrap_or(false),
  503. ContentType::Multipart { ref parts, .. } => {
  504. parts.iter().fold(true, |acc, a| match &a.content_type {
  505. ContentType::Text {
  506. kind: Text::Plain, ..
  507. } => false,
  508. ContentType::Text {
  509. kind: Text::Html, ..
  510. } => acc,
  511. ContentType::Multipart {
  512. kind: MultipartType::Alternative,
  513. ..
  514. } => a.is_html(),
  515. _ => acc,
  516. })
  517. }
  518. _ => false,
  519. }
  520. }
  521. pub fn is_signed(&self) -> bool {
  522. match self.content_type {
  523. ContentType::Multipart {
  524. kind: MultipartType::Signed,
  525. ..
  526. } => true,
  527. _ => false,
  528. }
  529. }
  530. pub fn into_raw(&self) -> String {
  531. let mut ret = String::with_capacity(2 * self.raw.len());
  532. fn into_raw_helper(a: &Attachment, ret: &mut String) {
  533. ret.extend(
  534. format!(
  535. "Content-Transfer-Encoding: {}\n",
  536. a.content_transfer_encoding
  537. )
  538. .chars(),
  539. );
  540. match &a.content_type {
  541. ContentType::Text { kind: _, charset } => {
  542. ret.extend(
  543. format!("Content-Type: {}; charset={}\n\n", a.content_type, charset)
  544. .chars(),
  545. );
  546. ret.extend(String::from_utf8_lossy(a.body()).chars());
  547. }
  548. ContentType::Multipart {
  549. boundary,
  550. kind,
  551. parts,
  552. } => {
  553. let boundary = String::from_utf8_lossy(boundary);
  554. ret.extend(format!("Content-Type: {}; boundary={}", kind, boundary).chars());
  555. if *kind == MultipartType::Signed {
  556. ret.extend(
  557. "; micalg=pgp-sha512; protocol=\"application/pgp-signature\"".chars(),
  558. );
  559. }
  560. ret.push('\n');
  561. let boundary_start = format!("\n--{}\n", boundary);
  562. for p in parts {
  563. ret.extend(boundary_start.chars());
  564. into_raw_helper(p, ret);
  565. }
  566. ret.extend(format!("--{}--\n\n", boundary).chars());
  567. }
  568. ContentType::MessageRfc822 => {
  569. ret.extend(format!("Content-Type: {}\n\n", a.content_type).chars());
  570. ret.extend(String::from_utf8_lossy(a.body()).chars());
  571. }
  572. ContentType::PGPSignature => {
  573. ret.extend(format!("Content-Type: {}\n\n", a.content_type).chars());
  574. ret.extend(String::from_utf8_lossy(a.body()).chars());
  575. }
  576. ContentType::OctetStream { ref name } => {
  577. if let Some(name) = name {
  578. ret.extend(
  579. format!("Content-Type: {}; name={}\n\n", a.content_type, name).chars(),
  580. );
  581. } else {
  582. ret.extend(format!("Content-Type: {}\n\n", a.content_type).chars());
  583. }
  584. ret.push_str(&BASE64_MIME.encode(a.body()).trim());
  585. }
  586. _ => {
  587. ret.extend(format!("Content-Type: {}\n\n", a.content_type).chars());
  588. ret.extend(String::from_utf8_lossy(a.body()).chars());
  589. }
  590. }
  591. }
  592. into_raw_helper(self, &mut ret);
  593. ret
  594. }
  595. }
  596. pub fn interpret_format_flowed(_t: &str) -> String {
  597. unimplemented!()
  598. }
  599. fn decode_rfc822(_raw: &[u8]) -> Attachment {
  600. // FIXME
  601. let builder = AttachmentBuilder::new(b"message/rfc822 cannot be displayed");
  602. builder.build()
  603. }
  604. type Filter<'a> = Box<dyn FnMut(&'a Attachment, &mut Vec<u8>) -> () + 'a>;
  605. fn decode_rec_helper<'a>(a: &'a Attachment, filter: &mut Option<Filter<'a>>) -> Vec<u8> {
  606. match a.content_type {
  607. ContentType::Other { .. } => Vec::new(),
  608. ContentType::Text { .. } => decode_helper(a, filter),
  609. ContentType::OctetStream { ref name } => name
  610. .clone()
  611. .unwrap_or_else(|| a.mime_type())
  612. .to_string()
  613. .into_bytes(),
  614. ContentType::PGPSignature => Vec::new(),
  615. ContentType::MessageRfc822 => {
  616. let temp = decode_rfc822(a.body());
  617. decode_rec(&temp, None)
  618. }
  619. ContentType::Multipart {
  620. ref kind,
  621. ref parts,
  622. ..
  623. } => match kind {
  624. MultipartType::Alternative => {
  625. for a in parts {
  626. if let ContentType::Text {
  627. kind: Text::Plain, ..
  628. } = a.content_type
  629. {
  630. return decode_helper(a, filter);
  631. }
  632. }
  633. decode_helper(a, filter)
  634. }
  635. MultipartType::Signed => {
  636. let mut vec = Vec::new();
  637. for a in parts {
  638. vec.extend(decode_rec_helper(a, filter));
  639. }
  640. vec.extend(decode_helper(a, filter));
  641. vec
  642. }
  643. _ => {
  644. let mut vec = Vec::new();
  645. for a in parts {
  646. vec.extend(decode_rec_helper(a, filter));
  647. }
  648. vec
  649. }
  650. },
  651. }
  652. }
  653. pub fn decode_rec<'a>(a: &'a Attachment, mut filter: Option<Filter<'a>>) -> Vec<u8> {
  654. decode_rec_helper(a, &mut filter)
  655. }
  656. fn decode_helper<'a>(a: &'a Attachment, filter: &mut Option<Filter<'a>>) -> Vec<u8> {
  657. let charset = match a.content_type {
  658. ContentType::Text { charset: c, .. } => c,
  659. _ => Default::default(),
  660. };
  661. let bytes = match a.content_transfer_encoding {
  662. ContentTransferEncoding::Base64 => match BASE64_MIME.decode(a.body()) {
  663. Ok(v) => v,
  664. _ => a.body().to_vec(),
  665. },
  666. ContentTransferEncoding::QuotedPrintable => parser::quoted_printable_bytes(a.body())
  667. .to_full_result()
  668. .unwrap(),
  669. ContentTransferEncoding::_7Bit
  670. | ContentTransferEncoding::_8Bit
  671. | ContentTransferEncoding::Other { .. } => a.body().to_vec(),
  672. };
  673. let mut ret = if a.content_type.is_text() {
  674. if let Ok(v) = parser::decode_charset(&bytes, charset) {
  675. v.into_bytes()
  676. } else {
  677. a.body().to_vec()
  678. }
  679. } else {
  680. bytes.to_vec()
  681. };
  682. if let Some(filter) = filter {
  683. filter(a, &mut ret);
  684. }
  685. ret
  686. }
  687. pub fn decode<'a>(a: &'a Attachment, mut filter: Option<Filter<'a>>) -> Vec<u8> {
  688. decode_helper(a, &mut filter)
  689. }