Debloat the binary by using less AsRef arguments

Using `impl AsRef<str>` as the argument instead of `&str` makes it
possible to call the function with `&str`, `String` and other types
that implement `AsRef` trait.

The cost of it is that compiled binary contains mulitple versions of
the same function, one for each variant of types. If function contains
multiple generic `impl AsRef` arguments, the number of versions possibly
compiled into binary grows exponentially with the number of arguments.

Simple way to avoid it is to call `.as_ref()` on the caller side to
convert the argument to `&str`. In most cases even adding a `&` and
relying on `Deref` coercion is sufficient.

This patch changes many functions that accepted `impl AsRef<str>` and
`impl AsRef<Path>` to accept `&str` and `&Path` instead.

In some places `.clone()` calls are removed. Calling `.clone()` on
`String` and passing `String` to a function accepting `impl
AsRef<str>` is completely unnecessary as `&str` reference could be
passed instead. There is no clippy warning against it yet, but
changing argument type to `&str` allowed to find these cases.

The result of debloating is not impressive, several hundred kilobytes
are saved, which is about 3% of the `.so` binary, but the code is
cleaner too.
This commit is contained in:
link2xt
2021-05-08 16:52:29 +03:00
parent 03f0659454
commit adac903818
29 changed files with 244 additions and 308 deletions

View File

