mirror of
https://github.com/chatmail/core.git
synced 2026-05-04 13:56:30 +03:00
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:
@@ -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, ¶m1)
|
||||
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))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
81
src/blob.rs
81
src/blob.rs
@@ -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"
|
||||
|
||||
20
src/chat.rs
20
src/chat.rs
@@ -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;
|
||||
|
||||
@@ -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)))
|
||||
}
|
||||
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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={}",
|
||||
¶m_domain, ¶m_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/{}", ¶m_domain),
|
||||
&format!("https://autoconfig.thunderbird.net/v1.1/{}", ¶m_domain),
|
||||
param,
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -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(¶m_in.addr, &xml_raw);
|
||||
if let Err(err) = &res {
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
12
src/imap.rs
12
src/imap.rs
@@ -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");
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
61
src/imex.rs
61
src/imex.rs
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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 == '%'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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())),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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('.');
|
||||
}
|
||||
|
||||
24
src/qr.rs
24
src/qr.rs
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
40
src/sql.rs
40
src/sql.rs
@@ -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"),
|
||||
|
||||
@@ -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?;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user