diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f908642da..605bca1e39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: name: Lint Rust runs-on: ubuntu-latest env: - RUSTUP_TOOLCHAIN: 1.77.0 + RUSTUP_TOOLCHAIN: 1.77.1 steps: - uses: actions/checkout@v4 with: @@ -83,15 +83,15 @@ jobs: matrix: include: - os: ubuntu-latest - rust: 1.77.0 + rust: 1.77.1 - os: windows-latest - rust: 1.77.0 + rust: 1.77.1 - os: macos-latest - rust: 1.77.0 + rust: 1.77.1 - # Minimum Supported Rust Version = 1.70.0 + # Minimum Supported Rust Version = 1.77.0 - os: ubuntu-latest - rust: 1.70.0 + rust: 1.77.0 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 diff --git a/Cargo.toml b/Cargo.toml index d881d1c3b6..5ae60fdc7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "deltachat" version = "1.137.1" edition = "2021" license = "MPL-2.0" -rust-version = "1.70" +rust-version = "1.77" repository = "https://github.com/deltachat/deltachat-core-rust" [profile.dev] diff --git a/scripts/coredeps/install-rust.sh b/scripts/coredeps/install-rust.sh index 39076ca4fa..b6f232ed66 100755 --- a/scripts/coredeps/install-rust.sh +++ b/scripts/coredeps/install-rust.sh @@ -7,7 +7,7 @@ set -euo pipefail # # Avoid using rustup here as it depends on reading /proc/self/exe and # has problems running under QEMU. -RUST_VERSION=1.77.0 +RUST_VERSION=1.77.1 ARCH="$(uname -m)" test -f "/lib/libc.musl-$ARCH.so.1" && LIBC=musl || LIBC=gnu diff --git a/src/html.rs b/src/html.rs index 37798bc572..ee6b469b66 100644 --- a/src/html.rs +++ b/src/html.rs @@ -7,12 +7,8 @@ //! `MsgId.get_html()` will return HTML - //! this allows nice quoting, handling linebreaks properly etc. -use std::future::Future; -use std::pin::Pin; - use anyhow::{Context as _, Result}; use base64::Engine as _; -use futures::future::FutureExt; use lettre_email::mime::Mime; use lettre_email::PartBuilder; use mailparse::ParsedContentType; @@ -116,119 +112,109 @@ impl HtmlMsgParser { /// Usually, there is at most one plain-text and one HTML-text part, /// multiple plain-text parts might be used for mailinglist-footers, /// therefore we use the first one. - fn collect_texts_recursive<'a>( + async fn collect_texts_recursive<'a>( &'a mut self, mail: &'a mailparse::ParsedMail<'a>, - ) -> Pin> + 'a + Send>> { - // Boxed future to deal with recursion - async move { - match get_mime_multipart_type(&mail.ctype) { - MimeMultipartType::Multiple => { - for cur_data in &mail.subparts { - self.collect_texts_recursive(cur_data).await? - } - Ok(()) + ) -> Result<()> { + match get_mime_multipart_type(&mail.ctype) { + MimeMultipartType::Multiple => { + for cur_data in &mail.subparts { + Box::pin(self.collect_texts_recursive(cur_data)).await? } - MimeMultipartType::Message => { - let raw = mail.get_body_raw()?; - if raw.is_empty() { - return Ok(()); - } - let mail = mailparse::parse_mail(&raw).context("failed to parse mail")?; - self.collect_texts_recursive(&mail).await + Ok(()) + } + MimeMultipartType::Message => { + let raw = mail.get_body_raw()?; + if raw.is_empty() { + return Ok(()); } - MimeMultipartType::Single => { - let mimetype = mail.ctype.mimetype.parse::()?; - if mimetype == mime::TEXT_HTML { - if self.html.is_empty() { - if let Ok(decoded_data) = mail.get_body() { - self.html = decoded_data; - } - } - } else if mimetype == mime::TEXT_PLAIN && self.plain.is_none() { + let mail = mailparse::parse_mail(&raw).context("failed to parse mail")?; + Box::pin(self.collect_texts_recursive(&mail)).await + } + MimeMultipartType::Single => { + let mimetype = mail.ctype.mimetype.parse::()?; + if mimetype == mime::TEXT_HTML { + if self.html.is_empty() { if let Ok(decoded_data) = mail.get_body() { - self.plain = Some(PlainText { - text: decoded_data, - flowed: if let Some(format) = mail.ctype.params.get("format") { - format.as_str().to_ascii_lowercase() == "flowed" - } else { - false - }, - delsp: if let Some(delsp) = mail.ctype.params.get("delsp") { - delsp.as_str().to_ascii_lowercase() == "yes" - } else { - false - }, - }); + self.html = decoded_data; } } - Ok(()) + } else if mimetype == mime::TEXT_PLAIN && self.plain.is_none() { + if let Ok(decoded_data) = mail.get_body() { + self.plain = Some(PlainText { + text: decoded_data, + flowed: if let Some(format) = mail.ctype.params.get("format") { + format.as_str().to_ascii_lowercase() == "flowed" + } else { + false + }, + delsp: if let Some(delsp) = mail.ctype.params.get("delsp") { + delsp.as_str().to_ascii_lowercase() == "yes" + } else { + false + }, + }); + } } + Ok(()) } } - .boxed() } /// Replace cid:-protocol by the data:-protocol where appropriate. /// This allows the final html-file to be self-contained. - fn cid_to_data_recursive<'a>( + async fn cid_to_data_recursive<'a>( &'a mut self, context: &'a Context, mail: &'a mailparse::ParsedMail<'a>, - ) -> Pin> + 'a + Send>> { - // Boxed future to deal with recursion - async move { - match get_mime_multipart_type(&mail.ctype) { - MimeMultipartType::Multiple => { - for cur_data in &mail.subparts { - self.cid_to_data_recursive(context, cur_data).await?; - } - Ok(()) + ) -> Result<()> { + match get_mime_multipart_type(&mail.ctype) { + MimeMultipartType::Multiple => { + for cur_data in &mail.subparts { + Box::pin(self.cid_to_data_recursive(context, cur_data)).await?; } - MimeMultipartType::Message => { - let raw = mail.get_body_raw()?; - if raw.is_empty() { - return Ok(()); - } - let mail = mailparse::parse_mail(&raw).context("failed to parse mail")?; - self.cid_to_data_recursive(context, &mail).await + Ok(()) + } + MimeMultipartType::Message => { + let raw = mail.get_body_raw()?; + if raw.is_empty() { + return Ok(()); } - MimeMultipartType::Single => { - let mimetype = mail.ctype.mimetype.parse::()?; - if mimetype.type_() == mime::IMAGE { - if let Some(cid) = mail.headers.get_header_value(HeaderDef::ContentId) { - if let Ok(cid) = parse_message_id(&cid) { - if let Ok(replacement) = mimepart_to_data_url(mail) { - let re_string = format!( - "(]*src[^>]*=[^>]*)(cid:{})([^>]*>)", - regex::escape(&cid) - ); - match regex::Regex::new(&re_string) { - Ok(re) => { - self.html = re - .replace_all( - &self.html, - format!("${{1}}{replacement}${{3}}").as_str(), - ) - .as_ref() - .to_string() - } - Err(e) => warn!( - context, - "Cannot create regex for cid: {} throws {}", - re_string, - e - ), + let mail = mailparse::parse_mail(&raw).context("failed to parse mail")?; + Box::pin(self.cid_to_data_recursive(context, &mail)).await + } + MimeMultipartType::Single => { + let mimetype = mail.ctype.mimetype.parse::()?; + if mimetype.type_() == mime::IMAGE { + if let Some(cid) = mail.headers.get_header_value(HeaderDef::ContentId) { + if let Ok(cid) = parse_message_id(&cid) { + if let Ok(replacement) = mimepart_to_data_url(mail) { + let re_string = format!( + "(]*src[^>]*=[^>]*)(cid:{})([^>]*>)", + regex::escape(&cid) + ); + match regex::Regex::new(&re_string) { + Ok(re) => { + self.html = re + .replace_all( + &self.html, + format!("${{1}}{replacement}${{3}}").as_str(), + ) + .as_ref() + .to_string() } + Err(e) => warn!( + context, + "Cannot create regex for cid: {} throws {}", re_string, e + ), } } } } - Ok(()) } + Ok(()) } } - .boxed() } } diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 177118f17e..6e6947c8da 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -2,9 +2,7 @@ use std::cmp::min; use std::collections::{HashMap, HashSet}; -use std::future::Future; use std::path::Path; -use std::pin::Pin; use std::str; use anyhow::{bail, Context as _, Result}; @@ -818,59 +816,53 @@ impl MimeMessage { self.headers.get(headerdef.get_headername()) } - fn parse_mime_recursive<'a>( + async fn parse_mime_recursive<'a>( &'a mut self, context: &'a Context, mail: &'a mailparse::ParsedMail<'a>, is_related: bool, - ) -> Pin> + 'a + Send>> { - use futures::future::FutureExt; - - // Boxed future to deal with recursion - async move { - enum MimeS { - Multiple, - Single, - Message, - } + ) -> Result { + enum MimeS { + Multiple, + Single, + Message, + } - let mimetype = mail.ctype.mimetype.to_lowercase(); + let mimetype = mail.ctype.mimetype.to_lowercase(); - let m = if mimetype.starts_with("multipart") { - if mail.ctype.params.contains_key("boundary") { - MimeS::Multiple - } else { - MimeS::Single - } - } else if mimetype.starts_with("message") { - if mimetype == "message/rfc822" && !is_attachment_disposition(mail) { - MimeS::Message - } else { - MimeS::Single - } + let m = if mimetype.starts_with("multipart") { + if mail.ctype.params.contains_key("boundary") { + MimeS::Multiple } else { MimeS::Single - }; - - let is_related = is_related || mimetype == "multipart/related"; - match m { - MimeS::Multiple => self.handle_multiple(context, mail, is_related).await, - MimeS::Message => { - let raw = mail.get_body_raw()?; - if raw.is_empty() { - return Ok(false); - } - let mail = mailparse::parse_mail(&raw).context("failed to parse mail")?; + } + } else if mimetype.starts_with("message") { + if mimetype == "message/rfc822" && !is_attachment_disposition(mail) { + MimeS::Message + } else { + MimeS::Single + } + } else { + MimeS::Single + }; - self.parse_mime_recursive(context, &mail, is_related).await - } - MimeS::Single => { - self.add_single_part_if_known(context, mail, is_related) - .await + let is_related = is_related || mimetype == "multipart/related"; + match m { + MimeS::Multiple => Box::pin(self.handle_multiple(context, mail, is_related)).await, + MimeS::Message => { + let raw = mail.get_body_raw()?; + if raw.is_empty() { + return Ok(false); } + let mail = mailparse::parse_mail(&raw).context("failed to parse mail")?; + + Box::pin(self.parse_mime_recursive(context, &mail, is_related)).await + } + MimeS::Single => { + self.add_single_part_if_known(context, mail, is_related) + .await } } - .boxed() } async fn handle_multiple(