|
9 | 9 |
|
10 | 10 | use std::mem; |
11 | 11 |
|
12 | | -use anyhow::{Context as _, Result}; |
| 12 | +use anyhow::{Context as _, Result, ensure}; |
13 | 13 | use base64::Engine as _; |
14 | 14 | use mailparse::ParsedContentType; |
15 | 15 | use mime::Mime; |
16 | 16 |
|
17 | 17 | use crate::context::Context; |
18 | 18 | use crate::headerdef::{HeaderDef, HeaderDefMap}; |
19 | 19 | use crate::log::warn; |
20 | | -use crate::message::{self, Message, MsgId}; |
| 20 | +use crate::message::{Message, MsgId}; |
21 | 21 | use crate::mimeparser::parse_message_id; |
22 | | -use crate::param::Param::SendHtml; |
| 22 | +use crate::param::{Param::SendHtml, Params}; |
23 | 23 | use crate::plaintext::PlainText; |
| 24 | +use crate::sql; |
| 25 | +use crate::tools::{buf_compress, buf_decompress}; |
24 | 26 |
|
25 | 27 | impl Message { |
26 | 28 | /// Check if the message can be retrieved as HTML. |
@@ -258,28 +260,71 @@ impl MsgId { |
258 | 260 | /// NB: we do not save raw mime unconditionally in the database to save space. |
259 | 261 | /// The corresponding ffi-function is `dc_get_msg_html()`. |
260 | 262 | pub async fn get_html(self, context: &Context) -> Result<Option<String>> { |
261 | | - // If there are many concurrent db readers, going to the queue earlier makes sense. |
262 | | - let (param, rawmime) = tokio::join!( |
263 | | - self.get_param(context), |
264 | | - message::get_mime_headers(context, self) |
265 | | - ); |
266 | | - if let Some(html) = param?.get(SendHtml) { |
| 263 | + let (param, headers, compressed) = context |
| 264 | + .sql |
| 265 | + .query_row( |
| 266 | + "SELECT param, mime_headers, mime_compressed FROM msgs WHERE id=?", |
| 267 | + (self,), |
| 268 | + |row| { |
| 269 | + let param: String = row.get(0)?; |
| 270 | + let param: Params = param.parse().unwrap_or_default(); |
| 271 | + let headers = sql::row_get_vec(row, 1)?; |
| 272 | + let compressed: bool = row.get(2)?; |
| 273 | + Ok((param, headers, compressed)) |
| 274 | + }, |
| 275 | + ) |
| 276 | + .await?; |
| 277 | + if let Some(html) = param.get(SendHtml) { |
267 | 278 | return Ok(Some(html.to_string())); |
268 | 279 | } |
| 280 | + let from_rawmime = |rawmime: Vec<u8>| { |
| 281 | + if !rawmime.is_empty() { |
| 282 | + match HtmlMsgParser::from_bytes(context, &rawmime) { |
| 283 | + Err(err) => { |
| 284 | + warn!(context, "get_html: parser error: {:#}", err); |
| 285 | + Ok(None) |
| 286 | + } |
| 287 | + Ok((parser, _)) => Ok(Some(parser.html)), |
| 288 | + } |
| 289 | + } else { |
| 290 | + warn!(context, "get_html: no mime for {}", self); |
| 291 | + Ok(None) |
| 292 | + } |
| 293 | + }; |
269 | 294 |
|
270 | | - let rawmime = rawmime?; |
271 | | - if !rawmime.is_empty() { |
272 | | - match HtmlMsgParser::from_bytes(context, &rawmime) { |
273 | | - Err(err) => { |
274 | | - warn!(context, "get_html: parser error: {:#}", err); |
275 | | - Ok(None) |
| 295 | + if compressed { |
| 296 | + return from_rawmime(buf_decompress(&headers)?).await; |
| 297 | + } |
| 298 | + let headers2 = headers.clone(); |
| 299 | + let compressed = match tokio::task::block_in_place(move || buf_compress(&headers2)) { |
| 300 | + Err(e) => { |
| 301 | + warn!(context, "get_mime_headers: buf_compress() failed: {}", e); |
| 302 | + return from_rawmime(headers).await; |
| 303 | + } |
| 304 | + Ok(o) => o, |
| 305 | + }; |
| 306 | + let update = |conn: &mut rusqlite::Connection| { |
| 307 | + match conn.execute( |
| 308 | + " |
| 309 | +UPDATE msgs SET mime_headers=?, mime_compressed=1 |
| 310 | +WHERE id=? AND mime_headers!='' AND mime_compressed=0", |
| 311 | + (compressed, self), |
| 312 | + ) { |
| 313 | + Ok(rows_updated) => ensure!(rows_updated <= 1), |
| 314 | + Err(e) => { |
| 315 | + warn!(context, "get_mime_headers: UPDATE failed: {}", e); |
| 316 | + return Err(e.into()); |
276 | 317 | } |
277 | | - Ok((parser, _)) => Ok(Some(parser.html)), |
278 | 318 | } |
279 | | - } else { |
280 | | - warn!(context, "get_html: no mime for {}", self); |
281 | | - Ok(None) |
| 319 | + Ok(()) |
| 320 | + }; |
| 321 | + if let Err(e) = context.sql.call_write(update).await { |
| 322 | + warn!( |
| 323 | + context, |
| 324 | + "get_mime_headers: failed to update mime_headers: {}", e |
| 325 | + ); |
282 | 326 | } |
| 327 | + return from_rawmime(headers).await; |
283 | 328 | } |
284 | 329 | } |
285 | 330 |
|
|
0 commit comments