(
&mut self,
uid: u64,
)
| 445 | } |
| 446 | |
| 447 | fn fetch_message_content( |
| 448 | &mut self, |
| 449 | uid: u64, |
| 450 | ) -> Result<Option<EmailMessageContent>, EmailServiceError> { |
| 451 | let command = if self.gmail_thread_id_capable { |
| 452 | format!("UID FETCH {uid} (UID FLAGS INTERNALDATE X-GM-THRID BODY.PEEK[])") |
| 453 | } else { |
| 454 | format!("UID FETCH {uid} (UID FLAGS INTERNALDATE BODY.PEEK[])") |
| 455 | }; |
| 456 | let output = self.run_command(&command)?; |
| 457 | |
| 458 | let Some(fetch_line) = output |
| 459 | .lines |
| 460 | .iter() |
| 461 | .find(|line| line.starts_with("* ") && line.contains(" FETCH (")) |
| 462 | else { |
| 463 | return Ok(None); |
| 464 | }; |
| 465 | |
| 466 | let literal = output.literals.first().ok_or_else(|| { |
| 467 | EmailServiceError::Api("IMAP FETCH response missing message body literal".to_string()) |
| 468 | })?; |
| 469 | |
| 470 | let parsed_uid = capture_numeric_token(fetch_line, "UID") |
| 471 | .and_then(|value| value.parse::<u64>().ok()) |
| 472 | .unwrap_or(uid); |
| 473 | let thread_id = capture_numeric_token(fetch_line, "X-GM-THRID"); |
| 474 | let flags = capture_parenthesized_token(fetch_line, "FLAGS") |
| 475 | .map(|value| parse_flags(&value)) |
| 476 | .unwrap_or_default(); |
| 477 | let internal_date = capture_quoted_token(fetch_line, "INTERNALDATE"); |
| 478 | |
| 479 | let (headers, body) = split_headers_and_body(literal); |
| 480 | let from = headers.get("from").cloned(); |
| 481 | let subject = headers.get("subject").cloned(); |
| 482 | let date = headers.get("date").cloned().or(internal_date); |
| 483 | let (text_body, html_body) = extract_text_and_html_bodies(&headers, body); |
| 484 | |
| 485 | Ok(Some(EmailMessageContent { |
| 486 | metadata: EmailMessageMetadata { |
| 487 | id: parsed_uid.to_string(), |
| 488 | thread_id, |
| 489 | from, |
| 490 | subject, |
| 491 | date, |
| 492 | snippet: text_body |
| 493 | .as_deref() |
| 494 | .map(|value| value.chars().take(240).collect::<String>()) |
| 495 | .filter(|value| !value.trim().is_empty()), |
| 496 | internal_date_ms: None, |
| 497 | label_ids: flags, |
| 498 | }, |
| 499 | headers, |
| 500 | text_body, |
| 501 | html_body, |
| 502 | })) |
| 503 | } |
| 504 |
no test coverage detected