diff --git a/src/html.rs b/src/html.rs
index fec82589f0..20e1ba319f 100644
--- a/src/html.rs
+++ b/src/html.rs
@@ -9,7 +9,7 @@
use std::mem;
-use anyhow::{Context as _, Result};
+use anyhow::{Context as _, Result, ensure};
use base64::Engine as _;
use mailparse::ParsedContentType;
use mime::Mime;
@@ -17,10 +17,12 @@ use mime::Mime;
use crate::context::Context;
use crate::headerdef::{HeaderDef, HeaderDefMap};
use crate::log::warn;
-use crate::message::{self, Message, MsgId};
+use crate::message::{Message, MsgId};
use crate::mimeparser::parse_message_id;
-use crate::param::Param::SendHtml;
+use crate::param::{Param::SendHtml, Params};
use crate::plaintext::PlainText;
+use crate::sql;
+use crate::tools::{buf_compress, buf_decompress};
impl Message {
/// Check if the message can be retrieved as HTML.
@@ -258,28 +260,71 @@ impl MsgId {
/// NB: we do not save raw mime unconditionally in the database to save space.
/// The corresponding ffi-function is `dc_get_msg_html()`.
pub async fn get_html(self, context: &Context) -> Result> {
- // If there are many concurrent db readers, going to the queue earlier makes sense.
- let (param, rawmime) = tokio::join!(
- self.get_param(context),
- message::get_mime_headers(context, self)
- );
- if let Some(html) = param?.get(SendHtml) {
+ let (param, headers, compressed) = context
+ .sql
+ .query_row(
+ "SELECT param, mime_headers, mime_compressed FROM msgs WHERE id=?",
+ (self,),
+ |row| {
+ let param: String = row.get(0)?;
+ let param: Params = param.parse().unwrap_or_default();
+ let headers = sql::row_get_vec(row, 1)?;
+ let compressed: bool = row.get(2)?;
+ Ok((param, headers, compressed))
+ },
+ )
+ .await?;
+ if let Some(html) = param.get(SendHtml) {
return Ok(Some(html.to_string()));
}
+ let from_rawmime = |rawmime: Vec| async move {
+ if !rawmime.is_empty() {
+ match HtmlMsgParser::from_bytes(context, &rawmime).await {
+ Err(err) => {
+ warn!(context, "get_html: parser error: {:#}", err);
+ Ok(None)
+ }
+ Ok((parser, _)) => Ok(Some(parser.html)),
+ }
+ } else {
+ warn!(context, "get_html: no mime for {}", self);
+ Ok(None)
+ }
+ };
- let rawmime = rawmime?;
- if !rawmime.is_empty() {
- match HtmlMsgParser::from_bytes(context, &rawmime).await {
- Err(err) => {
- warn!(context, "get_html: parser error: {:#}", err);
- Ok(None)
+ if compressed {
+ return from_rawmime(buf_decompress(&headers)?).await;
+ }
+ let headers2 = headers.clone();
+ let compressed = match tokio::task::block_in_place(move || buf_compress(&headers2)) {
+ Err(e) => {
+ warn!(context, "get_mime_headers: buf_compress() failed: {}", e);
+ return from_rawmime(headers).await;
+ }
+ Ok(o) => o,
+ };
+ let update = |conn: &mut rusqlite::Connection| {
+ match conn.execute(
+ "
+UPDATE msgs SET mime_headers=?, mime_compressed=1
+WHERE id=? AND mime_headers!='' AND mime_compressed=0",
+ (compressed, self),
+ ) {
+ Ok(rows_updated) => ensure!(rows_updated <= 1),
+ Err(e) => {
+ warn!(context, "get_mime_headers: UPDATE failed: {}", e);
+ return Err(e.into());
}
- Ok((parser, _)) => Ok(Some(parser.html)),
}
- } else {
- warn!(context, "get_html: no mime for {}", self);
- Ok(None)
+ Ok(())
+ };
+ if let Err(e) = context.sql.call_write(update).await {
+ warn!(
+ context,
+ "get_mime_headers: failed to update mime_headers: {}", e
+ );
}
+ return from_rawmime(headers).await;
}
}
diff --git a/src/message.rs b/src/message.rs
index 0676daf7d8..f97f6ed956 100644
--- a/src/message.rs
+++ b/src/message.rs
@@ -32,13 +32,12 @@ use crate::mimeparser::{SystemMessage, parse_message_id};
use crate::param::{Param, Params};
use crate::pgp::split_armored_data;
use crate::reaction::get_msg_reactions;
-use crate::sql;
use crate::summary::Summary;
use crate::sync::SyncData;
use crate::tools::create_outgoing_rfc724_mid;
use crate::tools::{
- buf_compress, buf_decompress, get_filebytes, get_filemeta, gm2local_offset, read_file,
- sanitize_filename, time, timestamp_to_str,
+ get_filebytes, get_filemeta, gm2local_offset, read_file, sanitize_filename, time,
+ timestamp_to_str,
};
/// Message ID, including reserved IDs.
@@ -1617,62 +1616,6 @@ pub(crate) fn guess_msgtype_from_path_suffix(path: &Path) -> Option<(Viewtype, &
Some(info)
}
-/// Get the raw mime-headers of the given message.
-/// Raw headers are saved for large messages
-/// that need a "Show full message..."
-/// to see HTML part.
-///
-/// Returns an empty vector if there are no headers saved for the given message.
-pub(crate) async fn get_mime_headers(context: &Context, msg_id: MsgId) -> Result> {
- let (headers, compressed) = context
- .sql
- .query_row(
- "SELECT mime_headers, mime_compressed FROM msgs WHERE id=?",
- (msg_id,),
- |row| {
- let headers = sql::row_get_vec(row, 0)?;
- let compressed: bool = row.get(1)?;
- Ok((headers, compressed))
- },
- )
- .await?;
- if compressed {
- return buf_decompress(&headers);
- }
-
- let headers2 = headers.clone();
- let compressed = match tokio::task::block_in_place(move || buf_compress(&headers2)) {
- Err(e) => {
- warn!(context, "get_mime_headers: buf_compress() failed: {}", e);
- return Ok(headers);
- }
- Ok(o) => o,
- };
- let update = |conn: &mut rusqlite::Connection| {
- match conn.execute(
- "\
- UPDATE msgs SET mime_headers=?, mime_compressed=1 \
- WHERE id=? AND mime_headers!='' AND mime_compressed=0",
- (compressed, msg_id),
- ) {
- Ok(rows_updated) => ensure!(rows_updated <= 1),
- Err(e) => {
- warn!(context, "get_mime_headers: UPDATE failed: {}", e);
- return Err(e.into());
- }
- }
- Ok(())
- };
- if let Err(e) = context.sql.call_write(update).await {
- warn!(
- context,
- "get_mime_headers: failed to update mime_headers: {}", e
- );
- }
-
- Ok(headers)
-}
-
/// Delete a single message from the database, including references in other tables.
/// This may be called in batches; the final events are emitted in delete_msgs_locally_done() then.
pub(crate) async fn delete_msg_locally(context: &Context, msg: &Message) -> Result<()> {
diff --git a/src/receive_imf/receive_imf_tests.rs b/src/receive_imf/receive_imf_tests.rs
index 8209de31b9..4325a766e0 100644
--- a/src/receive_imf/receive_imf_tests.rs
+++ b/src/receive_imf/receive_imf_tests.rs
@@ -1680,8 +1680,8 @@ async fn test_save_mime_headers_off() -> anyhow::Result<()> {
let msg = bob.recv_msg(&alice.pop_sent_msg().await).await;
assert_eq!(msg.get_text(), "hi!");
- let mime = message::get_mime_headers(&bob, msg.id).await?;
- assert!(mime.is_empty());
+ let html = msg.id.get_html(&bob).await?;
+ assert!(html.is_none());
Ok(())
}