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.
 
 
 
 

480 lines
16 KiB

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