@@ -271,7 +271,7 @@ pub unsafe extern "C" fn dc_get_oauth2_url(
let redirect = to_string_lossy(redirect);
block_on(async move {
match oauth2::dc_get_oauth2_url(&ctx, addr, redirect).await {
match oauth2::dc_get_oauth2_url(&ctx, &addr, &redirect).await {
Some(res) => res.strdup(),
None => ptr::null_mut(),
}
@@ -1188,7 +1188,7 @@ pub unsafe extern "C" fn dc_search_msgs(
block_on(async move {
let arr = dc_array_t::from(
ctx.search_msgs(chat_id, to_string_lossy(query))
ctx.search_msgs(chat_id, &to_string_lossy(query))
.await
.unwrap_or_log_default(ctx, "Failed search_msgs")
.iter()
@@ -1237,7 +1237,7 @@ pub unsafe extern "C" fn dc_create_group_chat(
};
block_on(async move {
chat::create_group_chat(&ctx, protect, to_string_lossy(name))
chat::create_group_chat(&ctx, protect, &to_string_lossy(name))
.await
.log_err(ctx, "Failed to create group chat")
.map(|id| id.to_u32())
@@ -1312,7 +1312,7 @@ pub unsafe extern "C" fn dc_set_chat_name(
let ctx = &*context;
block_on(async move {
chat::set_chat_name(&ctx, ChatId::new(chat_id), to_string_lossy(name))
chat::set_chat_name(&ctx, ChatId::new(chat_id), &to_string_lossy(name))
.await
.map(|_| 1)
.unwrap_or_log_default(&ctx, "Failed to set chat name")
@@ -1642,7 +1642,7 @@ pub unsafe extern "C" fn dc_create_contact(
let name = to_string_lossy(name);
block_on(async move {
Contact::create(&ctx, name, to_string_lossy(addr))
Contact::create(&ctx, &name, &to_string_lossy(addr))
.await
.unwrap_or(0)
})
@@ -1660,7 +1660,7 @@ pub unsafe extern "C" fn dc_add_address_book(
let ctx = &*context;
block_on(async move {
match Contact::add_address_book(&ctx, to_string_lossy(addr_book)).await {
match Contact::add_address_book(&ctx, &to_string_lossy(addr_book)).await {
Ok(cnt) => cnt as libc::c_int,
Err(_) => 0,
}
@@ -1827,7 +1827,7 @@ pub unsafe extern "C" fn dc_imex(
if let Some(param1) = to_opt_string_lossy(param1) {
spawn(async move {
imex::imex(&ctx, what, &param1)
imex::imex(&ctx, what, param1.as_ref())
.await
.log_err(ctx, "IMEX failed")
});
@@ -1848,7 +1848,7 @@ pub unsafe extern "C" fn dc_imex_has_backup(
let ctx = &*context;
block_on(async move {
match imex::has_backup(&ctx, to_string_lossy(dir)).await {
match imex::has_backup(&ctx, to_string_lossy(dir).as_ref()).await {
Ok(res) => res.strdup(),
Err(err) => {
// do not bubble up error to the user,
@@ -1929,7 +1929,7 @@ pub unsafe extern "C" fn dc_check_qr(
let ctx = &*context;
block_on(async move {
let lot = qr::check_qr(&ctx, to_string_lossy(qr)).await;
let lot = qr::check_qr(&ctx, &to_string_lossy(qr)).await;
Box::into_raw(Box::new(lot))
})
}

View File

@@ -457,20 +457,20 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
}
"export-backup" => {
let dir = dirs::home_dir().unwrap_or_default();
imex(&context, ImexMode::ExportBackup, &dir).await?;
imex(&context, ImexMode::ExportBackup, dir.as_ref()).await?;
println!("Exported to {}.", dir.to_string_lossy());
}
"import-backup" => {
ensure!(!arg1.is_empty(), "Argument <backup-file> missing.");
imex(&context, ImexMode::ImportBackup, arg1).await?;
imex(&context, ImexMode::ImportBackup, arg1.as_ref()).await?;
}
"export-keys" => {
let dir = dirs::home_dir().unwrap_or_default();
imex(&context, ImexMode::ExportSelfKeys, &dir).await?;
imex(&context, ImexMode::ExportSelfKeys, dir.as_ref()).await?;
println!("Exported to {}.", dir.to_string_lossy());
}
"import-keys" => {
imex(&context, ImexMode::ImportSelfKeys, arg1).await?;
imex(&context, ImexMode::ImportSelfKeys, arg1.as_ref()).await?;
}
"export-setup" => {
let setup_code = create_setup_code(&context);
@@ -1086,7 +1086,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
if !arg2.is_empty() {
let book = format!("{}\n{}", arg1, arg2);
Contact::add_address_book(&context, book).await?;
Contact::add_address_book(&context, &book).await?;
} else {
Contact::create(&context, "", arg1).await?;
}

View File

@@ -58,11 +58,11 @@ impl<'a> BlobObject<'a> {
/// underlying error.
pub async fn create(
context: &'a Context,
suggested_name: impl AsRef<str>,
suggested_name: &str,
data: &[u8],
) -> std::result::Result<BlobObject<'a>, BlobError> {
let blobdir = context.get_blobdir();
let (stem, ext) = BlobObject::sanitise_name(suggested_name.as_ref());
let (stem, ext) = BlobObject::sanitise_name(suggested_name);
let (name, mut file) = BlobObject::create_new_file(blobdir, &stem, &ext).await?;
file.write_all(data)
.await
@@ -137,18 +137,17 @@ impl<'a> BlobObject<'a> {
/// copied.
pub async fn create_and_copy(
context: &'a Context,
src: impl AsRef<Path>,
src: &Path,
) -> std::result::Result<BlobObject<'a>, BlobError> {
let mut src_file =
fs::File::open(src.as_ref())
.await
.map_err(|err| BlobError::CopyFailure {
blobdir: context.get_blobdir().to_path_buf(),
blobname: String::from(""),
src: src.as_ref().to_path_buf(),
cause: err,
})?;
let (stem, ext) = BlobObject::sanitise_name(&src.as_ref().to_string_lossy());
let mut src_file = fs::File::open(src)
.await
.map_err(|err| BlobError::CopyFailure {
blobdir: context.get_blobdir().to_path_buf(),
blobname: String::from(""),
src: src.to_path_buf(),
cause: err,
})?;
let (stem, ext) = BlobObject::sanitise_name(&src.to_string_lossy());
let (name, mut dst_file) =
BlobObject::create_new_file(context.get_blobdir(), &stem, &ext).await?;
let name_for_err = name.clone();
@@ -161,7 +160,7 @@ impl<'a> BlobObject<'a> {
return Err(BlobError::CopyFailure {
blobdir: context.get_blobdir().to_path_buf(),
blobname: name_for_err,
src: src.as_ref().to_path_buf(),
src: src.to_path_buf(),
cause: err,
});
}
@@ -195,16 +194,13 @@ impl<'a> BlobObject<'a> {
/// the [BlobObject::from_path] methods. See those for possible
/// errors.
pub async fn new_from_path(
context: &Context,
src: impl AsRef<Path>,
) -> std::result::Result<BlobObject<'_>, BlobError> {
if src.as_ref().starts_with(context.get_blobdir()) {
context: &'a Context,
src: &Path,
) -> std::result::Result<BlobObject<'a>, BlobError> {
if src.starts_with(context.get_blobdir()) {
BlobObject::from_path(context, src)
} else if src.as_ref().starts_with("$BLOBDIR/") {
BlobObject::from_name(
context,
src.as_ref().to_str().unwrap_or_default().to_string(),
)
} else if src.starts_with("$BLOBDIR/") {
BlobObject::from_name(context, src.to_str().unwrap_or_default().to_string())
} else {
BlobObject::create_and_copy(context, src).await
}
@@ -225,23 +221,22 @@ impl<'a> BlobObject<'a> {
/// [BlobError::WrongName] is used if the file name does not
/// remain identical after sanitisation.
pub fn from_path(
context: &Context,
path: impl AsRef<Path>,
) -> std::result::Result<BlobObject, BlobError> {
let rel_path = path
.as_ref()
.strip_prefix(context.get_blobdir())
.map_err(|_| BlobError::WrongBlobdir {
blobdir: context.get_blobdir().to_path_buf(),
src: path.as_ref().to_path_buf(),
})?;
if !BlobObject::is_acceptible_blob_name(&rel_path) {
context: &'a Context,
path: &Path,
) -> std::result::Result<BlobObject<'a>, BlobError> {
let rel_path =
path.strip_prefix(context.get_blobdir())
.map_err(|_| BlobError::WrongBlobdir {
blobdir: context.get_blobdir().to_path_buf(),
src: path.to_path_buf(),
})?;
if !BlobObject::is_acceptible_blob_name(rel_path) {
return Err(BlobError::WrongName {
blobname: path.as_ref().to_path_buf(),
blobname: path.to_path_buf(),
});
}
let name = rel_path.to_str().ok_or_else(|| BlobError::WrongName {
blobname: path.as_ref().to_path_buf(),
blobname: path.to_path_buf(),
})?;
BlobObject::from_name(context, name.to_string())
}
@@ -724,13 +719,15 @@ mod tests {
let t = TestContext::new().await;
let src = t.dir.path().join("src");
fs::write(&src, b"boo").await.unwrap();
let blob = BlobObject::create_and_copy(&t, &src).await.unwrap();
let blob = BlobObject::create_and_copy(&t, src.as_ref()).await.unwrap();
assert_eq!(blob.as_name(), "$BLOBDIR/src");
let data = fs::read(blob.to_abs_path()).await.unwrap();
assert_eq!(data, b"boo");
let whoops = t.dir.path().join("whoops");
assert!(BlobObject::create_and_copy(&t, &whoops).await.is_err());
assert!(BlobObject::create_and_copy(&t, whoops.as_ref())
.await
.is_err());
let whoops = t.get_blobdir().join("whoops");
assert!(!whoops.exists().await);
}
@@ -741,7 +738,9 @@ mod tests {
let src_ext = t.dir.path().join("external");
fs::write(&src_ext, b"boo").await.unwrap();
let blob = BlobObject::new_from_path(&t, &src_ext).await.unwrap();
let blob = BlobObject::new_from_path(&t, src_ext.as_ref())
.await
.unwrap();
assert_eq!(blob.as_name(), "$BLOBDIR/external");
let data = fs::read(blob.to_abs_path()).await.unwrap();
assert_eq!(data, b"boo");
@@ -758,7 +757,9 @@ mod tests {
let t = TestContext::new().await;
let src_ext = t.dir.path().join("autocrypt-setup-message-4137848473.html");
fs::write(&src_ext, b"boo").await.unwrap();
let blob = BlobObject::new_from_path(&t, &src_ext).await.unwrap();
let blob = BlobObject::new_from_path(&t, src_ext.as_ref())
.await
.unwrap();
assert_eq!(
blob.as_name(),
"$BLOBDIR/autocrypt-setup-message-4137848473.html"

View File

@@ -1367,7 +1367,7 @@ pub(crate) async fn update_saved_messages_icon(context: &Context) -> Result<()>
// if there is no saved-messages chat, there is nothing to update. this is no error.
if let Some(chat_id) = ChatId::lookup_by_contact(context, DC_CONTACT_ID_SELF).await? {
let icon = include_bytes!("../assets/icon-saved-messages.png");
let blob = BlobObject::create(context, "icon-saved-messages.png".to_string(), icon).await?;
let blob = BlobObject::create(context, "icon-saved-messages.png", icon).await?;
let icon = blob.as_name().to_string();
let mut chat = Chat::load_from_db(context, chat_id).await?;
@@ -1381,7 +1381,7 @@ pub(crate) async fn update_device_icon(context: &Context) -> Result<()> {
// if there is no device-chat, there is nothing to update. this is no error.
if let Some(chat_id) = ChatId::lookup_by_contact(context, DC_CONTACT_ID_DEVICE).await? {
let icon = include_bytes!("../assets/icon-device.png");
let blob = BlobObject::create(context, "icon-device.png".to_string(), icon).await?;
let blob = BlobObject::create(context, "icon-device.png", icon).await?;
let icon = blob.as_name().to_string();
let mut chat = Chat::load_from_db(context, chat_id).await?;
@@ -2174,7 +2174,7 @@ pub async fn get_chat_contacts(context: &Context, chat_id: ChatId) -> Result<Vec
pub async fn create_group_chat(
context: &Context,
protect: ProtectionStatus,
chat_name: impl AsRef<str>,
chat_name: &str,
) -> Result<ChatId> {
let chat_name = improve_single_line_input(chat_name);
ensure!(!chat_name.is_empty(), "Invalid chat name");
@@ -2531,7 +2531,7 @@ pub async fn remove_contact_from_chat(
if chat.is_promoted() {
msg.viewtype = Viewtype::Text;
if contact.id == DC_CONTACT_ID_SELF {
set_group_explicitly_left(context, chat.grpid).await?;
set_group_explicitly_left(context, &chat.grpid).await?;
msg.text = Some(
stock_str::msg_group_left(context, DC_CONTACT_ID_SELF as u32).await,
);
@@ -2573,13 +2573,13 @@ pub async fn remove_contact_from_chat(
Ok(())
}
async fn set_group_explicitly_left(context: &Context, grpid: impl AsRef<str>) -> Result<()> {
if !is_group_explicitly_left(context, grpid.as_ref()).await? {
async fn set_group_explicitly_left(context: &Context, grpid: &str) -> Result<()> {
if !is_group_explicitly_left(context, grpid).await? {
context
.sql
.execute(
"INSERT INTO leftgrps (grpid) VALUES(?);",
paramsv![grpid.as_ref().to_string()],
paramsv![grpid.to_string()],
)
.await?;
}
@@ -2601,11 +2601,7 @@ pub(crate) async fn is_group_explicitly_left(
Ok(exists)
}
pub async fn set_chat_name(
context: &Context,
chat_id: ChatId,
new_name: impl AsRef<str>,
) -> Result<()> {
pub async fn set_chat_name(context: &Context, chat_id: ChatId, new_name: &str) -> Result<()> {
let new_name = improve_single_line_input(new_name);
/* the function only sets the names of group chats; normal chats get their names from the contacts */
let mut success = false;

View File

@@ -8,8 +8,8 @@ use hsluv::hsluv_to_rgb;
use sha1::{Digest, Sha1};
/// Converts an identifier to Hue angle.
fn str_to_angle(s: impl AsRef<str>) -> f64 {
let bytes = s.as_ref().as_bytes();
fn str_to_angle(s: &str) -> f64 {
let bytes = s.as_bytes();
let result = Sha1::digest(bytes);
let checksum: u16 = result.get(0).map_or(0, |&x| u16::from(x))
+ 256 * result.get(1).map_or(0, |&x| u16::from(x));
@@ -31,7 +31,7 @@ fn rgb_to_u32((r, g, b): (f64, f64, f64)) -> u32 {
///
/// Saturation is set to maximum (100.0) to make colors distinguishable, and lightness is set to
/// half (50.0) to make colors suitable both for light and dark theme.
pub(crate) fn str_to_color(s: impl AsRef<str>) -> u32 {
pub(crate) fn str_to_color(s: &str) -> u32 {
rgb_to_u32(hsluv_to_rgb((str_to_angle(s), 100.0, 50.0)))
}

View File

@@ -249,7 +249,7 @@ impl Context {
.await?;
match value {
Some(value) => {
let mut blob = BlobObject::new_from_path(self, value).await?;
let mut blob = BlobObject::new_from_path(self, value.as_ref()).await?;
blob.recode_to_avatar_size(self).await?;
self.sql.set_raw_config(key, Some(blob.as_name())).await?;
Ok(())

View File

@@ -449,7 +449,7 @@ async fn get_autoconfig(
) -> Option<Vec<ServerParams>> {
if let Ok(res) = moz_autoconfigure(
ctx,
format!(
&format!(
"https://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
param_domain, param_addr_urlencoded
),
@@ -464,7 +464,7 @@ async fn get_autoconfig(
if let Ok(res) = moz_autoconfigure(
ctx,
// the doc does not mention `emailaddress=`, however, Thunderbird adds it, see https://releases.mozilla.org/pub/thunderbird/ , which makes some sense
format!(
&format!(
"https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}",
&param_domain, &param_addr_urlencoded
),
@@ -503,7 +503,7 @@ async fn get_autoconfig(
// always SSL for Thunderbird's database
if let Ok(res) = moz_autoconfigure(
ctx,
format!("https://autoconfig.thunderbird.net/v1.1/{}", &param_domain),
&format!("https://autoconfig.thunderbird.net/v1.1/{}", &param_domain),
param,
)
.await

View File

@@ -251,10 +251,10 @@ fn parse_serverparams(in_emailaddr: &str, xml_raw: &str) -> Result<Vec<ServerPar
pub(crate) async fn moz_autoconfigure(
context: &Context,
url: impl AsRef<str>,
url: &str,
param_in: &LoginParam,
) -> Result<Vec<ServerParams>, Error> {
let xml_raw = read_url(context, url.as_ref()).await?;
let xml_raw = read_url(context, url).await?;
let res = parse_serverparams(&param_in.addr, &xml_raw);
if let Err(err) = &res {

View File

@@ -254,21 +254,14 @@ impl Contact {
/// a bunch of addresses.
///
/// May result in a `#DC_EVENT_CONTACTS_CHANGED` event.
pub async fn create(
context: &Context,
name: impl AsRef<str>,
addr: impl AsRef<str>,
) -> Result<u32> {
pub async fn create(context: &Context, name: &str, addr: &str) -> Result<u32> {
let name = improve_single_line_input(name);
ensure!(
!addr.as_ref().is_empty(),
"Cannot create contact with empty address"
);
ensure!(!addr.is_empty(), "Cannot create contact with empty address");
let (name, addr) = sanitize_name_and_addr(name, addr);
let (name, addr) = sanitize_name_and_addr(&name, addr);
let (contact_id, sth_modified) =
Contact::add_or_lookup(context, name, addr, Origin::ManuallyCreated).await?;
Contact::add_or_lookup(context, &name, &addr, Origin::ManuallyCreated).await?;
let blocked = Contact::is_blocked_load(context, contact_id).await;
match sth_modified {
Modifier::None => {}
@@ -365,19 +358,16 @@ impl Contact {
/// Returns the contact_id and a `Modifier` value indicating if a modification occured.
pub(crate) async fn add_or_lookup(
context: &Context,
name: impl AsRef<str>,
addr: impl AsRef<str>,
name: &str,
addr: &str,
mut origin: Origin,
) -> Result<(u32, Modifier)> {
let mut sth_modified = Modifier::None;
ensure!(
!addr.as_ref().is_empty(),
"Can not add_or_lookup empty address"
);
ensure!(!addr.is_empty(), "Can not add_or_lookup empty address");
ensure!(origin != Origin::Unknown, "Missing valid origin");
let addr = addr_normalize(addr.as_ref()).to_string();
let addr = addr_normalize(addr).to_string();
let addr_self = context
.get_config(Config::ConfiguredAddr)
.await?
@@ -392,16 +382,12 @@ impl Contact {
context,
"Bad address \"{}\" for contact \"{}\".",
addr,
if !name.as_ref().is_empty() {
name.as_ref()
} else {
"<unset>"
},
if !name.is_empty() { name } else { "<unset>" },
);
bail!("Bad address supplied: {:?}", addr);
}
let mut name = name.as_ref();
let mut name = name;
#[allow(clippy::collapsible_if)]
if origin <= Origin::OutgoingTo {
// The user may accidentally have written to a "noreply" address with another MUA:
@@ -581,13 +567,13 @@ impl Contact {
/// The `addr_book` is a multiline string in the format `Name one\nAddress one\nName two\nAddress two`.
///
/// Returns the number of modified contacts.
pub async fn add_address_book(context: &Context, addr_book: impl AsRef<str>) -> Result<usize> {
pub async fn add_address_book(context: &Context, addr_book: &str) -> Result<usize> {
let mut modify_cnt = 0;
for (name, addr) in split_address_book(addr_book.as_ref()).into_iter() {
for (name, addr) in split_address_book(addr_book).into_iter() {
let (name, addr) = sanitize_name_and_addr(name, addr);
let name = normalize_name(name);
match Contact::add_or_lookup(context, name, &addr, Origin::AddressBook).await {
match Contact::add_or_lookup(context, &name, &addr, Origin::AddressBook).await {
Err(err) => {
warn!(
context,
@@ -633,13 +619,7 @@ impl Contact {
let flag_add_self = (listflags & DC_GCL_ADD_SELF) != 0;
if flag_verified_only || query.is_some() {
let s3str_like_cmd = format!(
"%{}%",
query
.as_ref()
.map(|s| s.as_ref().to_string())
.unwrap_or_default()
);
let s3str_like_cmd = format!("%{}%", query.as_ref().map(|s| s.as_ref()).unwrap_or(""));
context
.sql
.query_map(
@@ -849,14 +829,14 @@ impl Contact {
cat_fingerprint(&mut ret, &loginparam.addr, &fingerprint_self, "");
cat_fingerprint(
&mut ret,
peerstate.addr.clone(),
&peerstate.addr,
&fingerprint_other_verified,
&fingerprint_other_unverified,
);
} else {
cat_fingerprint(
&mut ret,
peerstate.addr.clone(),
&peerstate.addr,
&fingerprint_other_verified,
&fingerprint_other_unverified,
);
@@ -1098,18 +1078,14 @@ impl Contact {
VerifiedStatus::Unverified
}
pub async fn addr_equals_contact(
context: &Context,
addr: impl AsRef<str>,
contact_id: u32,
) -> bool {
if addr.as_ref().is_empty() {
pub async fn addr_equals_contact(context: &Context, addr: &str, contact_id: u32) -> bool {
if addr.is_empty() {
return false;
}
if let Ok(contact) = Contact::load_from_db(context, contact_id).await {
if !contact.addr.is_empty() {
let normalized_addr = addr_normalize(addr.as_ref());
let normalized_addr = addr_normalize(addr);
if contact.addr == normalized_addr {
return true;
}
@@ -1178,23 +1154,23 @@ pub fn addr_normalize(addr: &str) -> &str {
}
}
fn sanitize_name_and_addr(name: impl AsRef<str>, addr: impl AsRef<str>) -> (String, String) {
fn sanitize_name_and_addr(name: &str, addr: &str) -> (String, String) {
static ADDR_WITH_NAME_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new("(.*)<(.*)>").unwrap());
if let Some(captures) = ADDR_WITH_NAME_REGEX.captures(addr.as_ref()) {
(
if name.as_ref().is_empty() {
if name.is_empty() {
captures
.get(1)
.map_or("".to_string(), |m| normalize_name(m.as_str()))
} else {
name.as_ref().to_string()
name.to_string()
},
captures
.get(2)
.map_or("".to_string(), |m| m.as_str().to_string()),
)
} else {
(name.as_ref().to_string(), addr.as_ref().to_string())
(name.to_string(), addr.to_string())
}
}
@@ -1351,13 +1327,13 @@ pub fn normalize_name(full_name: impl AsRef<str>) -> String {
fn cat_fingerprint(
ret: &mut String,
addr: impl AsRef<str>,
addr: &str,
fingerprint_verified: impl AsRef<str>,
fingerprint_unverified: impl AsRef<str>,
) {
*ret += &format!(
"\n\n{}:\n{}",
addr.as_ref(),
addr,
if !fingerprint_verified.as_ref().is_empty() {
fingerprint_verified.as_ref()
} else {
@@ -1370,7 +1346,7 @@ fn cat_fingerprint(
{
*ret += &format!(
"\n\n{} (alternative):\n{}",
addr.as_ref(),
addr,
fingerprint_unverified.as_ref()
);
}

View File

@@ -463,12 +463,8 @@ impl Context {
///
/// If `chat_id` is provided this searches only for messages in this chat, if `chat_id`
/// is `None` this searches messages from all chats.
pub async fn search_msgs(
&self,
chat_id: Option<ChatId>,
query: impl AsRef<str>,
) -> Result<Vec<MsgId>> {
let real_query = query.as_ref().trim();
pub async fn search_msgs(&self, chat_id: Option<ChatId>, query: &str) -> Result<Vec<MsgId>> {
let real_query = query.trim();
if real_query.is_empty() {
return Ok(Vec::new());
}
@@ -535,28 +531,27 @@ impl Context {
Ok(list)
}
pub async fn is_inbox(&self, folder_name: impl AsRef<str>) -> Result<bool> {
pub async fn is_inbox(&self, folder_name: &str) -> Result<bool> {
let inbox = self.get_config(Config::ConfiguredInboxFolder).await?;
Ok(inbox == Some(folder_name.as_ref().to_string()))
Ok(inbox.as_deref() == Some(folder_name))
}
pub async fn is_sentbox(&self, folder_name: impl AsRef<str>) -> Result<bool> {
pub async fn is_sentbox(&self, folder_name: &str) -> Result<bool> {
let sentbox = self.get_config(Config::ConfiguredSentboxFolder).await?;
Ok(sentbox == Some(folder_name.as_ref().to_string()))
Ok(sentbox.as_deref() == Some(folder_name))
}
pub async fn is_mvbox(&self, folder_name: impl AsRef<str>) -> Result<bool> {
pub async fn is_mvbox(&self, folder_name: &str) -> Result<bool> {
let mvbox = self.get_config(Config::ConfiguredMvboxFolder).await?;
Ok(mvbox == Some(folder_name.as_ref().to_string()))
Ok(mvbox.as_deref() == Some(folder_name))
}
pub async fn is_spam_folder(&self, folder_name: impl AsRef<str>) -> Result<bool> {
let is_spam = self.get_config(Config::ConfiguredSpamFolder).await?
== Some(folder_name.as_ref().to_string());
pub async fn is_spam_folder(&self, folder_name: &str) -> Result<bool> {
let spam = self.get_config(Config::ConfiguredSpamFolder).await?;
Ok(is_spam)
Ok(spam.as_deref() == Some(folder_name))
}
pub fn derive_blobdir(dbfile: &PathBuf) -> PathBuf {

View File

@@ -51,7 +51,7 @@ enum CreateEvent {
pub async fn dc_receive_imf(
context: &Context,
imf_raw: &[u8],
server_folder: impl AsRef<str>,
server_folder: &str,
server_uid: u32,
seen: bool,
) -> Result<()> {
@@ -61,17 +61,14 @@ pub async fn dc_receive_imf(
pub(crate) async fn dc_receive_imf_inner(
context: &Context,
imf_raw: &[u8],
server_folder: impl AsRef<str>,
server_folder: &str,
server_uid: u32,
seen: bool,
fetching_existing_messages: bool,
) -> Result<()> {
info!(
context,
"Receiving message {}/{}, seen={}...",
server_folder.as_ref(),
server_uid,
seen
"Receiving message {}/{}, seen={}...", server_folder, server_uid, seen
);
if std::env::var(crate::DCC_MIME_DEBUG).unwrap_or_default() == "2" {
@@ -176,7 +173,7 @@ pub(crate) async fn dc_receive_imf_inner(
imf_raw,
incoming,
incoming_origin,
server_folder.as_ref(),
server_folder,
server_uid,
&to_ids,
&rfc724_mid,
@@ -366,7 +363,7 @@ async fn add_parts(
imf_raw: &[u8],
incoming: bool,
incoming_origin: Origin,
server_folder: impl AsRef<str>,
server_folder: &str,
server_uid: u32,
to_ids: &ContactIds,
rfc724_mid: &str,
@@ -394,9 +391,8 @@ async fn add_parts(
if let Some((old_server_folder, old_server_uid, _)) =
message::rfc724_mid_exists(context, rfc724_mid).await?
{
if old_server_folder != server_folder.as_ref() || old_server_uid != server_uid {
message::update_server_uid(context, rfc724_mid, server_folder.as_ref(), server_uid)
.await;
if old_server_folder != server_folder || old_server_uid != server_uid {
message::update_server_uid(context, rfc724_mid, server_folder, server_uid).await;
}
warn!(context, "Message already in DB");
@@ -655,7 +651,7 @@ async fn add_parts(
let is_spam = (chat_id_blocked == Blocked::Deaddrop)
&& !incoming_origin.is_known()
&& (is_dc_message == MessengerMessage::No)
&& context.is_spam_folder(&server_folder).await?;
&& context.is_spam_folder(server_folder).await?;
if is_spam {
*chat_id = DC_CHAT_ID_TRASH;
info!(context, "Message is probably spam (TRASH)");
@@ -689,7 +685,7 @@ async fn add_parts(
}
}
if !context.is_sentbox(&server_folder).await?
if !context.is_sentbox(server_folder).await?
&& mime_parser.get(HeaderDef::Received).is_none()
{
// Most mailboxes have a "Drafts" folder where constantly new emails appear but we don't actually want to show them
@@ -920,7 +916,6 @@ async fn add_parts(
let subject = mime_parser.get_subject().unwrap_or_default();
let mut parts = std::mem::replace(&mut mime_parser.parts, Vec::new());
let server_folder = server_folder.as_ref().to_string();
let is_system_message = mime_parser.is_system_message;
// if indicated by the parser,
@@ -1855,8 +1850,8 @@ async fn create_adhoc_grp_id(context: &Context, member_ids: &[u32]) -> Result<St
}
#[allow(clippy::indexing_slicing)]
fn hex_hash(s: impl AsRef<str>) -> String {
let bytes = s.as_ref().as_bytes();
fn hex_hash(s: &str) -> String {
let bytes = s.as_bytes();
let result = Sha256::digest(bytes);
hex::encode(&result[..8])
}
@@ -2089,7 +2084,7 @@ async fn add_or_lookup_contact_by_addr(
let display_name_normalized = display_name.map(normalize_name).unwrap_or_default();
let (row_id, _modified) =
Contact::add_or_lookup(context, display_name_normalized, addr, origin).await?;
Contact::add_or_lookup(context, &display_name_normalized, addr, origin).await?;
ensure!(row_id > 0, "could not add contact: {:?}", addr);
Ok(row_id)

View File

@@ -641,9 +641,8 @@ impl rusqlite::types::ToSql for EmailAddress {
}
/// Makes sure that a user input that is not supposed to contain newlines does not contain newlines.
pub(crate) fn improve_single_line_input(input: impl AsRef<str>) -> String {
pub(crate) fn improve_single_line_input(input: &str) -> String {
input
.as_ref()
.replace("\n", " ")
.replace("\r", " ")
.trim()

View File

@@ -710,7 +710,7 @@ impl Imap {
}
let (largest_uid_processed, error_cnt) = self
.fetch_many_msgs(context, &folder, uids, fetch_existing_msgs)
.fetch_many_msgs(context, folder, uids, fetch_existing_msgs)
.await;
read_errors += error_cnt;
@@ -858,10 +858,10 @@ impl Imap {
/// Fetches a list of messages by server UID.
///
/// Returns the last uid fetch successfully and an error count.
async fn fetch_many_msgs<S: AsRef<str>>(
async fn fetch_many_msgs(
&mut self,
context: &Context,
folder: S,
folder: &str,
server_uids: Vec<u32>,
fetching_existing_messages: bool,
) -> (Option<u32>, usize) {
@@ -899,14 +899,14 @@ impl Imap {
context,
"Error on fetching messages #{} from folder \"{}\"; error={}.",
&set,
folder.as_ref(),
folder,
err
);
return (None, server_uids.len());
}
};
let folder = folder.as_ref().to_string();
let folder = folder.to_string();
while let Some(Ok(msg)) = msgs.next().await {
let server_uid = msg.uid.unwrap_or_default();
@@ -1129,7 +1129,7 @@ impl Imap {
return Some(ImapActionResult::RetryLater);
}
}
match self.select_folder(context, Some(&folder)).await {
match self.select_folder(context, Some(folder)).await {
Ok(_) => None,
Err(select_folder::Error::ConnectionLost) => {
warn!(context, "Lost imap connection");

View File

@@ -32,10 +32,10 @@ impl DerefMut for Client {
}
impl Client {
pub async fn login<U: AsRef<str>, P: AsRef<str>>(
pub async fn login(
self,
username: U,
password: P,
username: &str,
password: &str,
) -> std::result::Result<Session, (ImapError, Self)> {
let Client { inner, is_secure } = self;
let session = inner
@@ -53,10 +53,10 @@ impl Client {
Ok(Session { inner: session })
}
pub async fn authenticate<A: async_imap::Authenticator, S: AsRef<str>>(
pub async fn authenticate(
self,
auth_type: S,
authenticator: A,
auth_type: &str,
authenticator: impl async_imap::Authenticator,
) -> std::result::Result<Session, (ImapError, Self)> {
let Client { inner, is_secure } = self;
let session =
@@ -75,15 +75,14 @@ impl Client {
Ok(Session { inner: session })
}
pub async fn connect_secure<A: net::ToSocketAddrs, S: AsRef<str>>(
addr: A,
domain: S,
pub async fn connect_secure(
addr: impl net::ToSocketAddrs,
domain: &str,
strict_tls: bool,
) -> ImapResult<Self> {
let stream = TcpStream::connect(addr).await?;
let tls = dc_build_tls(strict_tls);
let tls_stream: Box<dyn SessionStream> =
Box::new(tls.connect(domain.as_ref(), stream).await?);
let tls_stream: Box<dyn SessionStream> = Box::new(tls.connect(domain, stream).await?);
let mut client = ImapClient::new(tls_stream);
let _greeting = client
@@ -97,7 +96,7 @@ impl Client {
})
}
pub async fn connect_insecure<A: net::ToSocketAddrs>(addr: A) -> ImapResult<Self> {
pub async fn connect_insecure(addr: impl net::ToSocketAddrs) -> ImapResult<Self> {
let stream: Box<dyn SessionStream> = Box::new(TcpStream::connect(addr).await?);
let mut client = ImapClient::new(stream);
@@ -112,7 +111,7 @@ impl Client {
})
}
pub async fn secure<S: AsRef<str>>(self, domain: S, strict_tls: bool) -> ImapResult<Client> {
pub async fn secure(self, domain: &str, strict_tls: bool) -> ImapResult<Client> {
if self.is_secure {
Ok(self)
} else {
@@ -121,7 +120,7 @@ impl Client {
inner.run_command_and_check_ok("STARTTLS", None).await?;
let stream = inner.into_inner();
let ssl_stream = tls.connect(domain.as_ref(), stream).await?;
let ssl_stream = tls.connect(domain, stream).await?;
let boxed: Box<dyn SessionStream> = Box::new(ssl_stream);
Ok(Client {

View File

@@ -27,7 +27,7 @@ impl Imap {
}
self.setup_handle(context).await?;
self.select_folder(context, watch_folder.clone()).await?;
self.select_folder(context, watch_folder.as_deref()).await?;
let timeout = Duration::from_secs(23 * 60);
let mut info = Default::default();

View File

@@ -62,10 +62,10 @@ impl Imap {
/// select a folder, possibly update uid_validity and, if needed,
/// expunge the folder to remove delete-marked messages.
/// Returns whether a new folder was selected.
pub(super) async fn select_folder<S: AsRef<str>>(
pub(super) async fn select_folder(
&mut self,
context: &Context,
folder: Option<S>,
folder: Option<&str>,
) -> Result<NewlySelected> {
if self.session.is_none() {
self.config.selected_folder = None;
@@ -76,9 +76,9 @@ impl Imap {
// 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(ref folder) = folder {
if let Some(folder) = folder {
if let Some(ref selected_folder) = self.config.selected_folder {
if folder.as_ref() == selected_folder {
if folder == selected_folder {
return Ok(NewlySelected::No);
}
}
@@ -88,7 +88,7 @@ impl Imap {
self.maybe_close_folder(context).await?;
// select new folder
if let Some(ref folder) = folder {
if let Some(folder) = folder {
if let Some(ref mut session) = &mut self.session {
let res = session.select(folder).await;
@@ -98,7 +98,7 @@ impl Imap {
match res {
Ok(mailbox) => {
self.config.selected_folder = Some(folder.as_ref().to_string());
self.config.selected_folder = Some(folder.to_string());
self.config.selected_mailbox = Some(mailbox);
Ok(NewlySelected::Yes)
}
@@ -108,7 +108,7 @@ impl Imap {
Err(Error::ConnectionLost)
}
Err(async_imap::error::Error::Validate(_)) => {
Err(Error::BadFolderName(folder.as_ref().to_string()))
Err(Error::BadFolderName(folder.to_string()))
}
Err(err) => {
self.config.selected_folder = None;

View File

@@ -78,7 +78,7 @@ pub enum ImexMode {
///
/// Only one import-/export-progress can run at the same time.
/// To cancel an import-/export-progress, drop the future returned by this function.
pub async fn imex(context: &Context, what: ImexMode, param1: impl AsRef<Path>) -> Result<()> {
pub async fn imex(context: &Context, what: ImexMode, param1: &Path) -> Result<()> {
let cancel = context.alloc_ongoing().await?;
let res = async {
@@ -123,8 +123,7 @@ async fn cleanup_aborted_imex(context: &Context, what: ImexMode) {
}
/// Returns the filename of the backup found (otherwise an error)
pub async fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<String> {
let dir_name = dir_name.as_ref();
pub async fn has_backup(context: &Context, dir_name: &Path) -> Result<String> {
let mut dir_iter = async_std::fs::read_dir(dir_name).await?;
let mut newest_backup_name = "".to_string();
let mut newest_backup_path: Option<PathBuf> = None;
@@ -154,8 +153,7 @@ pub async fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result
}
/// Returns the filename of the backup found (otherwise an error)
pub async fn has_backup_old(context: &Context, dir_name: impl AsRef<Path>) -> Result<String> {
let dir_name = dir_name.as_ref();
pub async fn has_backup_old(context: &Context, dir_name: &Path) -> Result<String> {
let mut dir_iter = async_std::fs::read_dir(dir_name).await?;
let mut newest_backup_time = 0;
let mut newest_backup_name = "".to_string();
@@ -450,8 +448,8 @@ pub fn normalize_setup_code(s: &str) -> String {
out
}
async fn imex_inner(context: &Context, what: ImexMode, path: impl AsRef<Path>) -> Result<()> {
info!(context, "Import/export dir: {}", path.as_ref().display());
async fn imex_inner(context: &Context, what: ImexMode, path: &Path) -> Result<()> {
info!(context, "Import/export dir: {}", path.display());
ensure!(context.sql.is_open().await, "Database not opened.");
context.emit_event(EventType::ImexProgress(10));
@@ -475,12 +473,8 @@ async fn imex_inner(context: &Context, what: ImexMode, path: impl AsRef<Path>) -
}
/// Import Backup
async fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Result<()> {
if backup_to_import
.as_ref()
.to_string_lossy()
.ends_with(".bak")
{
async fn import_backup(context: &Context, backup_to_import: &Path) -> Result<()> {
if backup_to_import.to_string_lossy().ends_with(".bak") {
// Backwards compability
return import_backup_old(context, backup_to_import).await;
}
@@ -488,7 +482,7 @@ async fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) ->
info!(
context,
"Import \"{}\" to \"{}\".",
backup_to_import.as_ref().display(),
backup_to_import.display(),
context.get_dbfile().display()
);
@@ -546,7 +540,7 @@ async fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) ->
context
.sql
.open(context, &context.get_dbfile(), false)
.open(context, context.get_dbfile(), false)
.await
.context("Could not re-open db")?;
@@ -555,11 +549,11 @@ async fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) ->
Ok(())
}
async fn import_backup_old(context: &Context, backup_to_import: impl AsRef<Path>) -> Result<()> {
async fn import_backup_old(context: &Context, backup_to_import: &Path) -> Result<()> {
info!(
context,
"Import \"{}\" to \"{}\".",
backup_to_import.as_ref().display(),
backup_to_import.display(),
context.get_dbfile().display()
);
@@ -579,14 +573,14 @@ async fn import_backup_old(context: &Context, backup_to_import: impl AsRef<Path>
);
ensure!(
dc_copy_file(context, backup_to_import.as_ref(), context.get_dbfile()).await,
dc_copy_file(context, backup_to_import, context.get_dbfile()).await,
"could not copy file"
);
/* error already logged */
/* re-open copied database file */
context
.sql
.open(context, &context.get_dbfile(), false)
.open(context, context.get_dbfile(), false)
.await
.context("Could not re-open db")?;
@@ -669,7 +663,7 @@ async fn import_backup_old(context: &Context, backup_to_import: impl AsRef<Path>
* Export backup
******************************************************************************/
#[allow(unused)]
async fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
async fn export_backup(context: &Context, dir: &Path) -> Result<()> {
// get a fine backup file name (the name includes the date so that multiple backup instances are possible)
let now = time();
let (temp_path, dest_path) = get_next_backup_path(dir, now).await?;
@@ -705,10 +699,7 @@ async fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
let res = export_backup_inner(context, &temp_path).await;
// we re-open the database after export is finished
context
.sql
.open(context, &context.get_dbfile(), false)
.await;
context.sql.open(context, context.get_dbfile(), false).await;
match &res {
Ok(_) => {
@@ -775,7 +766,7 @@ async fn export_backup_inner(context: &Context, temp_path: &PathBuf) -> Result<(
/*******************************************************************************
* Classic key import
******************************************************************************/
async fn import_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
async fn import_self_keys(context: &Context, dir: &Path) -> Result<()> {
/* hint: even if we switch to import Autocrypt Setup Files, we should leave the possibility to import
plain ASC keys, at least keys without a password, if we do not want to implement a password entry function.
Importing ASC keys is useful to use keys in Delta Chat used by any other non-Autocrypt-PGP implementation.
@@ -785,12 +776,12 @@ async fn import_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()
let mut set_default: bool;
let mut imported_cnt = 0;
let dir_name = dir.as_ref().to_string_lossy();
let dir_name = dir.to_string_lossy();
let mut dir_handle = async_std::fs::read_dir(&dir).await?;
while let Some(entry) = dir_handle.next().await {
let entry_fn = entry?.file_name();
let name_f = entry_fn.to_string_lossy();
let path_plus_name = dir.as_ref().join(&entry_fn);
let path_plus_name = dir.join(&entry_fn);
match dc_get_filesuffix_lc(&name_f) {
Some(suffix) => {
if suffix != "asc" {
@@ -833,7 +824,7 @@ async fn import_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()
Ok(())
}
async fn export_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
async fn export_self_keys(context: &Context, dir: &Path) -> Result<()> {
let mut export_errors = 0;
let keys = context
@@ -861,7 +852,7 @@ async fn export_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()
for (id, public_key, private_key, is_default) in keys {
let id = Some(id).filter(|_| is_default != 0);
if let Ok(key) = public_key {
if export_key_to_asc_file(context, &dir, id, &key)
if export_key_to_asc_file(context, dir, id, &key)
.await
.is_err()
{
@@ -871,7 +862,7 @@ async fn export_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()
export_errors += 1;
}
if let Ok(key) = private_key {
if export_key_to_asc_file(context, &dir, id, &key)
if export_key_to_asc_file(context, dir, id, &key)
.await
.is_err()
{
@@ -891,7 +882,7 @@ async fn export_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()
******************************************************************************/
async fn export_key_to_asc_file<T>(
context: &Context,
dir: impl AsRef<Path>,
dir: &Path,
id: Option<i64>,
key: &T,
) -> std::io::Result<()>
@@ -908,7 +899,7 @@ where
"unknown"
};
let id = id.map_or("default".into(), |i| i.to_string());
dir.as_ref().join(format!("{}-key-{}.asc", kind, &id))
dir.join(format!("{}-key-{}.asc", kind, &id))
};
info!(
context,
@@ -988,7 +979,7 @@ mod tests {
async fn test_export_public_key_to_asc_file() {
let context = TestContext::new().await;
let key = alice_keypair().public;
let blobdir = "$BLOBDIR";
let blobdir = Path::new("$BLOBDIR");
assert!(export_key_to_asc_file(&context.ctx, blobdir, None, &key)
.await
.is_ok());
@@ -1003,7 +994,7 @@ mod tests {
async fn test_export_private_key_to_asc_file() {
let context = TestContext::new().await;
let key = alice_keypair().secret;
let blobdir = "$BLOBDIR";
let blobdir = Path::new("$BLOBDIR");
assert!(export_key_to_asc_file(&context.ctx, blobdir, None, &key)
.await
.is_ok());
@@ -1018,7 +1009,7 @@ mod tests {
async fn test_export_and_import_key() {
let context = TestContext::new().await;
context.configure_alice().await;
let blobdir = context.ctx.get_blobdir().to_str().unwrap();
let blobdir = context.ctx.get_blobdir();
if let Err(err) = imex(&context.ctx, ImexMode::ExportSelfKeys, blobdir).await {
panic!("got error on export: {:?}", err);
}

View File

@@ -904,8 +904,8 @@ async fn add_all_recipients_as_contacts(context: &Context, imap: &mut Imap, fold
match Contact::add_or_lookup(
context,
display_name_normalized,
contact.addr,
&display_name_normalized,
&contact.addr,
Origin::OutgoingTo,
)
.await

View File

@@ -2034,7 +2034,7 @@ pub(crate) async fn rfc724_mid_exists(
pub async fn update_server_uid(
context: &Context,
rfc724_mid: &str,
server_folder: impl AsRef<str>,
server_folder: &str,
server_uid: u32,
) {
match context
@@ -2042,7 +2042,7 @@ pub async fn update_server_uid(
.execute(
"UPDATE msgs SET server_folder=?, server_uid=? \
WHERE rfc724_mid=?",
paramsv![server_folder.as_ref(), server_uid, rfc724_mid],
paramsv![server_folder, server_uid, rfc724_mid],
)
.await
{

View File

@@ -1278,7 +1278,7 @@ async fn build_body_file(
}
fn build_selfavatar_file(context: &Context, path: &str) -> Result<String> {
let blob = BlobObject::from_path(context, path)?;
let blob = BlobObject::from_path(context, path.as_ref())?;
let body = std::fs::read(blob.to_abs_path())?;
let encoded_body = wrapped_base64_encode(&body);
Ok(encoded_body)
@@ -1328,8 +1328,8 @@ fn encode_words(word: &str) -> String {
encoded_words::encode(word, None, encoded_words::EncodingFlag::Shortest, None)
}
fn needs_encoding(to_check: impl AsRef<str>) -> bool {
!to_check.as_ref().chars().all(|c| {
fn needs_encoding(to_check: &str) -> bool {
!to_check.chars().all(|c| {
c.is_ascii_alphanumeric() || c == '-' || c == '_' || c == '.' || c == '~' || c == '%'
})
}

View File

@@ -524,7 +524,7 @@ impl MimeMessage {
} else {
String::new()
};
match BlobObject::create(context, format!("avatar{}", extension), &decoded_data)
match BlobObject::create(context, &format!("avatar{}", extension), &decoded_data)
.await
{
Ok(blob) => Some(AvatarAction::Change(blob.as_name().to_string())),

View File

@@ -53,20 +53,20 @@ struct Response {
pub async fn dc_get_oauth2_url(
context: &Context,
addr: impl AsRef<str>,
redirect_uri: impl AsRef<str>,
addr: &str,
redirect_uri: &str,
) -> Option<String> {
if let Some(oauth2) = Oauth2::from_address(addr).await {
if context
.sql
.set_raw_config("oauth2_pending_redirect_uri", Some(redirect_uri.as_ref()))
.set_raw_config("oauth2_pending_redirect_uri", Some(redirect_uri))
.await
.is_err()
{
return None;
}
let oauth2_url = replace_in_uri(&oauth2.get_code, "$CLIENT_ID", &oauth2.client_id);
let oauth2_url = replace_in_uri(&oauth2_url, "$REDIRECT_URI", redirect_uri.as_ref());
let oauth2_url = replace_in_uri(oauth2.get_code, "$CLIENT_ID", oauth2.client_id);
let oauth2_url = replace_in_uri(&oauth2_url, "$REDIRECT_URI", redirect_uri);
Some(oauth2_url)
} else {
@@ -76,8 +76,8 @@ pub async fn dc_get_oauth2_url(
pub async fn dc_get_oauth2_access_token(
context: &Context,
addr: impl AsRef<str>,
code: impl AsRef<str>,
addr: &str,
code: &str,
regenerate: bool,
) -> Result<Option<String>> {
if let Some(oauth2) = Oauth2::from_address(addr).await {
@@ -101,7 +101,7 @@ pub async fn dc_get_oauth2_access_token(
.unwrap_or_else(|| "unset".into());
let (redirect_uri, token_url, update_redirect_uri_on_success) =
if refresh_token.is_none() || refresh_token_for != code.as_ref() {
if refresh_token.is_none() || refresh_token_for != code {
info!(context, "Generate OAuth2 refresh_token and access_token...",);
(
context
@@ -145,7 +145,7 @@ pub async fn dc_get_oauth2_access_token(
} else if value == "$REDIRECT_URI" {
value = &redirect_uri;
} else if value == "$CODE" {
value = code.as_ref();
value = code;
} else if value == "$REFRESH_TOKEN" && refresh_token.is_some() {
value = refresh_token.as_ref().unwrap();
}
@@ -179,7 +179,7 @@ pub async fn dc_get_oauth2_access_token(
.await?;
context
.sql
.set_raw_config("oauth2_refresh_token_for", Some(code.as_ref()))
.set_raw_config("oauth2_refresh_token_for", Some(code))
.await?;
}
@@ -222,10 +222,10 @@ pub async fn dc_get_oauth2_access_token(
pub async fn dc_get_oauth2_addr(
context: &Context,
addr: impl AsRef<str>,
code: impl AsRef<str>,
addr: &str,
code: &str,
) -> Result<Option<String>> {
let oauth2 = match Oauth2::from_address(addr.as_ref()).await {
let oauth2 = match Oauth2::from_address(addr).await {
Some(o) => o,
None => return Ok(None),
};
@@ -233,16 +233,14 @@ pub async fn dc_get_oauth2_addr(
return Ok(None);
}
if let Some(access_token) =
dc_get_oauth2_access_token(context, addr.as_ref(), code.as_ref(), false).await?
{
let addr_out = oauth2.get_addr(context, access_token).await;
if let Some(access_token) = dc_get_oauth2_access_token(context, addr, code, false).await? {
let addr_out = oauth2.get_addr(context, &access_token).await;
if addr_out.is_none() {
// regenerate
if let Some(access_token) =
dc_get_oauth2_access_token(context, addr, code, true).await?
{
Ok(oauth2.get_addr(context, access_token).await)
Ok(oauth2.get_addr(context, &access_token).await)
} else {
Ok(None)
}
@@ -255,8 +253,8 @@ pub async fn dc_get_oauth2_addr(
}
impl Oauth2 {
async fn from_address(addr: impl AsRef<str>) -> Option<Self> {
let addr_normalized = normalize_addr(addr.as_ref());
async fn from_address(addr: &str) -> Option<Self> {
let addr_normalized = normalize_addr(addr);
if let Some(domain) = addr_normalized
.find('@')
.map(|index| addr_normalized.split_at(index + 1).1)
@@ -274,9 +272,9 @@ impl Oauth2 {
None
}
async fn get_addr(&self, context: &Context, access_token: impl AsRef<str>) -> Option<String> {
async fn get_addr(&self, context: &Context, access_token: &str) -> Option<String> {
let userinfo_url = self.get_userinfo.unwrap_or("");
let userinfo_url = replace_in_uri(&userinfo_url, "$ACCESS_TOKEN", access_token);
let userinfo_url = replace_in_uri(userinfo_url, "$ACCESS_TOKEN", access_token);
// should returns sth. as
// {
@@ -326,9 +324,9 @@ async fn is_expired(context: &Context) -> Result<bool> {
Ok(true)
}
fn replace_in_uri(uri: impl AsRef<str>, key: impl AsRef<str>, value: impl AsRef<str>) -> String {
let value_urlencoded = utf8_percent_encode(value.as_ref(), NON_ALPHANUMERIC).to_string();
uri.as_ref().replace(key.as_ref(), &value_urlencoded)
fn replace_in_uri(uri: &str, key: &str, value: &str) -> String {
let value_urlencoded = utf8_percent_encode(value, NON_ALPHANUMERIC).to_string();
uri.replace(key, &value_urlencoded)
}
fn normalize_addr(addr: &str) -> &str {

View File

@@ -306,8 +306,8 @@ impl Params {
let file = ParamsFile::from_param(context, val)?;
let blob = match file {
ParamsFile::FsPath(path) => match create {
true => BlobObject::new_from_path(context, path).await?,
false => BlobObject::from_path(context, path)?,
true => BlobObject::new_from_path(context, &path).await?,
false => BlobObject::from_path(context, &path)?,
},
ParamsFile::Blob(blob) => blob,
};

View File

@@ -115,14 +115,14 @@ pub fn get_provider_by_domain(domain: &str) -> Option<&'static Provider> {
/// Finds a provider based on MX record for the given domain.
///
/// For security reasons, only Gmail can be configured this way.
pub async fn get_provider_by_mx(domain: impl AsRef<str>) -> Option<&'static Provider> {
pub async fn get_provider_by_mx(domain: &str) -> Option<&'static Provider> {
if let Ok(resolver) = resolver(
config::ResolverConfig::default(),
config::ResolverOpts::default(),
)
.await
{
let mut fqdn: String = String::from(domain.as_ref());
let mut fqdn: String = domain.to_string();
if !fqdn.ends_with('.') {
fqdn.push('.');
}

View File

@@ -45,9 +45,7 @@ fn starts_with_ignore_case(string: &str, pattern: &str) -> bool {
/// Check a scanned QR code.
/// The function should be called after a QR code is scanned.
/// The function takes the raw text scanned and checks what can be done with it.
pub async fn check_qr(context: &Context, qr: impl AsRef<str>) -> Lot {
let qr = qr.as_ref();
pub async fn check_qr(context: &Context, qr: &str) -> Lot {
info!(context, "Scanned QR code: {}", qr);
if starts_with_ignore_case(qr, OPENPGP4FPR_SCHEME) {
@@ -156,15 +154,11 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Lot {
if let Some(peerstate) = peerstate {
lot.state = LotState::QrFprOk;
lot.id = Contact::add_or_lookup(
context,
name,
peerstate.addr.clone(),
Origin::UnhandledQrScan,
)
.await
.map(|(id, _)| id)
.unwrap_or_default();
lot.id =
Contact::add_or_lookup(context, &name, &peerstate.addr, Origin::UnhandledQrScan)
.await
.map(|(id, _)| id)
.unwrap_or_default();
if let Ok(chat) = ChatIdBlocked::get_for_contact(context, lot.id, Blocked::Deaddrop)
.await
@@ -286,7 +280,7 @@ async fn set_account_from_qr(context: &Context, qr: &str) -> Result<(), Error> {
}
pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error> {
match check_qr(context, &qr).await.state {
match check_qr(context, qr).await.state {
LotState::QrAccount => set_account_from_qr(context, qr).await,
LotState::QrWebrtcInstance => {
let val = decode_webrtc_instance(context, qr).text2;
@@ -423,7 +417,7 @@ impl Lot {
pub async fn from_address(context: &Context, name: String, addr: String) -> Self {
let mut l = Lot::new();
l.state = LotState::QrAddr;
l.id = match Contact::add_or_lookup(context, name, addr, Origin::UnhandledQrScan).await {
l.id = match Contact::add_or_lookup(context, &name, &addr, Origin::UnhandledQrScan).await {
Ok((id, _)) => id,
Err(err) => return err.into(),
};
@@ -677,7 +671,7 @@ mod tests {
let res = check_qr(
&ctx.ctx,
format!("OPENPGP4FPR:{}#a=alice@example.com", pub_key.fingerprint()),
&format!("OPENPGP4FPR:{}#a=alice@example.com", pub_key.fingerprint()),
)
.await;
assert_eq!(res.get_state(), LotState::QrFprOk);

View File

@@ -296,7 +296,7 @@ async fn securejoin(context: &Context, qr: &str) -> Result<ChatId, JoinError> {
========================================================*/
info!(context, "Requesting secure-join ...",);
let qr_scan = check_qr(context, &qr).await;
let qr_scan = check_qr(context, qr).await;
let invite = QrInvite::try_from(qr_scan)?;
@@ -365,9 +365,9 @@ async fn send_handshake_msg(
context: &Context,
contact_chat_id: ChatId,
step: &str,
param2: impl AsRef<str>,
param2: &str,
fingerprint: Option<Fingerprint>,
grpid: impl AsRef<str>,
grpid: &str,
) -> Result<(), SendMsgError> {
let mut msg = Message {
viewtype: Viewtype::Text,
@@ -381,14 +381,14 @@ async fn send_handshake_msg(
} else {
msg.param.set(Param::Arg, step);
}
if !param2.as_ref().is_empty() {
if !param2.is_empty() {
msg.param.set(Param::Arg2, param2);
}
if let Some(fp) = fingerprint {
msg.param.set(Param::Arg3, fp.hex());
}
if !grpid.as_ref().is_empty() {
msg.param.set(Param::Arg4, grpid.as_ref());
if !grpid.is_empty() {
msg.param.set(Param::Arg4, grpid);
}
if step == "vg-request" || step == "vc-request" {
msg.param.set_int(Param::ForcePlaintext, 1);

View File

@@ -1,10 +1,10 @@
//! # SQLite wrapper
use async_std::path::Path;
use async_std::sync::RwLock;
use std::collections::HashSet;
use std::convert::TryFrom;
use std::path::Path;
use std::time::Duration;
use anyhow::{bail, format_err, Context as _, Result};
@@ -107,19 +107,18 @@ impl Sql {
pub async fn open(
&self,
context: &Context,
dbfile: impl AsRef<Path>,
dbfile: &Path,
readonly: bool,
) -> anyhow::Result<()> {
if self.is_open().await {
error!(
context,
"Cannot open, database \"{:?}\" already opened.",
dbfile.as_ref(),
"Cannot open, database \"{:?}\" already opened.", dbfile,
);
bail!("SQL database is already opened.");
}
*self.pool.write().await = Some(Self::new_pool(dbfile.as_ref(), readonly)?);
*self.pool.write().await = Some(Self::new_pool(dbfile, readonly)?);
if !readonly {
{
@@ -183,7 +182,7 @@ impl Sql {
if recode_avatar {
if let Some(avatar) = context.get_config(Config::Selfavatar).await? {
let mut blob = BlobObject::new_from_path(context, &avatar).await?;
let mut blob = BlobObject::new_from_path(context, avatar.as_ref()).await?;
match blob.recode_to_avatar_size(context).await {
Ok(()) => {
context
@@ -199,7 +198,7 @@ impl Sql {
}
}
info!(context, "Opened {:?}.", dbfile.as_ref());
info!(context, "Opened {:?}.", dbfile);
Ok(())
}
@@ -318,11 +317,10 @@ impl Sql {
}
/// Query the database if the requested table already exists.
pub async fn table_exists(&self, name: impl AsRef<str>) -> anyhow::Result<bool> {
let name = name.as_ref().to_string();
pub async fn table_exists(&self, name: &str) -> anyhow::Result<bool> {
let conn = self.get_conn().await?;
let mut exists = false;
conn.pragma(None, "table_info", &name, |_row| {
conn.pragma(None, "table_info", &name.to_string(), |_row| {
// will only be executed if the info was found
exists = true;
Ok(())
@@ -332,18 +330,12 @@ impl Sql {
}
/// Check if a column exists in a given table.
pub async fn col_exists(
&self,
table_name: impl AsRef<str>,
col_name: impl AsRef<str>,
) -> anyhow::Result<bool> {
let table_name = table_name.as_ref().to_string();
let col_name = col_name.as_ref().to_string();
pub async fn col_exists(&self, table_name: &str, col_name: &str) -> anyhow::Result<bool> {
let conn = self.get_conn().await?;
let mut exists = false;
// `PRAGMA table_info` returns one row per column,
// each row containing 0=cid, 1=name, 2=type, 3=notnull, 4=dflt_value
conn.pragma(None, "table_info", &table_name, |row| {
conn.pragma(None, "table_info", &table_name.to_string(), |row| {
let curr_name: String = row.get(1)?;
if col_name == curr_name {
exists = true;
@@ -406,13 +398,13 @@ impl Sql {
if exists {
self.execute(
"UPDATE config SET value=? WHERE keyname=?;",
paramsv![(*value).to_string(), key.to_string()],
paramsv![value, key],
)
.await?;
} else {
self.execute(
"INSERT INTO config (keyname, value) VALUES (?, ?);",
paramsv![key.to_string(), (*value).to_string()],
paramsv![key, value],
)
.await?;
}
@@ -429,7 +421,7 @@ impl Sql {
let value = self
.query_get_value(
"SELECT value FROM config WHERE keyname=?;",
paramsv![key.as_ref().to_string()],
paramsv![key.as_ref()],
)
.await
.context(format!("failed to fetch raw config: {}", key.as_ref()))?;
@@ -761,7 +753,7 @@ mod test {
t.sql.close().await;
housekeeping(&t).await.unwrap_err(); // housekeeping should fail as the db is closed
t.sql.open(&t, &t.get_dbfile(), false).await.unwrap();
t.sql.open(&t, t.get_dbfile(), false).await.unwrap();
let a = t.get_config(Config::Selfavatar).await.unwrap().unwrap();
assert_eq!(avatar_bytes, &async_std::fs::read(&a).await.unwrap()[..]);
@@ -792,11 +784,11 @@ mod test {
let sql = Sql::new();
// Create database with all the tables.
sql.open(&t, &dbfile, false).await.unwrap();
sql.open(&t, dbfile.as_ref(), false).await.unwrap();
sql.close().await;
// Reopen the database
sql.open(&t, &dbfile, false).await?;
sql.open(&t, dbfile.as_ref(), false).await?;
sql.execute(
"INSERT INTO config (keyname, value) VALUES (?, ?);",
paramsv!("foo", "bar"),

View File

@@ -925,7 +925,7 @@ impl Context {
chat::add_device_msg(self, Some("core-about-device-chat"), Some(&mut msg)).await?;
let image = include_bytes!("../assets/welcome-image.jpg");
let blob = BlobObject::create(self, "welcome-image.jpg".to_string(), image).await?;
let blob = BlobObject::create(self, "welcome-image.jpg", image).await?;
let mut msg = Message::new(Viewtype::Image);
msg.param.set(Param::File, blob.as_name());
chat::add_device_msg(self, Some("core-welcome-image"), Some(&mut msg)).await?;

View File

@@ -338,13 +338,13 @@ impl TestContext {
pub async fn create_chat(&self, other: &TestContext) -> Chat {
let (contact_id, _modified) = Contact::add_or_lookup(
self,
other
&other
.ctx
.get_config(Config::Displayname)
.await
.unwrap_or_default()
.unwrap_or_default(),
other
&other
.ctx
.get_config(Config::ConfiguredAddr)
.await