diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e85c6b31..57a47d082 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ env: RUST_VERSION: 1.91.0 # Minimum Supported Rust Version - MSRV: 1.85.0 + MSRV: 1.88.0 jobs: lint_rust: diff --git a/Cargo.toml b/Cargo.toml index efcc8e17e..017ab7e21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "deltachat" version = "2.27.0" edition = "2024" license = "MPL-2.0" -rust-version = "1.85" +rust-version = "1.88" repository = "https://github.com/chatmail/core" [profile.dev] diff --git a/src/accounts.rs b/src/accounts.rs index 7ae4deed9..041d9735f 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -678,13 +678,12 @@ impl Config { // Convert them to relative paths. let mut modified = false; for account in &mut config.inner.accounts { - if account.dir.is_absolute() { - if let Some(old_path_parent) = account.dir.parent() { - if let Ok(new_path) = account.dir.strip_prefix(old_path_parent) { - account.dir = new_path.to_path_buf(); - modified = true; - } - } + if account.dir.is_absolute() + && let Some(old_path_parent) = account.dir.parent() + && let Ok(new_path) = account.dir.strip_prefix(old_path_parent) + { + account.dir = new_path.to_path_buf(); + modified = true; } } if modified && writable { diff --git a/src/chat.rs b/src/chat.rs index ba97878ac..67eb4b05a 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -740,16 +740,15 @@ impl ChatId { } } _ => { - if msg.viewtype == Viewtype::File { - if let Some((better_type, _)) = message::guess_msgtype_from_suffix(msg) + if msg.viewtype == Viewtype::File + && let Some((better_type, _)) = message::guess_msgtype_from_suffix(msg) // We do not do an automatic conversion to other viewtypes here so that // users can send images as "files" to preserve the original quality // (usually we compress images). The remaining conversions are done by // `prepare_msg_blob()` later. .filter(|&(vt, _)| vt == Viewtype::Webxdc || vt == Viewtype::Vcard) - { - msg.viewtype = better_type; - } + { + msg.viewtype = better_type; } if msg.viewtype == Viewtype::Vcard { let blob = msg @@ -767,13 +766,13 @@ impl ChatId { msg.chat_id = self; // if possible, replace existing draft and keep id - if !msg.id.is_special() { - if let Some(old_draft) = self.get_draft(context).await? { - if old_draft.id == msg.id - && old_draft.chat_id == self - && old_draft.state == MessageState::OutDraft - { - let affected_rows = context + if !msg.id.is_special() + && let Some(old_draft) = self.get_draft(context).await? + && old_draft.id == msg.id + && old_draft.chat_id == self + && old_draft.state == MessageState::OutDraft + { + let affected_rows = context .sql.execute( "UPDATE msgs SET timestamp=?1,type=?2,txt=?3,txt_normalized=?4,param=?5,mime_in_reply_to=?6 @@ -793,9 +792,7 @@ impl ChatId { msg.id, ), ).await?; - return Ok(affected_rows > 0); - } - } + return Ok(affected_rows > 0); } let row_id = context @@ -993,11 +990,11 @@ impl ChatId { let mut res = Vec::new(); let now = time(); for (chat_id, metric) in chats_with_metrics { - if let Some(chat_timestamp) = chat_id.get_timestamp(context).await? { - if now > chat_timestamp + 42 * 24 * 3600 { - // Chat was inactive for 42 days, skip. - continue; - } + if let Some(chat_timestamp) = chat_id.get_timestamp(context).await? + && now > chat_timestamp + 42 * 24 * 3600 + { + // Chat was inactive for 42 days, skip. + continue; } if metric < 0.1 { @@ -1252,10 +1249,10 @@ impl ChatId { None }; - if let Some(last_msg_time) = last_msg_time { - if last_msg_time > sort_timestamp { - sort_timestamp = last_msg_time; - } + if let Some(last_msg_time) = last_msg_time + && last_msg_time > sort_timestamp + { + sort_timestamp = last_msg_time; } Ok(sort_timestamp) @@ -1376,10 +1373,10 @@ impl Chat { let mut chat_name = "Err [Name not found]".to_owned(); match get_chat_contacts(context, chat.id).await { Ok(contacts) => { - if let Some(contact_id) = contacts.first() { - if let Ok(contact) = Contact::get_by_id(context, *contact_id).await { - contact.get_display_name().clone_into(&mut chat_name); - } + if let Some(contact_id) = contacts.first() + && let Ok(contact) = Contact::get_by_id(context, *contact_id).await + { + contact.get_display_name().clone_into(&mut chat_name); } } Err(err) => { @@ -1576,10 +1573,10 @@ impl Chat { if self.typ == Chattype::Single { let contacts = get_chat_contacts(context, self.id).await?; - if let Some(contact_id) = contacts.first() { - if let Ok(contact) = Contact::get_by_id(context, *contact_id).await { - color = contact.get_color(); - } + if let Some(contact_id) = contacts.first() + && let Ok(contact) = Contact::get_by_id(context, *contact_id).await + { + color = contact.get_color(); } } else if !self.grpid.is_empty() { color = str_to_color(&self.grpid); @@ -1841,8 +1838,8 @@ impl Chat { } // add independent location to database - if msg.param.exists(Param::SetLatitude) { - if let Ok(row_id) = context + if msg.param.exists(Param::SetLatitude) + && let Ok(row_id) = context .sql .insert( "INSERT INTO locations \ @@ -1857,9 +1854,8 @@ impl Chat { ), ) .await - { - location_id = row_id; - } + { + location_id = row_id; } let ephemeral_timer = if msg.param.get_cmd() == SystemMessage::EphemeralTimerChanged { @@ -2497,18 +2493,18 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> { msg.param.set(Param::File, blob.as_name()); } - if !msg.param.exists(Param::MimeType) { - if let Some((viewtype, mime)) = message::guess_msgtype_from_suffix(msg) { - // If we unexpectedly didn't recognize the file as image, don't send it as such, - // either the format is unsupported or the image is corrupted. - let mime = match viewtype != Viewtype::Image - || matches!(msg.viewtype, Viewtype::Image | Viewtype::Sticker) - { - true => mime, - false => "application/octet-stream", - }; - msg.param.set(Param::MimeType, mime); - } + if !msg.param.exists(Param::MimeType) + && let Some((viewtype, mime)) = message::guess_msgtype_from_suffix(msg) + { + // If we unexpectedly didn't recognize the file as image, don't send it as such, + // either the format is unsupported or the image is corrupted. + let mime = match viewtype != Viewtype::Image + || matches!(msg.viewtype, Viewtype::Image | Viewtype::Sticker) + { + true => mime, + false => "application/octet-stream", + }; + msg.param.set(Param::MimeType, mime); } msg.try_calc_and_set_dimensions(context).await?; @@ -2692,15 +2688,15 @@ async fn prepare_send_msg( // This is meant as a last line of defence, the UI should check that before as well. // (We allow Chattype::Single in general for "Reply Privately"; // checking for exact contact_id will produce false positives when ppl just left the group) - if chat.typ != Chattype::Single && !context.get_config_bool(Config::Bot).await? { - if let Some(quoted_message) = msg.quoted_message(context).await? { - if quoted_message.chat_id != chat_id { - bail!( - "Quote of message from {} cannot be sent to {chat_id}", - quoted_message.chat_id - ); - } - } + if chat.typ != Chattype::Single + && !context.get_config_bool(Config::Bot).await? + && let Some(quoted_message) = msg.quoted_message(context).await? + && quoted_message.chat_id != chat_id + { + bail!( + "Quote of message from {} cannot be sent to {chat_id}", + quoted_message.chat_id + ); } // check current MessageState for drafts (to keep msg_id) ... @@ -2830,16 +2826,15 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) - let now = smeared_time(context); - if rendered_msg.last_added_location_id.is_some() { - if let Err(err) = location::set_kml_sent_timestamp(context, msg.chat_id, now).await { - error!(context, "Failed to set kml sent_timestamp: {err:#}."); - } + if rendered_msg.last_added_location_id.is_some() + && let Err(err) = location::set_kml_sent_timestamp(context, msg.chat_id, now).await + { + error!(context, "Failed to set kml sent_timestamp: {err:#}."); } - if attach_selfavatar { - if let Err(err) = msg.chat_id.set_selfavatar_timestamp(context, now).await { - error!(context, "Failed to set selfavatar timestamp: {err:#}."); - } + if attach_selfavatar && let Err(err) = msg.chat_id.set_selfavatar_timestamp(context, now).await + { + error!(context, "Failed to set selfavatar timestamp: {err:#}."); } if rendered_msg.is_encrypted { @@ -4483,11 +4478,11 @@ pub async fn add_device_msg_with_importance( let mut chat_id = ChatId::new(0); let mut msg_id = MsgId::new_unset(); - if let Some(label) = label { - if was_device_msg_ever_added(context, label).await? { - info!(context, "Device-message {label} already added."); - return Ok(msg_id); - } + if let Some(label) = label + && was_device_msg_ever_added(context, label).await? + { + info!(context, "Device-message {label} already added."); + return Ok(msg_id); } if let Some(msg) = msg { @@ -4499,10 +4494,10 @@ pub async fn add_device_msg_with_importance( // makes sure, the added message is the last one, // even if the date is wrong (useful esp. when warning about bad dates) msg.timestamp_sort = timestamp_sent; - if let Some(last_msg_time) = chat_id.get_timestamp(context).await? { - if msg.timestamp_sort <= last_msg_time { - msg.timestamp_sort = last_msg_time + 1; - } + if let Some(last_msg_time) = chat_id.get_timestamp(context).await? + && msg.timestamp_sort <= last_msg_time + { + msg.timestamp_sort = last_msg_time + 1; } prepare_msg_blob(context, msg).await?; let state = MessageState::InFresh; diff --git a/src/configure.rs b/src/configure.rs index a0a06292d..1d0bc5c54 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -258,19 +258,18 @@ async fn on_configure_completed( } } - if let Some(new_addr) = context.get_config(Config::ConfiguredAddr).await? { - if let Some(old_addr) = old_addr { - if !addr_cmp(&new_addr, &old_addr) { - let mut msg = Message::new_text( - stock_str::aeap_explanation_and_link(context, &old_addr, &new_addr).await, - ); - chat::add_device_msg(context, None, Some(&mut msg)) - .await - .context("Cannot add AEAP explanation") - .log_err(context) - .ok(); - } - } + if let Some(new_addr) = context.get_config(Config::ConfiguredAddr).await? + && let Some(old_addr) = old_addr + && !addr_cmp(&new_addr, &old_addr) + { + let mut msg = Message::new_text( + stock_str::aeap_explanation_and_link(context, &old_addr, &new_addr).await, + ); + chat::add_device_msg(context, None, Some(&mut msg)) + .await + .context("Cannot add AEAP explanation") + .log_err(context) + .ok(); } Ok(()) diff --git a/src/configure/auto_mozilla.rs b/src/configure/auto_mozilla.rs index 01cd06fd2..f08aba93c 100644 --- a/src/configure/auto_mozilla.rs +++ b/src/configure/auto_mozilla.rs @@ -154,10 +154,10 @@ fn parse_xml_reader( if let Some(incoming_server) = parse_server(reader, event)? { incoming_servers.push(incoming_server); } - } else if tag == "outgoingserver" { - if let Some(outgoing_server) = parse_server(reader, event)? { - outgoing_servers.push(outgoing_server); - } + } else if tag == "outgoingserver" + && let Some(outgoing_server) = parse_server(reader, event)? + { + outgoing_servers.push(outgoing_server); } } Event::Eof => break, diff --git a/src/contact.rs b/src/contact.rs index 93be417a6..ef5095d5e 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -138,27 +138,27 @@ impl ContactId { }) .await?; - if sync.into() { - if let Some((addr, fingerprint)) = row { - if fingerprint.is_empty() { - chat::sync( - context, - chat::SyncId::ContactAddr(addr), - chat::SyncAction::Rename(name.to_string()), - ) - .await - .log_err(context) - .ok(); - } else { - chat::sync( - context, - chat::SyncId::ContactFingerprint(fingerprint), - chat::SyncAction::Rename(name.to_string()), - ) - .await - .log_err(context) - .ok(); - } + if sync.into() + && let Some((addr, fingerprint)) = row + { + if fingerprint.is_empty() { + chat::sync( + context, + chat::SyncId::ContactAddr(addr), + chat::SyncAction::Rename(name.to_string()), + ) + .await + .log_err(context) + .ok(); + } else { + chat::sync( + context, + chat::SyncId::ContactFingerprint(fingerprint), + chat::SyncAction::Rename(name.to_string()), + ) + .await + .log_err(context) + .ok(); } } Ok(()) @@ -393,13 +393,13 @@ async fn import_vcard_contact(context: &Context, contact: &VcardContact) -> Resu ); } } - if let Some(biography) = &contact.biography { - if let Err(e) = set_status(context, id, biography.to_owned(), false, false).await { - warn!( - context, - "import_vcard_contact: Could not set biography for {}: {e:#}.", contact.addr - ); - } + if let Some(biography) = &contact.biography + && let Err(e) = set_status(context, id, biography.to_owned(), false, false).await + { + warn!( + context, + "import_vcard_contact: Could not set biography for {}: {e:#}.", contact.addr + ); } Ok(id) } @@ -1564,10 +1564,10 @@ impl Contact { if show_fallback_icon && !self.id.is_special() && !self.is_key_contact() { return Ok(Some(chat::get_unencrypted_icon(context).await?)); } - if let Some(image_rel) = self.param.get(Param::ProfileImage) { - if !image_rel.is_empty() { - return Ok(Some(get_abs_path(context, Path::new(image_rel)))); - } + if let Some(image_rel) = self.param.get(Param::ProfileImage) + && !image_rel.is_empty() + { + return Ok(Some(get_abs_path(context, Path::new(image_rel)))); } Ok(None) } @@ -1800,10 +1800,11 @@ WHERE type=? AND id IN ( // also unblock mailinglist // if the contact is a mailinglist address explicitly created to allow unblocking - if !new_blocking && contact.origin == Origin::MailinglistAddress { - if let Some((chat_id, ..)) = chat::get_chat_id_by_grpid(context, &contact.addr).await? { - chat_id.unblock_ex(context, Nosync).await?; - } + if !new_blocking + && contact.origin == Origin::MailinglistAddress + && let Some((chat_id, ..)) = chat::get_chat_id_by_grpid(context, &contact.addr).await? + { + chat_id.unblock_ex(context, Nosync).await?; } if sync.into() { diff --git a/src/context.rs b/src/context.rs index 610b2887c..0ca01a044 100644 --- a/src/context.rs +++ b/src/context.rs @@ -608,10 +608,9 @@ impl Context { if self .quota_needs_update(DC_BACKGROUND_FETCH_QUOTA_CHECK_RATELIMIT) .await + && let Err(err) = self.update_recent_quota(&mut session).await { - if let Err(err) = self.update_recent_quota(&mut session).await { - warn!(self, "Failed to update quota: {err:#}."); - } + warn!(self, "Failed to update quota: {err:#}."); } } diff --git a/src/debug_logging.rs b/src/debug_logging.rs index 9b437e8cc..1bd25b034 100644 --- a/src/debug_logging.rs +++ b/src/debug_logging.rs @@ -115,15 +115,13 @@ pub async fn maybe_set_logging_xdc_inner( filename: Option<&str>, msg_id: MsgId, ) -> anyhow::Result<()> { - if viewtype == Viewtype::Webxdc { - if let Some(filename) = filename { - if filename.starts_with("debug_logging") - && filename.ends_with(".xdc") - && chat_id.is_self_talk(context).await? - { - set_debug_logging_xdc(context, Some(msg_id)).await?; - } - } + if viewtype == Viewtype::Webxdc + && let Some(filename) = filename + && filename.starts_with("debug_logging") + && filename.ends_with(".xdc") + && chat_id.is_self_talk(context).await? + { + set_debug_logging_xdc(context, Some(msg_id)).await?; } Ok(()) } diff --git a/src/html.rs b/src/html.rs index cba1466d9..5ecbba1a3 100644 --- a/src/html.rs +++ b/src/html.rs @@ -169,27 +169,28 @@ impl HtmlMsgParser { 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() { - 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().eq_ignore_ascii_case("flowed") - } else { - false - }, - delsp: if let Some(delsp) = mail.ctype.params.get("delsp") { - delsp.as_str().eq_ignore_ascii_case("yes") - } else { - false - }, - }); + if self.html.is_empty() + && let Ok(decoded_data) = mail.get_body() + { + self.html = decoded_data; } + } else if mimetype == mime::TEXT_PLAIN + && self.plain.is_none() + && 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().eq_ignore_ascii_case("flowed") + } else { + false + }, + delsp: if let Some(delsp) = mail.ctype.params.get("delsp") { + delsp.as_str().eq_ignore_ascii_case("yes") + } else { + false + }, + }); } Ok(()) } @@ -213,31 +214,29 @@ impl HtmlMsgParser { MimeMultipartType::Message => 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 - ), - } - } + if mimetype.type_() == mime::IMAGE + && let Some(cid) = mail.headers.get_header_value(HeaderDef::ContentId) + && let Ok(cid) = parse_message_id(&cid) + && 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(()) diff --git a/src/imap.rs b/src/imap.rs index 1aeca6d20..5614f6593 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -1259,15 +1259,14 @@ impl Session { continue; }; let is_seen = fetch.flags().any(|flag| flag == Flag::Seen); - if is_seen { - if let Some(chat_id) = mark_seen_by_uid(context, folder, uid_validity, uid) + if is_seen + && let Some(chat_id) = mark_seen_by_uid(context, folder, uid_validity, uid) .await .with_context(|| { format!("failed to update seen status for msg {folder}/{uid}") })? - { - updated_chat_ids.insert(chat_id); - } + { + updated_chat_ids.insert(chat_id); } if let Some(modseq) = fetch.modseq { @@ -1321,10 +1320,10 @@ impl Session { while let Some(msg) = list.try_next().await? { match get_fetch_headers(&msg) { Ok(headers) => { - if let Some(from) = mimeparser::get_from(&headers) { - if context.is_self_addr(&from.addr).await? { - result.extend(mimeparser::get_recipients(&headers)); - } + if let Some(from) = mimeparser::get_from(&headers) + && context.is_self_addr(&from.addr).await? + { + result.extend(mimeparser::get_recipients(&headers)); } } Err(err) => { @@ -1557,17 +1556,17 @@ impl Session { .await?; let mut got_turn_server = false; for m in metadata { - if m.entry == "/shared/vendor/deltachat/turn" { - if let Some(value) = m.value { - match create_ice_servers_from_metadata(context, &value).await { - Ok((parsed_timestamp, parsed_ice_servers)) => { - old_metadata.ice_servers_expiration_timestamp = parsed_timestamp; - old_metadata.ice_servers = parsed_ice_servers; - got_turn_server = false; - } - Err(err) => { - warn!(context, "Failed to parse TURN server metadata: {err:#}."); - } + if m.entry == "/shared/vendor/deltachat/turn" + && let Some(value) = m.value + { + match create_ice_servers_from_metadata(context, &value).await { + Ok((parsed_timestamp, parsed_ice_servers)) => { + old_metadata.ice_servers_expiration_timestamp = parsed_timestamp; + old_metadata.ice_servers = parsed_ice_servers; + got_turn_server = false; + } + Err(err) => { + warn!(context, "Failed to parse TURN server metadata: {err:#}."); } } } @@ -1852,11 +1851,13 @@ impl Imap { info!(context, "Scanning folder: {:?}", folder); // Update the delimiter iff there is a different one, but only once. - if let Some(d) = folder.delimiter() { - if delimiter_is_default && !d.is_empty() && delimiter != d { - delimiter = d.to_string(); - delimiter_is_default = false; - } + if let Some(d) = folder.delimiter() + && delimiter_is_default + && !d.is_empty() + && delimiter != d + { + delimiter = d.to_string(); + delimiter_is_default = false; } let folder_meaning = get_folder_meaning_by_attrs(folder.attributes()); @@ -2097,12 +2098,10 @@ async fn needs_move_to_mvbox( .get_header_value(HeaderDef::AutoSubmitted) .filter(|val| val.eq_ignore_ascii_case("auto-generated")) .is_some() + && let Some(from) = mimeparser::get_from(headers) + && context.is_self_addr(&from.addr).await? { - if let Some(from) = mimeparser::get_from(headers) { - if context.is_self_addr(&from.addr).await? { - return Ok(true); - } - } + return Ok(true); } if !context.get_config_bool(Config::MvboxMove).await? { return Ok(false); @@ -2272,12 +2271,13 @@ pub(crate) async fn prefetch_should_download( // We do not know the Message-ID or the Message-ID is missing (in this case, we create one in // the further process). - if let Some(chat) = prefetch_get_chat(context, headers).await? { - if chat.typ == Chattype::Group && !chat.id.is_special() { - // This might be a group command, like removing a group member. - // We really need to fetch this to avoid inconsistent group state. - return Ok(true); - } + if let Some(chat) = prefetch_get_chat(context, headers).await? + && chat.typ == Chattype::Group + && !chat.id.is_special() + { + // This might be a group command, like removing a group member. + // We really need to fetch this to avoid inconsistent group state. + return Ok(true); } let maybe_ndn = if let Some(from) = headers.get_header_value(HeaderDef::From_) { @@ -2524,11 +2524,11 @@ fn build_sequence_sets(uids: &[u32]) -> Result, String)>> { let mut ranges: Vec = vec![]; for ¤t in uids { - if let Some(last) = ranges.last_mut() { - if last.end + 1 == current { - last.end = current; - continue; - } + if let Some(last) = ranges.last_mut() + && last.end + 1 == current + { + last.end = current; + continue; } ranges.push(UidRange { diff --git a/src/imap/select_folder.rs b/src/imap/select_folder.rs index 6927bd736..2a42b13ff 100644 --- a/src/imap/select_folder.rs +++ b/src/imap/select_folder.rs @@ -34,16 +34,16 @@ impl ImapSession { /// because no EXPUNGE responses are sent, see /// pub(super) async fn maybe_close_folder(&mut self, context: &Context) -> anyhow::Result<()> { - if let Some(folder) = &self.selected_folder { - if self.selected_folder_needs_expunge { - info!(context, "Expunge messages in {folder:?}."); + if let Some(folder) = &self.selected_folder + && self.selected_folder_needs_expunge + { + info!(context, "Expunge messages in {folder:?}."); - self.close().await.context("IMAP close/expunge failed")?; - info!(context, "Close/expunge succeeded."); - self.selected_folder = None; - self.selected_folder_needs_expunge = false; - self.new_mail = false; - } + self.close().await.context("IMAP close/expunge failed")?; + info!(context, "Close/expunge succeeded."); + self.selected_folder = None; + self.selected_folder_needs_expunge = false; + self.new_mail = false; } Ok(()) } @@ -54,10 +54,10 @@ impl ImapSession { async fn select_folder(&mut self, context: &Context, folder: &str) -> Result { // if there is a new folder and the new folder is equal to the selected one, there's nothing to do. // if there is _no_ new folder, we continue as we might want to expunge below. - if let Some(selected_folder) = &self.selected_folder { - if folder == selected_folder { - return Ok(NewlySelected::No); - } + if let Some(selected_folder) = &self.selected_folder + && folder == selected_folder + { + return Ok(NewlySelected::No); } // deselect existing folder, if needed (it's also done implicitly by SELECT, however, without EXPUNGE then) diff --git a/src/message.rs b/src/message.rs index 46d5ff675..2f7252a37 100644 --- a/src/message.rs +++ b/src/message.rs @@ -638,33 +638,33 @@ impl Message { pub(crate) async fn try_calc_and_set_dimensions(&mut self, context: &Context) -> Result<()> { if self.viewtype.has_file() { let file_param = self.param.get_file_path(context)?; - if let Some(path_and_filename) = file_param { - if matches!( + if let Some(path_and_filename) = file_param + && matches!( self.viewtype, Viewtype::Image | Viewtype::Gif | Viewtype::Sticker - ) && !self.param.exists(Param::Width) - { - let buf = read_file(context, &path_and_filename).await?; + ) + && !self.param.exists(Param::Width) + { + let buf = read_file(context, &path_and_filename).await?; - match get_filemeta(&buf) { - Ok((width, height)) => { - self.param.set_int(Param::Width, width as i32); - self.param.set_int(Param::Height, height as i32); - } - Err(err) => { - self.param.set_int(Param::Width, 0); - self.param.set_int(Param::Height, 0); - warn!( - context, - "Failed to get width and height for {}: {err:#}.", - path_and_filename.display() - ); - } + match get_filemeta(&buf) { + Ok((width, height)) => { + self.param.set_int(Param::Width, width as i32); + self.param.set_int(Param::Height, height as i32); } + Err(err) => { + self.param.set_int(Param::Width, 0); + self.param.set_int(Param::Height, 0); + warn!( + context, + "Failed to get width and height for {}: {err:#}.", + path_and_filename.display() + ); + } + } - if !self.id.is_unset() { - self.update_param(context).await?; - } + if !self.id.is_unset() { + self.update_param(context).await?; } } } @@ -992,14 +992,12 @@ impl Message { return None; } - if let Some(filename) = self.get_file(context) { - if let Ok(ref buf) = read_file(context, &filename).await { - if let Ok((typ, headers, _)) = split_armored_data(buf) { - if typ == pgp::armor::BlockType::Message { - return headers.get(crate::pgp::HEADER_SETUPCODE).cloned(); - } - } - } + if let Some(filename) = self.get_file(context) + && let Ok(ref buf) = read_file(context, &filename).await + && let Ok((typ, headers, _)) = split_armored_data(buf) + && typ == pgp::armor::BlockType::Message + { + return headers.get(crate::pgp::HEADER_SETUPCODE).cloned(); } None @@ -1224,26 +1222,25 @@ impl Message { /// /// `References` header is not taken into account. pub async fn parent(&self, context: &Context) -> Result> { - if let Some(in_reply_to) = &self.in_reply_to { - if let Some(msg_id) = rfc724_mid_exists(context, in_reply_to).await? { - let msg = Message::load_from_db_optional(context, msg_id).await?; - return Ok(msg); - } + if let Some(in_reply_to) = &self.in_reply_to + && let Some(msg_id) = rfc724_mid_exists(context, in_reply_to).await? + { + let msg = Message::load_from_db_optional(context, msg_id).await?; + return Ok(msg); } Ok(None) } /// Returns original message ID for message from "Saved Messages". pub async fn get_original_msg_id(&self, context: &Context) -> Result> { - if !self.original_msg_id.is_special() { - if let Some(msg) = Message::load_from_db_optional(context, self.original_msg_id).await? - { - return if msg.chat_id.is_trash() { - Ok(None) - } else { - Ok(Some(msg.id)) - }; - } + if !self.original_msg_id.is_special() + && let Some(msg) = Message::load_from_db_optional(context, self.original_msg_id).await? + { + return if msg.chat_id.is_trash() { + Ok(None) + } else { + Ok(Some(msg.id)) + }; } Ok(None) } @@ -1613,10 +1610,10 @@ pub(crate) async fn delete_msg_locally(context: &Context, msg: &Message) -> Resu .expect("RwLock is poisoned") .as_ref() .map(|dl| dl.msg_id); - if let Some(id) = logging_xdc_id { - if id == msg.id { - set_debug_logging_xdc(context, None).await?; - } + if let Some(id) = logging_xdc_id + && id == msg.id + { + set_debug_logging_xdc(context, None).await?; } Ok(()) diff --git a/src/message/message_tests.rs b/src/message/message_tests.rs index 267c7acbb..66f2c6f09 100644 --- a/src/message/message_tests.rs +++ b/src/message/message_tests.rs @@ -39,17 +39,16 @@ async fn test_get_width_height() { let mut has_image = false; let chatitems = chat::get_chat_msgs(&t, device_chat_id).await.unwrap(); for chatitem in chatitems { - if let ChatItem::Message { msg_id } = chatitem { - if let Ok(msg) = Message::load_from_db(&t, msg_id).await { - if msg.get_viewtype() == Viewtype::Image { - has_image = true; - // just check that width/height are inside some reasonable ranges - assert!(msg.get_width() > 100); - assert!(msg.get_height() > 100); - assert!(msg.get_width() < 4000); - assert!(msg.get_height() < 4000); - } - } + if let ChatItem::Message { msg_id } = chatitem + && let Ok(msg) = Message::load_from_db(&t, msg_id).await + && msg.get_viewtype() == Viewtype::Image + { + has_image = true; + // just check that width/height are inside some reasonable ranges + assert!(msg.get_width() > 100); + assert!(msg.get_height() > 100); + assert!(msg.get_width() < 4000); + assert!(msg.get_height() < 4000); } } assert!(has_image); diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 00e02fb37..b995c350a 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -292,11 +292,10 @@ impl MimeFactory { // In a broadcast channel, only send member-added/removed messages // to the affected member: - if let Some(fp) = must_have_only_one_recipient(&msg, &chat) { - if fp? != fingerprint { + if let Some(fp) = must_have_only_one_recipient(&msg, &chat) + && fp? != fingerprint { continue; } - } let public_key_opt = if let Some(public_key_bytes) = &public_key_bytes_opt { Some(SignedPublicKey::from_slice(public_key_bytes)?) @@ -347,8 +346,8 @@ impl MimeFactory { // Row is a tombstone, // member is not actually part of the group. if !recipients_contain_addr(&past_members, &addr) { - if let Some(email_to_remove) = email_to_remove { - if email_to_remove == addr { + if let Some(email_to_remove) = email_to_remove + && email_to_remove == addr { // This is a "member removed" message, // we need to notify removed member // that it was removed. @@ -365,7 +364,6 @@ impl MimeFactory { } } } - } if !undisclosed_recipients { past_members.push((name, addr.clone())); past_member_timestamps.push(remove_timestamp); @@ -395,15 +393,14 @@ impl MimeFactory { "member_fingerprints.len() ({}) < to.len() ({})", member_fingerprints.len(), to.len()); - if to.len() > 1 { - if let Some(position) = to.iter().position(|(_, x)| x == &from_addr) { + if to.len() > 1 + && let Some(position) = to.iter().position(|(_, x)| x == &from_addr) { to.remove(position); member_timestamps.remove(position); if is_encrypted { member_fingerprints.remove(position); } } - } member_timestamps.extend(past_member_timestamps); if is_encrypted { @@ -733,36 +730,35 @@ impl MimeFactory { )); } - if let Loaded::Message { chat, .. } = &self.loaded { - if chat.typ == Chattype::Group { - if !self.member_timestamps.is_empty() && !chat.member_list_is_stale(context).await? - { - headers.push(( - "Chat-Group-Member-Timestamps", - mail_builder::headers::raw::Raw::new( - self.member_timestamps - .iter() - .map(|ts| ts.to_string()) - .collect::>() - .join(" "), - ) - .into(), - )); - } + if let Loaded::Message { chat, .. } = &self.loaded + && chat.typ == Chattype::Group + { + if !self.member_timestamps.is_empty() && !chat.member_list_is_stale(context).await? { + headers.push(( + "Chat-Group-Member-Timestamps", + mail_builder::headers::raw::Raw::new( + self.member_timestamps + .iter() + .map(|ts| ts.to_string()) + .collect::>() + .join(" "), + ) + .into(), + )); + } - if !self.member_fingerprints.is_empty() { - headers.push(( - "Chat-Group-Member-Fpr", - mail_builder::headers::raw::Raw::new( - self.member_fingerprints - .iter() - .map(|fp| fp.to_string()) - .collect::>() - .join(" "), - ) - .into(), - )); - } + if !self.member_fingerprints.is_empty() { + headers.push(( + "Chat-Group-Member-Fpr", + mail_builder::headers::raw::Raw::new( + self.member_fingerprints + .iter() + .map(|fp| fp.to_string()) + .collect::>() + .join(" "), + ) + .into(), + )); } } @@ -814,37 +810,34 @@ impl MimeFactory { "Auto-Submitted", mail_builder::headers::raw::Raw::new("auto-generated".to_string()).into(), )); - } else if let Loaded::Message { msg, .. } = &self.loaded { - if msg.param.get_cmd() == SystemMessage::SecurejoinMessage { - let step = msg.param.get(Param::Arg).unwrap_or_default(); - if step != "vg-request" && step != "vc-request" { - headers.push(( - "Auto-Submitted", - mail_builder::headers::raw::Raw::new("auto-replied".to_string()).into(), - )); - } + } else if let Loaded::Message { msg, .. } = &self.loaded + && msg.param.get_cmd() == SystemMessage::SecurejoinMessage + { + let step = msg.param.get(Param::Arg).unwrap_or_default(); + if step != "vg-request" && step != "vc-request" { + headers.push(( + "Auto-Submitted", + mail_builder::headers::raw::Raw::new("auto-replied".to_string()).into(), + )); } } - if let Loaded::Message { msg, chat } = &self.loaded { - if chat.typ == Chattype::OutBroadcast || chat.typ == Chattype::InBroadcast { - headers.push(( - "Chat-List-ID", - mail_builder::headers::text::Text::new(format!( - "{} <{}>", - chat.name, chat.grpid - )) + if let Loaded::Message { msg, chat } = &self.loaded + && (chat.typ == Chattype::OutBroadcast || chat.typ == Chattype::InBroadcast) + { + headers.push(( + "Chat-List-ID", + mail_builder::headers::text::Text::new(format!("{} <{}>", chat.name, chat.grpid)) .into(), - )); + )); - if msg.param.get_cmd() == SystemMessage::MemberAddedToGroup { - if let Some(secret) = msg.param.get(PARAM_BROADCAST_SECRET) { - headers.push(( - "Chat-Broadcast-Secret", - mail_builder::headers::text::Text::new(secret.to_string()).into(), - )); - } - } + if msg.param.get_cmd() == SystemMessage::MemberAddedToGroup + && let Some(secret) = msg.param.get(PARAM_BROADCAST_SECRET) + { + headers.push(( + "Chat-Broadcast-Secret", + mail_builder::headers::text::Text::new(secret.to_string()).into(), + )); } } @@ -1204,16 +1197,16 @@ impl MimeFactory { // Set the appropriate Content-Type for the inner message. for (h, v) in &mut message.headers { - if h == "Content-Type" { - if let mail_builder::headers::HeaderType::ContentType(ct) = v { - let mut ct_new = ct.clone(); - ct_new = ct_new.attribute("protected-headers", "v1"); - if use_std_header_protection { - ct_new = ct_new.attribute("hp", "cipher"); - } - *ct = ct_new; - break; + if h == "Content-Type" + && let mail_builder::headers::HeaderType::ContentType(ct) = v + { + let mut ct_new = ct.clone(); + ct_new = ct_new.attribute("protected-headers", "v1"); + if use_std_header_protection { + ct_new = ct_new.attribute("hp", "cipher"); } + *ct = ct_new; + break; } } @@ -1257,10 +1250,10 @@ impl MimeFactory { // once new core versions are sufficiently deployed. let anonymous_recipients = false; - if context.get_config_bool(Config::TestHooks).await? { - if let Some(hook) = &*context.pre_encrypt_mime_hook.lock() { - message = hook(context, message); - } + if context.get_config_bool(Config::TestHooks).await? + && let Some(hook) = &*context.pre_encrypt_mime_hook.lock() + { + message = hook(context, message); } let encrypted = if let Some(shared_secret) = shared_secret { @@ -1348,16 +1341,16 @@ impl MimeFactory { message } else { for (h, v) in &mut message.headers { - if h == "Content-Type" { - if let mail_builder::headers::HeaderType::ContentType(ct) = v { - let mut ct_new = ct.clone(); - ct_new = ct_new.attribute("protected-headers", "v1"); - if use_std_header_protection { - ct_new = ct_new.attribute("hp", "clear"); - } - *ct = ct_new; - break; + if h == "Content-Type" + && let mail_builder::headers::HeaderType::ContentType(ct) = v + { + let mut ct_new = ct.clone(); + ct_new = ct_new.attribute("protected-headers", "v1"); + if use_std_header_protection { + ct_new = ct_new.attribute("hp", "clear"); } + *ct = ct_new; + break; } } @@ -1882,10 +1875,10 @@ impl MimeFactory { parts.push(msg_kml_part); } - if location::is_sending_locations_to_chat(context, Some(msg.chat_id)).await? { - if let Some(part) = self.get_location_kml_part(context).await? { - parts.push(part); - } + if location::is_sending_locations_to_chat(context, Some(msg.chat_id)).await? + && let Some(part) = self.get_location_kml_part(context).await? + { + parts.push(part); } // we do not piggyback sync-files to other self-sent-messages diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 4b50ca2e1..97716776f 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -310,13 +310,14 @@ impl MimeMessage { // Currently we do not sign unencrypted messages by default. (&mail, mimetype) }; - if mimetype.type_() == mime::MULTIPART && mimetype.subtype().as_str() == "mixed" { - if let Some(part) = part.subparts.first() { - for field in &part.headers { - let key = field.get_key().to_lowercase(); - if !headers.contains_key(&key) && is_hidden(&key) || key == "message-id" { - headers.insert(key.to_string(), field.get_value()); - } + if mimetype.type_() == mime::MULTIPART + && mimetype.subtype().as_str() == "mixed" + && let Some(part) = part.subparts.first() + { + for field in &part.headers { + let key = field.get_key().to_lowercase(); + if !headers.contains_key(&key) && is_hidden(&key) || key == "message-id" { + headers.insert(key.to_string(), field.get_value()); } } } @@ -805,22 +806,20 @@ impl MimeMessage { { part.typ = Viewtype::Voice; } - if part.typ == Viewtype::Image || part.typ == Viewtype::Gif { - if let Some(value) = self.get_header(HeaderDef::ChatContent) { - if value == "sticker" { - part.typ = Viewtype::Sticker; - } - } - } - if part.typ == Viewtype::Audio - || part.typ == Viewtype::Voice - || part.typ == Viewtype::Video + if (part.typ == Viewtype::Image || part.typ == Viewtype::Gif) + && let Some(value) = self.get_header(HeaderDef::ChatContent) + && value == "sticker" { - if let Some(field_0) = self.get_header(HeaderDef::ChatDuration) { - let duration_ms = field_0.parse().unwrap_or_default(); - if duration_ms > 0 && duration_ms < 24 * 60 * 60 * 1000 { - part.param.set_int(Param::Duration, duration_ms); - } + part.typ = Viewtype::Sticker; + } + if (part.typ == Viewtype::Audio + || part.typ == Viewtype::Voice + || part.typ == Viewtype::Video) + && let Some(field_0) = self.get_header(HeaderDef::ChatDuration) + { + let duration_ms = field_0.parse().unwrap_or_default(); + if duration_ms > 0 && duration_ms < 24 * 60 * 60 * 1000 { + part.param.set_int(Param::Duration, duration_ms); } } @@ -836,38 +835,38 @@ impl MimeMessage { self.squash_attachment_parts(); } - if !context.get_config_bool(Config::Bot).await? { - if let Some(ref subject) = self.get_subject() { - let mut prepend_subject = true; - if !self.decrypting_failed { - let colon = subject.find(':'); - if colon == Some(2) - || colon == Some(3) - || self.has_chat_version() - || subject.contains("Chat:") - { - prepend_subject = false - } + if !context.get_config_bool(Config::Bot).await? + && let Some(ref subject) = self.get_subject() + { + let mut prepend_subject = true; + if !self.decrypting_failed { + let colon = subject.find(':'); + if colon == Some(2) + || colon == Some(3) + || self.has_chat_version() + || subject.contains("Chat:") + { + prepend_subject = false } + } - // For mailing lists, always add the subject because sometimes there are different topics - // and otherwise it might be hard to keep track: - if self.is_mailinglist_message() && !self.has_chat_version() { - prepend_subject = true; - } + // For mailing lists, always add the subject because sometimes there are different topics + // and otherwise it might be hard to keep track: + if self.is_mailinglist_message() && !self.has_chat_version() { + prepend_subject = true; + } - if prepend_subject && !subject.is_empty() { - let part_with_text = self - .parts - .iter_mut() - .find(|part| !part.msg.is_empty() && !part.is_reaction); - if let Some(part) = part_with_text { - // Message bubbles are small, so we use en dash to save space. In some - // languages there may be em dashes in the message text added by the author, - // they may look stronger than Subject separation, this is a known thing. - // Anyway, classic email support isn't a priority as of 2025. - part.msg = format!("{} – {}", subject, part.msg); - } + if prepend_subject && !subject.is_empty() { + let part_with_text = self + .parts + .iter_mut() + .find(|part| !part.msg.is_empty() && !part.is_reaction); + if let Some(part) = part_with_text { + // Message bubbles are small, so we use en dash to save space. In some + // languages there may be em dashes in the message text added by the author, + // they may look stronger than Subject separation, this is a known thing. + // Anyway, classic email support isn't a priority as of 2025. + part.msg = format!("{} – {}", subject, part.msg); } } } @@ -881,21 +880,22 @@ impl MimeMessage { self.parse_attachments(); // See if an MDN is requested from the other side - if !self.decrypting_failed && !self.parts.is_empty() { - if let Some(ref dn_to) = self.chat_disposition_notification_to { - // Check that the message is not outgoing. - let from = &self.from.addr; - if !context.is_self_addr(from).await? { - if from.to_lowercase() == dn_to.addr.to_lowercase() { - if let Some(part) = self.parts.last_mut() { - part.param.set_int(Param::WantsMdn, 1); - } - } else { - warn!( - context, - "{} requested a read receipt to {}, ignoring", from, dn_to.addr - ); + if !self.decrypting_failed + && !self.parts.is_empty() + && let Some(ref dn_to) = self.chat_disposition_notification_to + { + // Check that the message is not outgoing. + let from = &self.from.addr; + if !context.is_self_addr(from).await? { + if from.to_lowercase() == dn_to.addr.to_lowercase() { + if let Some(part) = self.parts.last_mut() { + part.param.set_int(Param::WantsMdn, 1); } + } else { + warn!( + context, + "{} requested a read receipt to {}, ignoring", from, dn_to.addr + ); } } } @@ -910,10 +910,11 @@ impl MimeMessage { ..Default::default() }; - if let Some(ref subject) = self.get_subject() { - if !self.has_chat_version() && self.webxdc_status_update.is_none() { - part.msg = subject.to_string(); - } + if let Some(ref subject) = self.get_subject() + && !self.has_chat_version() + && self.webxdc_status_update.is_none() + { + part.msg = subject.to_string(); } self.do_add_single_part(part); @@ -952,15 +953,15 @@ impl MimeMessage { let mut i = 0; while let Some(part) = self.parts.get_mut(i) { - if let Some(part_filename) = &part.org_filename { - if part_filename == &header_value { - if let Some(blob) = part.param.get(Param::File) { - let res = Some(AvatarAction::Change(blob.to_string())); - self.parts.remove(i); - return Ok(res); - } - break; + if let Some(part_filename) = &part.org_filename + && part_filename == &header_value + { + if let Some(blob) = part.param.get(Param::File) { + let res = Some(AvatarAction::Change(blob.to_string())); + self.parts.remove(i); + return Ok(res); } + break; } i += 1; } @@ -1604,13 +1605,13 @@ impl MimeMessage { } else if let Some(sender) = self.get_header(HeaderDef::Sender) { // the `Sender:`-header alone is no indicator for mailing list // as also used for bot-impersonation via `set_override_sender_name()` - if let Some(precedence) = self.get_header(HeaderDef::Precedence) { - if precedence == "list" || precedence == "bulk" { - // The message belongs to a mailing list, but there is no `ListId:`-header; - // `Sender:`-header is be used to get a unique id. - // This method is used by implementations as Majordomo. - return Some(sender); - } + if let Some(precedence) = self.get_header(HeaderDef::Precedence) + && (precedence == "list" || precedence == "bulk") + { + // The message belongs to a mailing list, but there is no `ListId:`-header; + // `Sender:`-header is be used to get a unique id. + // This method is used by implementations as Majordomo. + return Some(sender); } } None @@ -1651,10 +1652,10 @@ impl MimeMessage { remove_header(headers, "autocrypt-gossip", removed); // Secure-Join is secured unless it is an initial "vc-request"/"vg-request". - if let Some(secure_join) = remove_header(headers, "secure-join", removed) { - if secure_join == "vc-request" || secure_join == "vg-request" { - headers.insert("secure-join".to_string(), secure_join); - } + if let Some(secure_join) = remove_header(headers, "secure-join", removed) + && (secure_join == "vc-request" || secure_join == "vg-request") + { + headers.insert("secure-join".to_string(), secure_join); } } @@ -1889,12 +1890,11 @@ impl MimeMessage { .iter() .filter(|p| p.typ == Viewtype::Text) .count(); - if text_part_cnt == 2 { - if let Some(last_part) = self.parts.last() { - if last_part.typ == Viewtype::Text { - self.parts.pop(); - } - } + if text_part_cnt == 2 + && let Some(last_part) = self.parts.last() + && last_part.typ == Viewtype::Text + { + self.parts.pop(); } } } @@ -1947,15 +1947,15 @@ impl MimeMessage { } } - if let Some(delivery_report) = &self.delivery_report { - if delivery_report.failure { - let error = parts - .iter() - .find(|p| p.typ == Viewtype::Text) - .map(|p| p.msg.clone()); - if let Err(err) = handle_ndn(context, delivery_report, error).await { - warn!(context, "Could not handle NDN: {err:#}."); - } + if let Some(delivery_report) = &self.delivery_report + && delivery_report.failure + { + let error = parts + .iter() + .find(|p| p.typ == Viewtype::Text) + .map(|p| p.msg.clone()); + if let Err(err) = handle_ndn(context, delivery_report, error).await { + warn!(context, "Could not handle NDN: {err:#}."); } } } @@ -2303,14 +2303,14 @@ fn get_attachment_filename( // `Content-Disposition: ... filename=...` let mut desired_filename = ct.params.get("filename").map(|s| s.to_string()); - if desired_filename.is_none() { - if let Some(name) = ct.params.get("filename*").map(|s| s.to_string()) { - // be graceful and just use the original name. - // some MUA, including Delta Chat up to core1.50, - // use `filename*` mistakenly for simple encoded-words without following rfc2231 - warn!(context, "apostrophed encoding invalid: {}", name); - desired_filename = Some(name); - } + if desired_filename.is_none() + && let Some(name) = ct.params.get("filename*").map(|s| s.to_string()) + { + // be graceful and just use the original name. + // some MUA, including Delta Chat up to core1.50, + // use `filename*` mistakenly for simple encoded-words without following rfc2231 + warn!(context, "apostrophed encoding invalid: {}", name); + desired_filename = Some(name); } // if no filename is set, try `Content-Disposition: ... name=...` @@ -2383,24 +2383,23 @@ fn get_all_addresses_from_header(headers: &[MailHeader], header: &str) -> Vec { + for addr in addrs.iter() { + match addr { + mailparse::MailAddr::Single(info) => { + result.push(SingleInfo { + addr: addr_normalize(&info.addr).to_lowercase(), + display_name: info.display_name.clone(), + }); + } + mailparse::MailAddr::Group(infos) => { + for info in &infos.addrs { result.push(SingleInfo { addr: addr_normalize(&info.addr).to_lowercase(), display_name: info.display_name.clone(), }); } - mailparse::MailAddr::Group(infos) => { - for info in &infos.addrs { - result.push(SingleInfo { - addr: addr_normalize(&info.addr).to_lowercase(), - display_name: info.display_name.clone(), - }); - } - } } } } diff --git a/src/mimeparser/mimeparser_tests.rs b/src/mimeparser/mimeparser_tests.rs index 0059039b0..6d198075b 100644 --- a/src/mimeparser/mimeparser_tests.rs +++ b/src/mimeparser/mimeparser_tests.rs @@ -1774,10 +1774,10 @@ async fn test_hp_legacy_display() -> Result<()> { alice.set_config_bool(Config::TestHooks, true).await?; *alice.pre_encrypt_mime_hook.lock() = Some(|_, mut mime| { for (h, v) in &mut mime.headers { - if h == "Content-Type" { - if let mail_builder::headers::HeaderType::ContentType(ct) = v { - *ct = ct.clone().attribute("hp-legacy-display", "1"); - } + if h == "Content-Type" + && let mail_builder::headers::HeaderType::ContentType(ct) = v + { + *ct = ct.clone().attribute("hp-legacy-display", "1"); } } mime diff --git a/src/oauth2.rs b/src/oauth2.rs index a29e9d007..c42fee18a 100644 --- a/src/oauth2.rs +++ b/src/oauth2.rs @@ -139,10 +139,10 @@ pub(crate) async fn get_oauth2_access_token( value = &redirect_uri; } else if value == "$CODE" { value = code; - } else if value == "$REFRESH_TOKEN" { - if let Some(refresh_token) = refresh_token.as_ref() { - value = refresh_token; - } + } else if value == "$REFRESH_TOKEN" + && let Some(refresh_token) = refresh_token.as_ref() + { + value = refresh_token; } post_param.insert(key, value); @@ -261,14 +261,12 @@ impl Oauth2 { if let Some(domain) = addr_normalized .find('@') .map(|index| addr_normalized.split_at(index + 1).1) - { - if let Some(oauth2_authorizer) = provider::get_provider_info(domain) + && let Some(oauth2_authorizer) = provider::get_provider_info(domain) .and_then(|provider| provider.oauth2_authorizer.as_ref()) - { - return Some(match oauth2_authorizer { - Oauth2Authorizer::Yandex => OAUTH2_YANDEX, - }); - } + { + return Some(match oauth2_authorizer { + Oauth2Authorizer::Yandex => OAUTH2_YANDEX, + }); } None } diff --git a/src/receive_imf.rs b/src/receive_imf.rs index f8d2b909b..3febeac50 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -884,53 +884,35 @@ pub(crate) async fn receive_imf_inner( } } - if let Some(avatar_action) = &mime_parser.user_avatar { - if from_id != ContactId::UNDEFINED - && context - .update_contacts_timestamp( - from_id, - Param::AvatarTimestamp, - mime_parser.timestamp_sent, - ) - .await? - { - if let Err(err) = contact::set_profile_image( - context, - from_id, - avatar_action, - mime_parser.was_encrypted(), - ) - .await - { - warn!(context, "receive_imf cannot update profile image: {err:#}."); - }; - } - } + if let Some(avatar_action) = &mime_parser.user_avatar + && from_id != ContactId::UNDEFINED + && context + .update_contacts_timestamp(from_id, Param::AvatarTimestamp, mime_parser.timestamp_sent) + .await? + && let Err(err) = + contact::set_profile_image(context, from_id, avatar_action, mime_parser.was_encrypted()) + .await + { + warn!(context, "receive_imf cannot update profile image: {err:#}."); + }; // Ignore footers from mailinglists as they are often created or modified by the mailinglist software. - if let Some(footer) = &mime_parser.footer { - if !mime_parser.is_mailinglist_message() - && from_id != ContactId::UNDEFINED - && context - .update_contacts_timestamp( - from_id, - Param::StatusTimestamp, - mime_parser.timestamp_sent, - ) - .await? - { - if let Err(err) = contact::set_status( - context, - from_id, - footer.to_string(), - mime_parser.was_encrypted(), - mime_parser.has_chat_version(), - ) - .await - { - warn!(context, "Cannot update contact status: {err:#}."); - } - } + if let Some(footer) = &mime_parser.footer + && !mime_parser.is_mailinglist_message() + && from_id != ContactId::UNDEFINED + && context + .update_contacts_timestamp(from_id, Param::StatusTimestamp, mime_parser.timestamp_sent) + .await? + && let Err(err) = contact::set_status( + context, + from_id, + footer.to_string(), + mime_parser.was_encrypted(), + mime_parser.has_chat_version(), + ) + .await + { + warn!(context, "Cannot update contact status: {err:#}."); } // Get user-configured server deletion @@ -1341,8 +1323,8 @@ async fn do_chat_assignment( if let Some((id, blocked)) = chat::get_chat_id_by_grpid(context, grpid).await? { chat_id = Some(id); chat_id_blocked = blocked; - } else if allow_creation || test_normal_chat.is_some() { - if let Some((new_chat_id, new_chat_id_blocked)) = create_group( + } else if (allow_creation || test_normal_chat.is_some()) + && let Some((new_chat_id, new_chat_id_blocked)) = create_group( context, mime_parser, is_partial_download.is_some(), @@ -1353,16 +1335,15 @@ async fn do_chat_assignment( grpid, ) .await? - { - chat_id = Some(new_chat_id); - chat_id_blocked = new_chat_id_blocked; - chat_created = true; - } + { + chat_id = Some(new_chat_id); + chat_id_blocked = new_chat_id_blocked; + chat_created = true; } } ChatAssignment::MailingListOrBroadcast => { - if let Some(mailinglist_header) = mime_parser.get_mailinglist_header() { - if let Some((new_chat_id, new_chat_id_blocked, new_chat_created)) = + if let Some(mailinglist_header) = mime_parser.get_mailinglist_header() + && let Some((new_chat_id, new_chat_id_blocked, new_chat_created)) = create_or_lookup_mailinglist_or_broadcast( context, allow_creation, @@ -1372,13 +1353,12 @@ async fn do_chat_assignment( mime_parser, ) .await? - { - chat_id = Some(new_chat_id); - chat_id_blocked = new_chat_id_blocked; - chat_created = new_chat_created; + { + chat_id = Some(new_chat_id); + chat_id_blocked = new_chat_id_blocked; + chat_created = new_chat_created; - apply_mailinglist_changes(context, mime_parser, new_chat_id).await?; - } + apply_mailinglist_changes(context, mime_parser, new_chat_id).await?; } } ChatAssignment::ExistingChat { @@ -1413,11 +1393,10 @@ async fn do_chat_assignment( if chat_id_blocked != Blocked::Not && create_blocked != Blocked::Yes && !matches!(chat_assignment, ChatAssignment::MailingListOrBroadcast) + && let Some(chat_id) = chat_id { - if let Some(chat_id) = chat_id { - chat_id.set_blocked(context, create_blocked).await?; - chat_id_blocked = create_blocked; - } + chat_id.set_blocked(context, create_blocked).await?; + chat_id_blocked = create_blocked; } if chat_id.is_none() { @@ -1441,21 +1420,20 @@ async fn do_chat_assignment( chat_created = true; } - if let Some(chat_id) = chat_id { - if chat_id_blocked != Blocked::Not { - if chat_id_blocked != create_blocked { - chat_id.set_blocked(context, create_blocked).await?; - } - if create_blocked == Blocked::Request && parent_message.is_some() { - // we do not want any chat to be created implicitly. Because of the origin-scale-up, - // the contact requests will pop up and this should be just fine. - ContactId::scaleup_origin(context, &[from_id], Origin::IncomingReplyTo) - .await?; - info!( - context, - "Message is a reply to a known message, mark sender as known.", - ); - } + if let Some(chat_id) = chat_id + && chat_id_blocked != Blocked::Not + { + if chat_id_blocked != create_blocked { + chat_id.set_blocked(context, create_blocked).await?; + } + if create_blocked == Blocked::Request && parent_message.is_some() { + // we do not want any chat to be created implicitly. Because of the origin-scale-up, + // the contact requests will pop up and this should be just fine. + ContactId::scaleup_origin(context, &[from_id], Origin::IncomingReplyTo).await?; + info!( + context, + "Message is a reply to a known message, mark sender as known.", + ); } } } @@ -1476,8 +1454,8 @@ async fn do_chat_assignment( if let Some((id, blocked)) = chat::get_chat_id_by_grpid(context, grpid).await? { chat_id = Some(id); chat_id_blocked = blocked; - } else if allow_creation { - if let Some((new_chat_id, new_chat_id_blocked)) = create_group( + } else if allow_creation + && let Some((new_chat_id, new_chat_id_blocked)) = create_group( context, mime_parser, is_partial_download.is_some(), @@ -1488,11 +1466,10 @@ async fn do_chat_assignment( grpid, ) .await? - { - chat_id = Some(new_chat_id); - chat_id_blocked = new_chat_id_blocked; - chat_created = true; - } + { + chat_id = Some(new_chat_id); + chat_id_blocked = new_chat_id_blocked; + chat_created = true; } } ChatAssignment::ExistingChat { @@ -1574,11 +1551,12 @@ async fn do_chat_assignment( chat_created = true; } } - if chat_id.is_none() && mime_parser.has_chat_version() { - if let Some(chat) = ChatIdBlocked::lookup_by_contact(context, to_id).await? { - chat_id = Some(chat.id); - chat_id_blocked = chat.blocked; - } + if chat_id.is_none() + && mime_parser.has_chat_version() + && let Some(chat) = ChatIdBlocked::lookup_by_contact(context, to_id).await? + { + chat_id = Some(chat.id); + chat_id_blocked = chat.blocked; } } @@ -1598,11 +1576,11 @@ async fn do_chat_assignment( } // automatically unblock chat when the user sends a message - if chat_id_blocked != Blocked::Not { - if let Some(chat_id) = chat_id { - chat_id.unblock_ex(context, Nosync).await?; - chat_id_blocked = Blocked::Not; - } + if chat_id_blocked != Blocked::Not + && let Some(chat_id) = chat_id + { + chat_id.unblock_ex(context, Nosync).await?; + chat_id_blocked = Blocked::Not; } } let chat_id = chat_id.unwrap_or_else(|| { @@ -1640,11 +1618,9 @@ async fn add_parts( // if contact renaming is prevented (for mailinglists and bots), // we use name from From:-header as override name - if prevent_rename { - if let Some(name) = &mime_parser.from.display_name { - for part in &mut mime_parser.parts { - part.param.set(Param::OverrideSenderDisplayname, name); - } + if prevent_rename && let Some(name) = &mime_parser.from.display_name { + for part in &mut mime_parser.parts { + part.param.set(Param::OverrideSenderDisplayname, name); } } @@ -2270,36 +2246,36 @@ async fn handle_edit_delete( "Edit message: rfc724_mid {rfc724_mid:?} not found." ); } - } else if let Some(rfc724_mid_list) = mime_parser.get_header(HeaderDef::ChatDelete) { - if let Some(part) = mime_parser.parts.first() { - // See `message::delete_msgs_ex()`, unlike edit requests, DC doesn't send unencrypted - // deletion requests, so there's no need to support them. - if part.param.get_bool(Param::GuaranteeE2ee).unwrap_or(false) { - let mut modified_chat_ids = HashSet::new(); - let mut msg_ids = Vec::new(); + } else if let Some(rfc724_mid_list) = mime_parser.get_header(HeaderDef::ChatDelete) + && let Some(part) = mime_parser.parts.first() + { + // See `message::delete_msgs_ex()`, unlike edit requests, DC doesn't send unencrypted + // deletion requests, so there's no need to support them. + if part.param.get_bool(Param::GuaranteeE2ee).unwrap_or(false) { + let mut modified_chat_ids = HashSet::new(); + let mut msg_ids = Vec::new(); - let rfc724_mid_vec: Vec<&str> = rfc724_mid_list.split_whitespace().collect(); - for rfc724_mid in rfc724_mid_vec { - if let Some(msg_id) = message::rfc724_mid_exists(context, rfc724_mid).await? { - if let Some(msg) = Message::load_from_db_optional(context, msg_id).await? { - if msg.from_id == from_id { - message::delete_msg_locally(context, &msg).await?; - msg_ids.push(msg.id); - modified_chat_ids.insert(msg.chat_id); - } else { - warn!(context, "Delete message: Bad sender."); - } + let rfc724_mid_vec: Vec<&str> = rfc724_mid_list.split_whitespace().collect(); + for rfc724_mid in rfc724_mid_vec { + if let Some(msg_id) = message::rfc724_mid_exists(context, rfc724_mid).await? { + if let Some(msg) = Message::load_from_db_optional(context, msg_id).await? { + if msg.from_id == from_id { + message::delete_msg_locally(context, &msg).await?; + msg_ids.push(msg.id); + modified_chat_ids.insert(msg.chat_id); } else { - warn!(context, "Delete message: Database entry does not exist."); + warn!(context, "Delete message: Bad sender."); } } else { - warn!(context, "Delete message: {rfc724_mid:?} not found."); + warn!(context, "Delete message: Database entry does not exist."); } + } else { + warn!(context, "Delete message: {rfc724_mid:?} not found."); } - message::delete_msgs_locally_done(context, &msg_ids, modified_chat_ids).await?; - } else { - warn!(context, "Delete message: Not encrypted."); } + message::delete_msgs_locally_done(context, &msg_ids, modified_chat_ids).await?; + } else { + warn!(context, "Delete message: Not encrypted."); } } Ok(()) @@ -2356,33 +2332,32 @@ async fn save_locations( let mut send_event = false; - if let Some(message_kml) = &mime_parser.message_kml { - if let Some(newest_location_id) = + if let Some(message_kml) = &mime_parser.message_kml + && let Some(newest_location_id) = location::save(context, chat_id, from_id, &message_kml.locations, true).await? - { - location::set_msg_location_id(context, msg_id, newest_location_id).await?; - send_event = true; - } + { + location::set_msg_location_id(context, msg_id, newest_location_id).await?; + send_event = true; } - if let Some(location_kml) = &mime_parser.location_kml { - if let Some(addr) = &location_kml.addr { - let contact = Contact::get_by_id(context, from_id).await?; - if contact.get_addr().to_lowercase() == addr.to_lowercase() { - if location::save(context, chat_id, from_id, &location_kml.locations, false) - .await? - .is_some() - { - send_event = true; - } - } else { - warn!( - context, - "Address in location.kml {:?} is not the same as the sender address {:?}.", - addr, - contact.get_addr() - ); + if let Some(location_kml) = &mime_parser.location_kml + && let Some(addr) = &location_kml.addr + { + let contact = Contact::get_by_id(context, from_id).await?; + if contact.get_addr().to_lowercase() == addr.to_lowercase() { + if location::save(context, chat_id, from_id, &location_kml.locations, false) + .await? + .is_some() + { + send_event = true; } + } else { + warn!( + context, + "Address in location.kml {:?} is not the same as the sender address {:?}.", + addr, + contact.get_addr() + ); } } if send_event { @@ -2734,13 +2709,13 @@ async fn update_chats_contacts_timestamps( to_ids.iter(), chat_group_member_timestamps.iter().take(to_ids.len()), ) { - if let Some(contact_id) = contact_id { - if Some(*contact_id) != ignored_id { - // It could be that member was already added, - // but updated addition timestamp - // is also a modification worth notifying about. - modified |= add_statement.execute((chat_id, contact_id, ts))? > 0; - } + if let Some(contact_id) = contact_id + && Some(*contact_id) != ignored_id + { + // It could be that member was already added, + // but updated addition timestamp + // is also a modification worth notifying about. + modified |= add_statement.execute((chat_id, contact_id, ts))? > 0; } } @@ -3003,13 +2978,14 @@ async fn apply_group_changes( .copied() .collect(); - if let Some(added_id) = added_id { - if !added_ids.remove(&added_id) && added_id != ContactId::SELF { - // No-op "Member added" message. An exception is self-addition messages because they at - // least must be shown when a chat is created on our side. - info!(context, "No-op 'Member added' message (TRASH)"); - better_msg = Some(String::new()); - } + if let Some(added_id) = added_id + && !added_ids.remove(&added_id) + && added_id != ContactId::SELF + { + // No-op "Member added" message. An exception is self-addition messages because they at + // least must be shown when a chat is created on our side. + info!(context, "No-op 'Member added' message (TRASH)"); + better_msg = Some(String::new()); } if let Some(removed_id) = removed_id { removed_ids.remove(&removed_id); @@ -3064,59 +3040,52 @@ async fn apply_chat_name_and_avatar_changes( Some(_) => Some(chat.name.as_str()), None => None, }) - { - if let Some(grpname) = mime_parser + && let Some(grpname) = mime_parser .get_header(HeaderDef::ChatGroupName) .map(|grpname| grpname.trim()) .filter(|grpname| grpname.len() < 200) - { - let grpname = &sanitize_single_line(grpname); + { + let grpname = &sanitize_single_line(grpname); - let chat_group_name_timestamp = - chat.param.get_i64(Param::GroupNameTimestamp).unwrap_or(0); - let group_name_timestamp = group_name_timestamp.unwrap_or(mime_parser.timestamp_sent); - // To provide group name consistency, compare names if timestamps are equal. - if (chat_group_name_timestamp, grpname) < (group_name_timestamp, &chat.name) - && chat - .id - .update_timestamp(context, Param::GroupNameTimestamp, group_name_timestamp) - .await? - && grpname != &chat.name - { - info!(context, "Updating grpname for chat {}.", chat.id); - context - .sql - .execute("UPDATE chats SET name=? WHERE id=?;", (grpname, chat.id)) - .await?; - *send_event_chat_modified = true; - } - if mime_parser - .get_header(HeaderDef::ChatGroupNameChanged) - .is_some() - { - let old_name = &sanitize_single_line(old_name); - better_msg.get_or_insert( - stock_str::msg_grp_name(context, old_name, grpname, from_id).await, - ); - } + let chat_group_name_timestamp = chat.param.get_i64(Param::GroupNameTimestamp).unwrap_or(0); + let group_name_timestamp = group_name_timestamp.unwrap_or(mime_parser.timestamp_sent); + // To provide group name consistency, compare names if timestamps are equal. + if (chat_group_name_timestamp, grpname) < (group_name_timestamp, &chat.name) + && chat + .id + .update_timestamp(context, Param::GroupNameTimestamp, group_name_timestamp) + .await? + && grpname != &chat.name + { + info!(context, "Updating grpname for chat {}.", chat.id); + context + .sql + .execute("UPDATE chats SET name=? WHERE id=?;", (grpname, chat.id)) + .await?; + *send_event_chat_modified = true; + } + if mime_parser + .get_header(HeaderDef::ChatGroupNameChanged) + .is_some() + { + let old_name = &sanitize_single_line(old_name); + better_msg + .get_or_insert(stock_str::msg_grp_name(context, old_name, grpname, from_id).await); } } // ========== Apply chat avatar changes ========== - if let (Some(value), None) = (mime_parser.get_header(HeaderDef::ChatContent), &better_msg) { - if value == "group-avatar-changed" { - if let Some(avatar_action) = &mime_parser.group_avatar { - // this is just an explicit message containing the group-avatar, - // apart from that, the group-avatar is send along with various other messages - better_msg.get_or_insert(match avatar_action { - AvatarAction::Delete => stock_str::msg_grp_img_deleted(context, from_id).await, - AvatarAction::Change(_) => { - stock_str::msg_grp_img_changed(context, from_id).await - } - }); - } - } + if let (Some(value), None) = (mime_parser.get_header(HeaderDef::ChatContent), &better_msg) + && value == "group-avatar-changed" + && let Some(avatar_action) = &mime_parser.group_avatar + { + // this is just an explicit message containing the group-avatar, + // apart from that, the group-avatar is send along with various other messages + better_msg.get_or_insert(match avatar_action { + AvatarAction::Delete => stock_str::msg_grp_img_deleted(context, from_id).await, + AvatarAction::Change(_) => stock_str::msg_grp_img_changed(context, from_id).await, + }); } if let Some(avatar_action) = &mime_parser.group_avatar { @@ -3297,10 +3266,10 @@ fn compute_mailinglist_name( // for mailchimp lists, the name in `ListId` is just a long number. // a usable name for these lists is in the `From` header // and we can detect these lists by a unique `ListId`-suffix. - if listid.ends_with(".list-id.mcsv.net") { - if let Some(display_name) = &mime_parser.from.display_name { - name.clone_from(display_name); - } + if listid.ends_with(".list-id.mcsv.net") + && let Some(display_name) = &mime_parser.from.display_name + { + name.clone_from(display_name); } // additional names in square brackets in the subject are preferred @@ -3325,10 +3294,9 @@ fn compute_mailinglist_name( || mime_parser.from.addr.starts_with("notifications@") || mime_parser.from.addr.starts_with("newsletter@") || listid.ends_with(".xt.local")) + && let Some(display_name) = &mime_parser.from.display_name { - if let Some(display_name) = &mime_parser.from.display_name { - name.clone_from(display_name); - } + name.clone_from(display_name); } // as a last resort, use the ListId as the name @@ -3476,15 +3444,15 @@ async fn apply_out_broadcast_changes( chat::remove_from_chat_contacts_table_without_trace(context, chat.id, from_id).await?; info!(context, "Broadcast leave message (TRASH)"); better_msg = Some("".to_string()); - } else if from_id == ContactId::SELF { - if let Some(removed_id) = removed_id { - chat::remove_from_chat_contacts_table_without_trace(context, chat.id, removed_id) - .await?; + } else if from_id == ContactId::SELF + && let Some(removed_id) = removed_id + { + chat::remove_from_chat_contacts_table_without_trace(context, chat.id, removed_id) + .await?; - better_msg.get_or_insert( - stock_str::msg_del_member_local(context, removed_id, ContactId::SELF).await, - ); - } + better_msg.get_or_insert( + stock_str::msg_del_member_local(context, removed_id, ContactId::SELF).await, + ); } } @@ -3508,14 +3476,14 @@ async fn apply_in_broadcast_changes( ) -> Result { ensure!(chat.typ == Chattype::InBroadcast); - if let Some(part) = mime_parser.parts.first() { - if let Some(error) = &part.error { - warn!( - context, - "Not applying broadcast changes from message with error: {error}" - ); - return Ok(GroupChangesInfo::default()); - } + if let Some(part) = mime_parser.parts.first() + && let Some(error) = &part.error + { + warn!( + context, + "Not applying broadcast changes from message with error: {error}" + ); + return Ok(GroupChangesInfo::default()); } let mut send_event_chat_modified = false; @@ -3531,21 +3499,21 @@ async fn apply_in_broadcast_changes( ) .await?; - if let Some(added_addr) = mime_parser.get_header(HeaderDef::ChatGroupMemberAdded) { - if context.is_self_addr(added_addr).await? { - let msg = if chat.is_self_in_chat(context).await? { - // Self is already in the chat. - // Probably Alice has two devices and her second device added us again; - // just hide the message. - info!(context, "No-op broadcast 'Member added' message (TRASH)"); - "".to_string() - } else { - stock_str::msg_you_joined_broadcast(context).await - }; + if let Some(added_addr) = mime_parser.get_header(HeaderDef::ChatGroupMemberAdded) + && context.is_self_addr(added_addr).await? + { + let msg = if chat.is_self_in_chat(context).await? { + // Self is already in the chat. + // Probably Alice has two devices and her second device added us again; + // just hide the message. + info!(context, "No-op broadcast 'Member added' message (TRASH)"); + "".to_string() + } else { + stock_str::msg_you_joined_broadcast(context).await + }; - better_msg.get_or_insert(msg); - send_event_chat_modified = true; - } + better_msg.get_or_insert(msg); + send_event_chat_modified = true; } if let Some(removed_fpr) = mime_parser.get_header(HeaderDef::ChatGroupMemberRemovedFpr) { @@ -3756,12 +3724,11 @@ async fn get_previous_message( context: &Context, mime_parser: &MimeMessage, ) -> Result> { - if let Some(field) = mime_parser.get_header(HeaderDef::References) { - if let Some(rfc724mid) = parse_message_ids(field).last() { - if let Some(msg_id) = rfc724_mid_exists(context, rfc724mid).await? { - return Message::load_from_db_optional(context, msg_id).await; - } - } + if let Some(field) = mime_parser.get_header(HeaderDef::References) + && let Some(rfc724mid) = parse_message_ids(field).last() + && let Some(msg_id) = rfc724_mid_exists(context, rfc724mid).await? + { + return Message::load_from_db_optional(context, msg_id).await; } Ok(None) } diff --git a/src/scheduler.rs b/src/scheduler.rs index 9afc9820a..5025d5023 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -474,17 +474,17 @@ async fn inbox_fetch_idle(ctx: &Context, imap: &mut Imap, mut session: Session) } // Update quota no more than once a minute. - if ctx.quota_needs_update(60).await { - if let Err(err) = ctx.update_recent_quota(&mut session).await { - warn!(ctx, "Failed to update quota: {:#}.", err); - } + if ctx.quota_needs_update(60).await + && let Err(err) = ctx.update_recent_quota(&mut session).await + { + warn!(ctx, "Failed to update quota: {:#}.", err); } - if let Ok(()) = imap.resync_request_receiver.try_recv() { - if let Err(err) = session.resync_folders(ctx).await { - warn!(ctx, "Failed to resync folders: {:#}.", err); - imap.resync_request_sender.try_send(()).ok(); - } + if let Ok(()) = imap.resync_request_receiver.try_recv() + && let Err(err) = session.resync_folders(ctx).await + { + warn!(ctx, "Failed to resync folders: {:#}.", err); + imap.resync_request_sender.try_send(()).ok(); } maybe_add_time_based_warnings(ctx).await; diff --git a/src/simplify.rs b/src/simplify.rs index c342c6356..e4ea3c60a 100644 --- a/src/simplify.rs +++ b/src/simplify.rs @@ -199,19 +199,17 @@ fn remove_bottom_quote<'a>(lines: &'a [&str]) -> (&'a [&'a str], Option) }) .collect::>() .join("\n"); - if l_last > 1 { - if let Some(line) = lines.get(l_last - 1) { - if is_empty_line(line) { - l_last -= 1 - } - } + if l_last > 1 + && let Some(line) = lines.get(l_last - 1) + && is_empty_line(line) + { + l_last -= 1 } - if l_last > 1 { - if let Some(line) = lines.get(l_last - 1) { - if is_quoted_headline(line) { - l_last -= 1 - } - } + if l_last > 1 + && let Some(line) = lines.get(l_last - 1) + && is_quoted_headline(line) + { + l_last -= 1 } (lines.get(..l_last).unwrap_or(lines), Some(quoted_text)) } else { diff --git a/src/smtp.rs b/src/smtp.rs index 5c7e8df0a..ab03d50f3 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -307,24 +307,23 @@ pub(crate) async fn smtp_send( Ok(()) => SendResult::Success, }; - if let SendResult::Failure(err) = &status { - if let Some(msg_id) = msg_id { - // We couldn't send the message, so mark it as failed - match Message::load_from_db(context, msg_id).await { - Ok(mut msg) => { - if let Err(err) = - message::set_msg_failed(context, &mut msg, &err.to_string()).await - { - error!(context, "Failed to mark {msg_id} as failed: {err:#}."); - } - } - Err(err) => { - error!( - context, - "Failed to load {msg_id} to mark it as failed: {err:#}." - ); + if let SendResult::Failure(err) = &status + && let Some(msg_id) = msg_id + { + // We couldn't send the message, so mark it as failed + match Message::load_from_db(context, msg_id).await { + Ok(mut msg) => { + if let Err(err) = message::set_msg_failed(context, &mut msg, &err.to_string()).await + { + error!(context, "Failed to mark {msg_id} as failed: {err:#}."); } } + Err(err) => { + error!( + context, + "Failed to load {msg_id} to mark it as failed: {err:#}." + ); + } } } status diff --git a/src/sql.rs b/src/sql.rs index b82edaa8a..650d7ade3 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -235,26 +235,24 @@ impl Sql { } } - if recode_avatar { - if let Some(avatar) = context.get_config(Config::Selfavatar).await? { - let mut blob = BlobObject::from_path(context, Path::new(&avatar))?; - match blob.recode_to_avatar_size(context).await { - Ok(()) => { - if let Some(path) = blob.to_abs_path().to_str() { - context - .set_config_internal(Config::Selfavatar, Some(path)) - .await?; - } else { - warn!(context, "Setting selfavatar failed: non-UTF-8 filename"); - } - } - Err(e) => { - warn!(context, "Migrations can't recode avatar, removing. {:#}", e); + if recode_avatar && let Some(avatar) = context.get_config(Config::Selfavatar).await? { + let mut blob = BlobObject::from_path(context, Path::new(&avatar))?; + match blob.recode_to_avatar_size(context).await { + Ok(()) => { + if let Some(path) = blob.to_abs_path().to_str() { context - .set_config_internal(Config::Selfavatar, None) - .await? + .set_config_internal(Config::Selfavatar, Some(path)) + .await?; + } else { + warn!(context, "Setting selfavatar failed: non-UTF-8 filename"); } } + Err(e) => { + warn!(context, "Migrations can't recode avatar, removing. {:#}", e); + context + .set_config_internal(Config::Selfavatar, None) + .await? + } } } diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 7f1c8c407..8961eb09e 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -449,12 +449,11 @@ CREATE TABLE imap_sync (folder TEXT PRIMARY KEY, uidvalidity INTEGER DEFAULT 0, disable_server_delete = true; // Don't disable server delete if it was on by default (Nauta): - if let Some(provider) = context.get_configured_provider().await? { - if let Some(defaults) = &provider.config_defaults { - if defaults.iter().any(|d| d.key == Config::DeleteServerAfter) { - disable_server_delete = false; - } - } + if let Some(provider) = context.get_configured_provider().await? + && let Some(defaults) = &provider.config_defaults + && defaults.iter().any(|d| d.key == Config::DeleteServerAfter) + { + disable_server_delete = false; } } sql.set_db_version(73).await?; diff --git a/src/sql/pool.rs b/src/sql/pool.rs index 01f19b751..6de8da6ac 100644 --- a/src/sql/pool.rs +++ b/src/sql/pool.rs @@ -151,10 +151,10 @@ pub struct PooledConnection { impl Drop for PooledConnection { fn drop(&mut self) { // Put the connection back unless the pool is already dropped. - if let Some(pool) = self.pool.upgrade() { - if let Some(conn) = self.conn.take() { - pool.put(conn); - } + if let Some(pool) = self.pool.upgrade() + && let Some(conn) = self.conn.take() + { + pool.put(conn); } } } diff --git a/src/tools.rs b/src/tools.rs index 5b8e2530d..48363eabe 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -727,10 +727,10 @@ pub(crate) fn parse_receive_headers(headers: &Headers) -> String { /// Otherwise, return None. pub(crate) fn single_value(collection: impl IntoIterator) -> Option { let mut iter = collection.into_iter(); - if let Some(value) = iter.next() { - if iter.next().is_none() { - return Some(value); - } + if let Some(value) = iter.next() + && iter.next().is_none() + { + return Some(value); } None } diff --git a/src/webxdc.rs b/src/webxdc.rs index 6b8fd838c..4061a72bb 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -309,13 +309,11 @@ impl Context { }, ) .await? + && last_from_id == from_id + && last_param.get_cmd() == SystemMessage::WebxdcInfoMessage + && last_in_repl_to == instance.rfc724_mid { - if last_from_id == from_id - && last_param.get_cmd() == SystemMessage::WebxdcInfoMessage - && last_in_repl_to == instance.rfc724_mid - { - return Ok(Some(last_msg_id)); - } + return Ok(Some(last_msg_id)); } Ok(None) } @@ -341,63 +339,59 @@ impl Context { let mut param_changed = false; let mut instance = instance.clone(); - if let Some(ref document) = status_update_item.document { - if instance + if let Some(ref document) = status_update_item.document + && instance .param .update_timestamp(Param::WebxdcDocumentTimestamp, timestamp)? - { - instance.param.set(Param::WebxdcDocument, document); - param_changed = true; - } + { + instance.param.set(Param::WebxdcDocument, document); + param_changed = true; } - if let Some(ref summary) = status_update_item.summary { - if instance + if let Some(ref summary) = status_update_item.summary + && instance .param .update_timestamp(Param::WebxdcSummaryTimestamp, timestamp)? - { - let summary = sanitize_bidi_characters(summary); - instance.param.set(Param::WebxdcSummary, summary.clone()); - param_changed = true; - } + { + let summary = sanitize_bidi_characters(summary); + instance.param.set(Param::WebxdcSummary, summary.clone()); + param_changed = true; } - if can_info_msg { - if let Some(ref info) = status_update_item.info { - let info_msg_id = self - .get_overwritable_info_msg_id(&instance, from_id) - .await?; + if can_info_msg && let Some(ref info) = status_update_item.info { + let info_msg_id = self + .get_overwritable_info_msg_id(&instance, from_id) + .await?; - if let (Some(info_msg_id), None) = (info_msg_id, &status_update_item.href) { - chat::update_msg_text_and_timestamp( - self, - instance.chat_id, - info_msg_id, - info.as_str(), - timestamp, - ) - .await?; - notify_msg_id = info_msg_id; - } else { - notify_msg_id = chat::add_info_msg_with_cmd( - self, - instance.chat_id, - info.as_str(), - SystemMessage::WebxdcInfoMessage, - timestamp, - None, - Some(&instance), - Some(from_id), - None, - ) - .await?; - } + if let (Some(info_msg_id), None) = (info_msg_id, &status_update_item.href) { + chat::update_msg_text_and_timestamp( + self, + instance.chat_id, + info_msg_id, + info.as_str(), + timestamp, + ) + .await?; + notify_msg_id = info_msg_id; + } else { + notify_msg_id = chat::add_info_msg_with_cmd( + self, + instance.chat_id, + info.as_str(), + SystemMessage::WebxdcInfoMessage, + timestamp, + None, + Some(&instance), + Some(from_id), + None, + ) + .await?; + } - if let Some(ref href) = status_update_item.href { - let mut notify_msg = Message::load_from_db(self, notify_msg_id).await?; - notify_msg.param.set(Param::Arg, href); - notify_msg.update_param(self).await?; - } + if let Some(ref href) = status_update_item.href { + let mut notify_msg = Message::load_from_db(self, notify_msg_id).await?; + notify_msg.param.set(Param::Arg, href); + notify_msg.update_param(self).await?; } } @@ -413,20 +407,19 @@ impl Context { }); } - if from_id != ContactId::SELF { - if let Some(notify_list) = status_update_item.notify { - let self_addr = instance.get_webxdc_self_addr(self).await?; - if let Some(notify_text) = - notify_list.get(&self_addr).or_else(|| notify_list.get("*")) - { - self.emit_event(EventType::IncomingWebxdcNotify { - chat_id: instance.chat_id, - contact_id: from_id, - msg_id: notify_msg_id, - text: notify_text.clone(), - href: status_update_item.href, - }); - } + if from_id != ContactId::SELF + && let Some(notify_list) = status_update_item.notify + { + let self_addr = instance.get_webxdc_self_addr(self).await?; + if let Some(notify_text) = notify_list.get(&self_addr).or_else(|| notify_list.get("*")) + { + self.emit_event(EventType::IncomingWebxdcNotify { + chat_id: instance.chat_id, + contact_id: from_id, + msg_id: notify_msg_id, + text: notify_text.clone(), + href: status_update_item.href, + }); } } @@ -882,18 +875,15 @@ impl Message { let mut archive = self.get_webxdc_archive(context).await?; - if name == "index.html" { - if let Ok(bytes) = get_blob(&mut archive, "manifest.toml").await { - if let Ok(manifest) = parse_webxdc_manifest(&bytes) { - if let Some(min_api) = manifest.min_api { - if min_api > WEBXDC_API_VERSION { - return Ok(Vec::from( - "This Webxdc requires a newer Delta Chat version.", - )); - } - } - } - } + if name == "index.html" + && let Ok(bytes) = get_blob(&mut archive, "manifest.toml").await + && let Ok(manifest) = parse_webxdc_manifest(&bytes) + && let Some(min_api) = manifest.min_api + && min_api > WEBXDC_API_VERSION + { + return Ok(Vec::from( + "This Webxdc requires a newer Delta Chat version.", + )); } get_blob(&mut archive, name).await diff --git a/src/webxdc/maps_integration.rs b/src/webxdc/maps_integration.rs index 3ee931a59..28e3dd9bc 100644 --- a/src/webxdc/maps_integration.rs +++ b/src/webxdc/maps_integration.rs @@ -122,12 +122,11 @@ pub(crate) async fn intercept_get_updates( if location.independent != 0 { if let Some(marker) = &location.marker { label = marker.to_string() // marker contains one-char labels only - } else if location.msg_id != 0 { - if let Some(msg) = + } else if location.msg_id != 0 + && let Some(msg) = Message::load_from_db_optional(context, MsgId::new(location.msg_id)).await? - { - label = msg.get_text() - } + { + label = msg.get_text() } }