Don't overwrite already resolved participants, better naming of keys
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -10,6 +10,7 @@ pub trait ContactResolverBackend {
|
||||
|
||||
pub type AnyContactID = String;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ContactResolver<T: ContactResolverBackend> {
|
||||
backend: T,
|
||||
}
|
||||
|
||||
@@ -522,15 +522,15 @@ impl Daemon {
|
||||
.await?
|
||||
{
|
||||
for p in &saved.participants {
|
||||
if let DbParticipant::Remote { id: Some(pid), display_name, contact_id: None } = p {
|
||||
log::trace!(target: target::SYNC, "Resolving contact id for participant: {}", display_name);
|
||||
if let Some(contact) = contact_resolver.resolve_contact_id(display_name) {
|
||||
if let DbParticipant::Remote { handle, contact_id: None } = p {
|
||||
log::trace!(target: target::SYNC, "Resolving contact id for participant: {}", handle);
|
||||
if let Some(contact) = contact_resolver.resolve_contact_id(handle) {
|
||||
log::trace!(target: target::SYNC, "Resolved contact id for participant: {}", contact);
|
||||
let _ = database
|
||||
.with_repository(|r| r.update_participant_contact(*pid, &contact))
|
||||
.with_repository(|r| r.update_participant_contact(&handle, &contact))
|
||||
.await;
|
||||
} else {
|
||||
log::trace!(target: target::SYNC, "No contact id found for participant: {}", display_name);
|
||||
log::trace!(target: target::SYNC, "No contact id found for participant: {}", handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ use crate::daemon::attachment_store::AttachmentStore;
|
||||
use crate::daemon::models::Attachment;
|
||||
use kordophone::model::message::AttachmentMetadata;
|
||||
use kordophone::model::outgoing_message::OutgoingMessage;
|
||||
use kordophone_db::models::participant::Participant as DbParticipant;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Participant {
|
||||
Me,
|
||||
Remote {
|
||||
id: Option<i32>,
|
||||
display_name: String,
|
||||
handle: String,
|
||||
contact_id: Option<String>,
|
||||
},
|
||||
}
|
||||
@@ -20,8 +20,7 @@ pub enum Participant {
|
||||
impl From<String> for Participant {
|
||||
fn from(display_name: String) -> Self {
|
||||
Participant::Remote {
|
||||
id: None,
|
||||
display_name,
|
||||
handle: display_name,
|
||||
contact_id: None,
|
||||
}
|
||||
}
|
||||
@@ -30,8 +29,7 @@ impl From<String> for Participant {
|
||||
impl From<&str> for Participant {
|
||||
fn from(display_name: &str) -> Self {
|
||||
Participant::Remote {
|
||||
id: None,
|
||||
display_name: display_name.to_string(),
|
||||
handle: display_name.to_string(),
|
||||
contact_id: None,
|
||||
}
|
||||
}
|
||||
@@ -41,8 +39,8 @@ impl From<kordophone_db::models::Participant> for Participant {
|
||||
fn from(participant: kordophone_db::models::Participant) -> Self {
|
||||
match participant {
|
||||
kordophone_db::models::Participant::Me => Participant::Me,
|
||||
kordophone_db::models::Participant::Remote { id, display_name, contact_id } => {
|
||||
Participant::Remote { id, display_name, contact_id }
|
||||
kordophone_db::models::Participant::Remote { handle, contact_id } => {
|
||||
Participant::Remote { handle, contact_id }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +50,7 @@ impl Participant {
|
||||
pub fn display_name(&self) -> String {
|
||||
match self {
|
||||
Participant::Me => "(Me)".to_string(),
|
||||
Participant::Remote { display_name, .. } => display_name.clone(),
|
||||
Participant::Remote { handle, .. } => handle.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,8 +108,8 @@ impl From<Message> for kordophone_db::models::Message {
|
||||
id: message.id,
|
||||
sender: match message.sender {
|
||||
Participant::Me => kordophone_db::models::Participant::Me,
|
||||
Participant::Remote { id, display_name, contact_id } => {
|
||||
kordophone_db::models::Participant::Remote { id, display_name, contact_id }
|
||||
Participant::Remote { handle, contact_id } => {
|
||||
kordophone_db::models::Participant::Remote { handle, contact_id }
|
||||
}
|
||||
},
|
||||
text: message.text,
|
||||
@@ -146,8 +144,7 @@ impl From<kordophone::model::Message> for Message {
|
||||
id: message.guid,
|
||||
sender: match message.sender {
|
||||
Some(sender) => Participant::Remote {
|
||||
id: None,
|
||||
display_name: sender,
|
||||
handle: sender,
|
||||
contact_id: None,
|
||||
},
|
||||
None => Participant::Me,
|
||||
@@ -175,3 +172,12 @@ impl From<&OutgoingMessage> for Message {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Participant> for DbParticipant {
|
||||
fn from(participant: Participant) -> Self {
|
||||
match participant {
|
||||
Participant::Me => DbParticipant::Me,
|
||||
Participant::Remote { handle, contact_id } => DbParticipant::Remote { handle, contact_id: contact_id.clone() },
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ use dbus_tokio::connection;
|
||||
pub struct DBusAgent {
|
||||
event_sink: mpsc::Sender<Event>,
|
||||
signal_receiver: Arc<Mutex<Option<mpsc::Receiver<Signal>>>>,
|
||||
contact_resolver: ContactResolver<EDSContactResolverBackend>,
|
||||
}
|
||||
|
||||
impl DBusAgent {
|
||||
@@ -30,6 +31,7 @@ impl DBusAgent {
|
||||
Self {
|
||||
event_sink,
|
||||
signal_receiver: Arc::new(Mutex::new(Some(signal_receiver))),
|
||||
contact_resolver: ContactResolver::new(EDSContactResolverBackend::default()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,19 +174,18 @@ impl DBusAgent {
|
||||
}
|
||||
|
||||
fn resolve_participant_display_name(&self, participant: &Participant) -> String {
|
||||
let resolver = ContactResolver::new(EDSContactResolverBackend::default());
|
||||
match participant {
|
||||
// Me (we should use a special string here...)
|
||||
Participant::Me => "(Me)".to_string(),
|
||||
|
||||
// Remote participant with a resolved contact_id
|
||||
Participant::Remote { display_name, contact_id: Some(contact_id), .. } => {
|
||||
resolver.get_contact_display_name(contact_id).unwrap_or_else(|| display_name.clone())
|
||||
Participant::Remote { handle, contact_id: Some(contact_id), .. } => {
|
||||
self.contact_resolver.get_contact_display_name(contact_id).unwrap_or_else(|| handle.clone())
|
||||
}
|
||||
|
||||
// Remote participant without a resolved contact_id
|
||||
Participant::Remote { display_name, .. } => {
|
||||
display_name.clone()
|
||||
Participant::Remote { handle, .. } => {
|
||||
handle.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,6 +279,8 @@ impl DbusRepository for DBusAgent {
|
||||
// Remove the attachment placeholder here.
|
||||
let text = msg.text.replace("\u{FFFC}", "");
|
||||
|
||||
log::debug!("sender: {:?}", msg.sender.clone());
|
||||
|
||||
map.insert("text".into(), arg::Variant(Box::new(text)));
|
||||
map.insert(
|
||||
"date".into(),
|
||||
@@ -285,9 +288,11 @@ impl DbusRepository for DBusAgent {
|
||||
);
|
||||
map.insert(
|
||||
"sender".into(),
|
||||
arg::Variant(Box::new(msg.sender.display_name())),
|
||||
arg::Variant(Box::new(self.resolve_participant_display_name(&msg.sender.into()))),
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Attachments array
|
||||
let attachments: Vec<arg::PropMap> = msg
|
||||
.attachments
|
||||
|
||||
Reference in New Issue
Block a user