Reduce unwrap and expect usage

This commit is contained in:
link2xt
2022-05-21 14:12:23 +00:00
parent 9549aca48b
commit 73341394ee
16 changed files with 134 additions and 130 deletions

View File

@@ -3,7 +3,7 @@
## Unreleased
### Changes
- refactorings #3354
- refactorings #3354 #3347
### Fixes
- do not unnecessarily SELECT folders if there are no operations planned on

View File

@@ -458,7 +458,37 @@ pub unsafe extern "C" fn dc_event_get_id(event: *mut dc_event_t) -> libc::c_int
}
let event = &*event;
event.as_id()
match event.typ {
EventType::Info(_) => 100,
EventType::SmtpConnected(_) => 101,
EventType::ImapConnected(_) => 102,
EventType::SmtpMessageSent(_) => 103,
EventType::ImapMessageDeleted(_) => 104,
EventType::ImapMessageMoved(_) => 105,
EventType::NewBlobFile(_) => 150,
EventType::DeletedBlobFile(_) => 151,
EventType::Warning(_) => 300,
EventType::Error(_) => 400,
EventType::ErrorSelfNotInGroup(_) => 410,
EventType::MsgsChanged { .. } => 2000,
EventType::IncomingMsg { .. } => 2005,
EventType::MsgsNoticed { .. } => 2008,
EventType::MsgDelivered { .. } => 2010,
EventType::MsgFailed { .. } => 2012,
EventType::MsgRead { .. } => 2015,
EventType::ChatModified(_) => 2020,
EventType::ChatEphemeralTimerModified { .. } => 2021,
EventType::ContactsChanged(_) => 2030,
EventType::LocationChanged(_) => 2035,
EventType::ConfigureProgress { .. } => 2041,
EventType::ImexProgress(_) => 2051,
EventType::ImexFileWritten(_) => 2052,
EventType::SecurejoinInviterProgress { .. } => 2060,
EventType::SecurejoinJoinerProgress { .. } => 2061,
EventType::ConnectivityChanged => 2100,
EventType::SelfavatarChanged => 2110,
EventType::WebxdcStatusUpdate { .. } => 2120,
}
}
#[no_mangle]

View File

