Private
Public Access
1
0

Don't overwrite already resolved participants, better naming of keys

This commit is contained in:
2025-06-26 18:23:15 -07:00
parent bb19db17cd
commit f6bb1a9b57
25 changed files with 263 additions and 306 deletions

View File

@@ -4,7 +4,10 @@ use dbus::arg::{RefArg, Variant};
use once_cell::sync::OnceCell;
use std::collections::HashMap;
use std::time::Duration;
use std::sync::Mutex;
use std::thread;
#[derive(Clone)]
pub struct EDSContactResolverBackend;
// Cache the UID of the default local address book so we do not have to scan
@@ -12,6 +15,42 @@ pub struct EDSContactResolverBackend;
// D-Bus round-trip that we would rather avoid on every lookup.
static ADDRESS_BOOK_SOURCE_UID: OnceCell<String> = OnceCell::new();
/// Holds a D-Bus connection and the identifiers needed to create an address-book proxy.
struct AddressBookHandle {
connection: Connection,
object_path: String,
bus_name: String,
}
impl AddressBookHandle {
fn new() -> anyhow::Result<Self> {
let connection = new_session_connection()?;
let source_uid = ensure_address_book_uid(&connection)?;
let (object_path, bus_name) = open_address_book(&connection, &source_uid)?;
Ok(Self {
connection,
object_path,
bus_name,
})
}
}
/// Obtain the global address-book handle, initialising it on the first call.
static ADDRESS_BOOK_HANDLE: OnceCell<Mutex<AddressBookHandle>> = OnceCell::new();
fn get_address_book_handle() -> Option<&'static Mutex<AddressBookHandle>> {
ADDRESS_BOOK_HANDLE
.get_or_try_init(|| AddressBookHandle::new().map(Mutex::new))
.map_err(|e| {
log::debug!(
"EDS resolver: failed to initialise address book handle: {}",
e
);
})
.ok()
}
/// Helper that returns a blocking D-Bus session connection. Creating the
/// connection is cheap (<1 ms) but we still keep it around because the
/// underlying socket is re-used by the dbus crate.
@@ -109,51 +148,41 @@ impl ContactResolverBackend for EDSContactResolverBackend {
type ContactID = String;
fn resolve_contact_id(&self, address: &str) -> Option<Self::ContactID> {
// Only email addresses are supported for now. We fall back to NONE on
// any error to keep the resolver infallible for callers.
let conn = match new_session_connection() {
Ok(c) => c,
Err(e) => {
log::debug!("EDS resolver: failed to open session D-Bus: {}", e);
return None;
}
let handle_mutex = match get_address_book_handle() {
Some(h) => h,
None => return None,
};
let source_uid = match ensure_address_book_uid(&conn) {
Ok(u) => u,
Err(e) => {
log::debug!("EDS resolver: could not determine address-book UID: {}", e);
return None;
}
};
let (object_path, bus_name) = match open_address_book(&conn, &source_uid) {
Ok(v) => v,
Err(e) => {
log::debug!("EDS resolver: failed to open address book: {}", e);
return None;
}
};
let address_book_proxy = conn.with_proxy(bus_name, object_path, Duration::from_secs(60));
let handle = handle_mutex.lock().unwrap();
let address_book_proxy = handle.connection.with_proxy(
&handle.bus_name,
&handle.object_path,
Duration::from_secs(60),
);
let filter = if address.contains('@') {
format!("(is \"email\" \"{}\")", address)
} else {
// Remove country code, if present
let address = address.replace("+", "")
let normalized_address = address
.replace('+', "")
.chars()
.skip_while(|c| c.is_numeric() || *c == '(' || *c == ')')
.collect::<String>();
// Remove any remaining non-numeric characters
let address = address.chars()
.collect::<String>()
.chars()
.filter(|c| c.is_numeric())
.collect::<String>();
format!("(is \"phone\" \"{}\")", address)
format!(
"(or (is \"phone\" \"{}\") (is \"phone\" \"{}\") )",
address, normalized_address
)
};
log::trace!(
"EDS resolver: GetContactListUids filter: {}, address: {}",
filter,
address
);
let uids_result: Result<(Vec<String>,), _> = address_book_proxy.method_call(
"org.gnome.evolution.dataserver.AddressBook",
"GetContactListUids",
@@ -172,31 +201,17 @@ impl ContactResolverBackend for EDSContactResolverBackend {
}
fn get_contact_display_name(&self, contact_id: &Self::ContactID) -> Option<String> {
let conn = match new_session_connection() {
Ok(c) => c,
Err(e) => {
log::debug!("EDS resolver: failed to open session D-Bus: {}", e);
return None;
}
let handle_mutex = match get_address_book_handle() {
Some(h) => h,
None => return None,
};
let source_uid = match ensure_address_book_uid(&conn) {
Ok(u) => u,
Err(e) => {
log::debug!("EDS resolver: could not determine address-book UID: {}", e);
return None;
}
};
let (object_path, bus_name) = match open_address_book(&conn, &source_uid) {
Ok(v) => v,
Err(e) => {
log::debug!("EDS resolver: failed to open address book: {}", e);
return None;
}
};
let address_book_proxy = conn.with_proxy(bus_name, object_path, Duration::from_secs(60));
let handle = handle_mutex.lock().unwrap();
let address_book_proxy = handle.connection.with_proxy(
&handle.bus_name,
&handle.object_path,
Duration::from_secs(60),
);
let vcard_result: Result<(String,), _> = address_book_proxy.method_call(
"org.gnome.evolution.dataserver.AddressBook",