@@ -141,9 +141,10 @@ impl Accounts {
/// Remove an account.
pub async fn remove_account(&mut self, id: u32) -> Result<()> {
let ctx = self.accounts.remove(&id);
ensure!(ctx.is_some(), "no account with this id: {}", id);
let ctx = ctx.unwrap();
let ctx = self
.accounts
.remove(&id)
.with_context(|| format!("no account with id {}", id))?;
ctx.stop_io().await;
drop(ctx);

View File

@@ -289,7 +289,7 @@ impl<'a> BlobObject<'a> {
/// Returns the filename of the blob.
pub fn as_file_name(&self) -> &str {
self.name.rsplit('/').next().unwrap()
self.name.rsplit('/').next().unwrap_or_default()
}
/// The path relative in the blob directory.

View File

@@ -1441,7 +1441,9 @@ async fn create_or_lookup_group(
return Ok(None);
}
let grpname = mime_parser.get_header(HeaderDef::ChatGroupName).unwrap();
let grpname = mime_parser
.get_header(HeaderDef::ChatGroupName)
.context("Chat-Group-Name vanished")?;
let new_chat_id = ChatId::create_multiuser_record(
context,
Chattype::Group,

View File

@@ -1,10 +1,7 @@
//! # Events specification.
use std::ops::Deref;
use async_std::channel::{self, Receiver, Sender, TrySendError};
use async_std::path::PathBuf;
use strum::EnumProperty;
use crate::chat::ChatId;
use crate::contact::ContactId;
@@ -92,8 +89,6 @@ impl async_std::stream::Stream for EventEmitter {
/// context emits them in relation to various operations happening, a lot of these are again
/// documented in `deltachat.h`.
///
/// This struct [`Deref`]s to the [`EventType`].
///
/// [`Context`]: crate::context::Context
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Event {
@@ -110,68 +105,39 @@ pub struct Event {
pub typ: EventType,
}
impl Deref for Event {
type Target = EventType;
fn deref(&self) -> &EventType {
&self.typ
}
}
impl EventType {
/// Returns the corresponding Event ID.
///
/// These are the IDs used in the `DC_EVENT_*` constants in `deltachat.h`.
pub fn as_id(&self) -> i32 {
self.get_str("id")
.expect("missing id")
.parse()
.expect("invalid id")
}
}
#[derive(Debug, Clone, PartialEq, Eq, EnumProperty)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventType {
/// The library-user may write an informational string to the log.
///
/// This event should *not* be reported to the end-user using a popup or something like
/// that.
#[strum(props(id = "100"))]
Info(String),
/// Emitted when SMTP connection is established and login was successful.
#[strum(props(id = "101"))]
SmtpConnected(String),
/// Emitted when IMAP connection is established and login was successful.
#[strum(props(id = "102"))]
ImapConnected(String),
/// Emitted when a message was successfully sent to the SMTP server.
#[strum(props(id = "103"))]
SmtpMessageSent(String),
/// Emitted when an IMAP message has been marked as deleted
#[strum(props(id = "104"))]
ImapMessageDeleted(String),
/// Emitted when an IMAP message has been moved
#[strum(props(id = "105"))]
ImapMessageMoved(String),
/// Emitted when an new file in the $BLOBDIR was created
#[strum(props(id = "150"))]
NewBlobFile(String),
/// Emitted when an file in the $BLOBDIR was deleted
#[strum(props(id = "151"))]
DeletedBlobFile(String),
/// The library-user should write a warning string to the log.
///
/// This event should *not* be reported to the end-user using a popup or something like
/// that.
#[strum(props(id = "300"))]
Warning(String),
/// The library-user should report an error to the end-user.
@@ -184,7 +150,6 @@ pub enum EventType {
/// it might be better to delay showing these events until the function has really
/// failed (returned false). It should be sufficient to report only the *last* error
/// in a messasge box then.
#[strum(props(id = "400"))]
Error(String),
/// An action cannot be performed because the user is not in the group.
@@ -192,7 +157,6 @@ pub enum EventType {
/// dc_set_chat_name(), dc_set_chat_profile_image(),
/// dc_add_contact_to_chat(), dc_remove_contact_from_chat(),
/// dc_send_text_msg() or another sending function.
#[strum(props(id = "410"))]
ErrorSelfNotInGroup(String),
/// Messages or chats changed. One or more messages or chats changed for various
@@ -203,35 +167,44 @@ pub enum EventType {
///
/// `chat_id` is set if only a single chat is affected by the changes, otherwise 0.
/// `msg_id` is set if only a single message is affected by the changes, otherwise 0.
#[strum(props(id = "2000"))]
MsgsChanged { chat_id: ChatId, msg_id: MsgId },
MsgsChanged {
chat_id: ChatId,
msg_id: MsgId,
},
/// There is a fresh message. Typically, the user will show an notification
/// when receiving this message.
///
/// There is no extra #DC_EVENT_MSGS_CHANGED event send together with this event.
#[strum(props(id = "2005"))]
IncomingMsg { chat_id: ChatId, msg_id: MsgId },
IncomingMsg {
chat_id: ChatId,
msg_id: MsgId,
},
/// Messages were seen or noticed.
/// chat id is always set.
#[strum(props(id = "2008"))]
MsgsNoticed(ChatId),
/// A single message is sent successfully. State changed from DC_STATE_OUT_PENDING to
/// DC_STATE_OUT_DELIVERED, see dc_msg_get_state().
#[strum(props(id = "2010"))]
MsgDelivered { chat_id: ChatId, msg_id: MsgId },
MsgDelivered {
chat_id: ChatId,
msg_id: MsgId,
},
/// A single message could not be sent. State changed from DC_STATE_OUT_PENDING or DC_STATE_OUT_DELIVERED to
/// DC_STATE_OUT_FAILED, see dc_msg_get_state().
#[strum(props(id = "2012"))]
MsgFailed { chat_id: ChatId, msg_id: MsgId },
MsgFailed {
chat_id: ChatId,
msg_id: MsgId,
},
/// A single message is read by the receiver. State changed from DC_STATE_OUT_DELIVERED to
/// DC_STATE_OUT_MDN_RCVD, see dc_msg_get_state().
#[strum(props(id = "2015"))]
MsgRead { chat_id: ChatId, msg_id: MsgId },
MsgRead {
chat_id: ChatId,
msg_id: MsgId,
},
/// Chat changed. The name or the image of a chat group was changed or members were added or removed.
/// Or the verify state of a chat has changed.
@@ -240,11 +213,9 @@ pub enum EventType {
///
/// This event does not include ephemeral timer modification, which
/// is a separate event.
#[strum(props(id = "2020"))]
ChatModified(ChatId),
/// Chat ephemeral timer changed.
#[strum(props(id = "2021"))]
ChatEphemeralTimerModified {
chat_id: ChatId,
timer: EphemeralTimer,
@@ -253,7 +224,6 @@ pub enum EventType {
/// Contact(s) created, renamed, blocked or deleted.
///
/// @param data1 (int) If set, this is the contact_id of an added contact that should be selected.
#[strum(props(id = "2030"))]
ContactsChanged(Option<ContactId>),
/// Location of one or more contact has changed.
@@ -261,11 +231,9 @@ pub enum EventType {
/// @param data1 (u32) contact_id of the contact for which the location has changed.
/// If the locations of several contacts have been changed,
/// eg. after calling dc_delete_all_locations(), this parameter is set to `None`.
#[strum(props(id = "2035"))]
LocationChanged(Option<ContactId>),
/// Inform about the configuration progress started by configure().
#[strum(props(id = "2041"))]
ConfigureProgress {
/// Progress.
///
@@ -280,7 +248,6 @@ pub enum EventType {
///
/// @param data1 (usize) 0=error, 1-999=progress in permille, 1000=success and done
/// @param data2 0
#[strum(props(id = "2051"))]
ImexProgress(usize),
/// A file has been exported. A file has been written by imex().
@@ -290,7 +257,6 @@ pub enum EventType {
/// services.
///
/// @param data2 0
#[strum(props(id = "2052"))]
ImexFileWritten(PathBuf),
/// Progress information of a secure-join handshake from the view of the inviter
@@ -305,7 +271,6 @@ pub enum EventType {
/// 600=vg-/vc-request-with-auth received, vg-member-added/vc-contact-confirm sent, typically shown as "bob@addr verified".
/// 800=vg-member-added-received received, shown as "bob@addr securely joined GROUP", only sent for the verified-group-protocol.
/// 1000=Protocol finished for this contact.
#[strum(props(id = "2060"))]
SecurejoinInviterProgress {
contact_id: ContactId,
progress: usize,
@@ -319,7 +284,6 @@ pub enum EventType {
/// @param data2 (int) Progress as:
/// 400=vg-/vc-request-with-auth sent, typically shown as "alice@addr verified, introducing myself."
/// (Bob has verified alice and waits until Alice does the same for him)
#[strum(props(id = "2061"))]
SecurejoinJoinerProgress {
contact_id: ContactId,
progress: usize,
@@ -329,13 +293,10 @@ pub enum EventType {
/// This means that you should refresh the connectivity view
/// and possibly the connectivtiy HTML; see dc_get_connectivity() and
/// dc_get_connectivity_html() for details.
#[strum(props(id = "2100"))]
ConnectivityChanged,
#[strum(props(id = "2110"))]
SelfavatarChanged,
#[strum(props(id = "2120"))]
WebxdcStatusUpdate {
msg_id: MsgId,
status_update_serial: StatusUpdateSerial,

View File

@@ -11,7 +11,7 @@ use futures::future::FutureExt;
use std::future::Future;
use std::pin::Pin;
use anyhow::Result;
use anyhow::{Context as _, Result};
use lettre_email::mime::{self, Mime};
use crate::headerdef::{HeaderDef, HeaderDefMap};
@@ -134,7 +134,7 @@ impl HtmlMsgParser {
if raw.is_empty() {
return Ok(());
}
let mail = mailparse::parse_mail(&raw).unwrap();
let mail = mailparse::parse_mail(&raw).context("failed to parse mail")?;
self.collect_texts_recursive(context, &mail).await
}
MimeMultipartType::Single => {
@@ -190,7 +190,7 @@ impl HtmlMsgParser {
if raw.is_empty() {
return Ok(());
}
let mail = mailparse::parse_mail(&raw).unwrap();
let mail = mailparse::parse_mail(&raw).context("failed to parse mail")?;
self.cid_to_data_recursive(context, &mail).await
}
MimeMultipartType::Single => {

View File

@@ -4,7 +4,7 @@ use std::collections::BTreeMap;
use std::fmt;
use std::io::Cursor;
use anyhow::{format_err, Context as _, Result};
use anyhow::{ensure, Context as _, Result};
use async_trait::async_trait;
use num_traits::FromPrimitive;
use pgp::composed::Deserializable;
@@ -82,7 +82,7 @@ pub trait DcKey: Serialize + Deserializable + KeyTrait + Clone {
/// The fingerprint for the key.
fn fingerprint(&self) -> Fingerprint {
Fingerprint::new(KeyTrait::fingerprint(self)).expect("Invalid fingerprint from rpgp")
Fingerprint::new(KeyTrait::fingerprint(self))
}
}
@@ -320,11 +320,9 @@ pub async fn store_self_keypair(
pub struct Fingerprint(Vec<u8>);
impl Fingerprint {
pub fn new(v: Vec<u8>) -> Result<Fingerprint> {
match v.len() {
20 => Ok(Fingerprint(v)),
_ => Err(format_err!("Wrong fingerprint length")),
}
pub fn new(v: Vec<u8>) -> Fingerprint {
debug_assert_eq!(v.len(), 20);
Fingerprint(v)
}
/// Make a hex string from the fingerprint.
@@ -364,14 +362,15 @@ impl fmt::Display for Fingerprint {
impl std::str::FromStr for Fingerprint {
type Err = anyhow::Error;
fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
fn from_str(input: &str) -> Result<Self> {
let hex_repr: String = input
.to_uppercase()
.chars()
.filter(|&c| ('0'..='9').contains(&c) || ('A'..='F').contains(&c))
.collect();
let v: Vec<u8> = hex::decode(hex_repr)?;
let fp = Fingerprint::new(v)?;
let v: Vec<u8> = hex::decode(&hex_repr)?;
ensure!(v.len() == 20, "wrong fingerprint length: {}", hex_repr);
let fp = Fingerprint::new(v);
Ok(fp)
}
}
@@ -589,8 +588,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
fn test_fingerprint_from_str() {
let res = Fingerprint::new(vec![
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
])
.unwrap();
]);
let fp: Fingerprint = "0102030405060708090A0B0c0d0e0F1011121314".parse().unwrap();
assert_eq!(fp, res);
@@ -607,8 +605,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
fn test_fingerprint_hex() {
let fp = Fingerprint::new(vec![
1, 2, 4, 8, 16, 32, 64, 128, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
])
.unwrap();
]);
assert_eq!(fp.hex(), "0102040810204080FF0A0B0C0D0E0F1011121314");
}
@@ -616,8 +613,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
fn test_fingerprint_to_string() {
let fp = Fingerprint::new(vec![
1, 2, 4, 8, 16, 32, 64, 128, 255, 1, 2, 4, 8, 16, 32, 64, 128, 255, 19, 20,
])
.unwrap();
]);
assert_eq!(
fp.to_string(),
"0102 0408 1020 4080 FF01\n0204 0810 2040 80FF 1314"

View File

@@ -8,7 +8,9 @@
clippy::indexing_slicing,
clippy::wildcard_imports,
clippy::needless_borrow,
clippy::cast_lossless
clippy::cast_lossless,
clippy::unwrap_used,
clippy::expect_used
)]
#![allow(
clippy::match_bool,

View File

@@ -153,12 +153,12 @@ impl Kml {
) {
let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase();
if tag == "document" {
if let Some(addr) = event.attributes().find(|attr| {
attr.as_ref()
.map(|a| String::from_utf8_lossy(a.key).trim().to_lowercase() == "addr")
.unwrap_or_default()
}) {
self.addr = addr.unwrap().unescape_and_decode_value(reader).ok();
if let Some(addr) = event
.attributes()
.filter_map(|a| a.ok())
.find(|attr| String::from_utf8_lossy(attr.key).trim().to_lowercase() == "addr")
{
self.addr = addr.unescape_and_decode_value(reader).ok();
}
} else if tag == "placemark" {
self.tag = KmlTag::PLACEMARK;

View File

@@ -210,7 +210,7 @@ impl LoginParam {
let key = format!("{}smtp_certificate_checks", prefix);
let smtp_certificate_checks =
if let Some(certificate_checks) = sql.get_raw_config_int(key).await? {
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap()
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap_or_default()
} else {
Default::default()
};

View File

@@ -5,7 +5,7 @@ use std::future::Future;
use std::io::Cursor;
use std::pin::Pin;
use anyhow::{bail, Result};
use anyhow::{bail, Context as _, Result};
use deltachat_derive::{FromSql, ToSql};
use lettre_email::mime::{self, Mime};
use mailparse::{addrparse_header, DispositionType, MailHeader, MailHeaderMap, SingleInfo};
@@ -715,7 +715,7 @@ impl MimeMessage {
if raw.is_empty() {
return Ok(false);
}
let mail = mailparse::parse_mail(&raw).unwrap();
let mail = mailparse::parse_mail(&raw).context("failed to parse mail")?;
self.parse_mime_recursive(context, &mail, is_related).await
}

View File

@@ -146,8 +146,10 @@ pub async fn dc_get_oauth2_access_token(
value = &redirect_uri;
} else if value == "$CODE" {
value = code;
} else if value == "$REFRESH_TOKEN" && refresh_token.is_some() {
value = refresh_token.as_ref().unwrap();
} else if value == "$REFRESH_TOKEN" {
if let Some(refresh_token) = refresh_token.as_ref() {
value = refresh_token;
}
}
post_param.insert(key, value);
@@ -162,16 +164,18 @@ pub async fn dc_get_oauth2_access_token(
let client = surf::Client::new();
let parsed: Result<Response, _> = client.recv_json(req).await;
if parsed.is_err() {
warn!(
context,
"Failed to parse OAuth2 JSON response from {}: error: {:?}", token_url, parsed
);
return Ok(None);
}
let response = match parsed {
Ok(response) => response,
Err(err) => {
warn!(
context,
"Failed to parse OAuth2 JSON response from {}: error: {}", token_url, err
);
return Ok(None);
}
};
// update refresh_token if given, typically on the first round, but we update it later as well.
let response = parsed.unwrap();
if let Some(ref token) = response.refresh_token {
context
.sql
@@ -286,12 +290,13 @@ impl Oauth2 {
// }
let response: Result<HashMap<String, serde_json::Value>, surf::Error> =
surf::get(userinfo_url).recv_json().await;
if response.is_err() {
warn!(context, "Error getting userinfo: {:?}", response);
return None;
}
let parsed = response.unwrap();
let parsed = match response {
Ok(parsed) => parsed,
Err(err) => {
warn!(context, "Error getting userinfo: {}", err);
return None;
}
};
// CAVE: serde_json::Value.as_str() removes the quotes of json-strings
// but serde_json::Value.to_string() does not!
if let Some(addr) = parsed.get("email") {

View File

@@ -4,7 +4,7 @@ use std::collections::{BTreeMap, HashSet};
use std::io;
use std::io::Cursor;
use anyhow::{bail, ensure, format_err, Context as _, Result};
use anyhow::{bail, format_err, Context as _, Result};
use pgp::armor::BlockType;
use pgp::composed::{
Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey,
@@ -98,9 +98,7 @@ pub fn split_armored_data(buf: &[u8]) -> Result<(BlockType, BTreeMap<String, Str
let mut bytes = Vec::with_capacity(buf.len());
dearmor.read_to_end(&mut bytes)?;
ensure!(dearmor.typ.is_some(), "Failed to parse type");
let typ = dearmor.typ.unwrap();
let typ = dearmor.typ.context("failed to parse type")?;
// normalize headers
let headers = dearmor
@@ -183,10 +181,12 @@ pub(crate) fn create_keypair(
.can_encrypt(true)
.passphrase(None)
.build()
.unwrap(),
.map_err(|err| {
PgpKeygenError::new("failed to build subkey parameters", format_err!("{}", err))
})?,
)
.build()
.map_err(|err| PgpKeygenError::new("invalid key params", format_err!(err)))?;
.map_err(|err| PgpKeygenError::new("invalid key params", format_err!("{}", err)))?;
let key = key_params
.generate()
.map_err(|err| PgpKeygenError::new("invalid params", err))?;

View File

@@ -245,8 +245,11 @@ async fn fingerprint_equals_sender(
};
if let Some(peerstate) = peerstate {
if peerstate.public_key_fingerprint.is_some()
&& fingerprint == peerstate.public_key_fingerprint.as_ref().unwrap()
if peerstate
.public_key_fingerprint
.as_ref()
.filter(|&fp| fp == fingerprint)
.is_some()
{
return Ok(true);
}

View File

@@ -702,13 +702,15 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
Ok(mut dir_handle) => {
/* avoid deletion of files that are just created to build a message object */
let diff = std::time::Duration::from_secs(60 * 60);
let keep_files_newer_than = std::time::SystemTime::now().checked_sub(diff).unwrap();
let keep_files_newer_than = std::time::SystemTime::now()
.checked_sub(diff)
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
while let Some(entry) = dir_handle.next().await {
if entry.is_err() {
break;
}
let entry = entry.unwrap();
let entry = match entry {
Ok(entry) => entry,
Err(_) => break,
};
let name_f = entry.file_name();
let name_s = name_f.to_string_lossy();
@@ -724,11 +726,13 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
if let Ok(stats) = async_std::fs::metadata(entry.path()).await {
let recently_created =
stats.created().is_ok() && stats.created().unwrap() > keep_files_newer_than;
let recently_modified = stats.modified().is_ok()
&& stats.modified().unwrap() > keep_files_newer_than;
let recently_accessed = stats.accessed().is_ok()
&& stats.accessed().unwrap() > keep_files_newer_than;
stats.created().map_or(false, |t| t > keep_files_newer_than);
let recently_modified = stats
.modified()
.map_or(false, |t| t > keep_files_newer_than);
let recently_accessed = stats
.accessed()
.map_or(false, |t| t > keep_files_newer_than);
if recently_created || recently_modified || recently_accessed {
info!(