diff --git a/src/padfoot/connection.rs b/src/padfoot/connection.rs index 639eba1..cbff5b2 100644 --- a/src/padfoot/connection.rs +++ b/src/padfoot/connection.rs @@ -2,7 +2,7 @@ use crate::telepathy; use dbus::blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection}; use dbus::channel::Sender; use dbus::message::SignalArgs; -use dbus::tree; +use dbus::{arg, tree}; use dc::config::Config; use dc::context::Context; @@ -68,7 +68,8 @@ impl Connection { let msgq = Arc::new(Mutex::new(VecDeque::::new())); let id2 = id.clone(); - let msgq2 = msgq.clone(); + // Use this if we need to send messages in response to DC events: + // let msgq2 = msgq.clone(); let f = move |_c: &Context, e: Event| { match e { Event::Info(msg) => println!("Connection<{}>: INFO: {}", id2, msg), @@ -144,11 +145,26 @@ impl Connection { let c_rc = std::rc::Rc::new(self); let f = tree::Factory::new_fn::<()>(); - let iface = telepathy::connection_server(&f, (), move |_| c_rc.clone()); - let mut tree = f.tree(()); - tree = tree.add(f.object_path(path, ()).introspectable().add(iface)); + let c_rc1 = c_rc.clone(); + let conn_iface = telepathy::connection_server(&f, (), move |_| c_rc1.clone()); + + let c_rc2 = c_rc.clone(); + let contacts_iface = + telepathy::connection_interface_contacts_server(&f, (), move |_| c_rc2.clone()); + + let c_rc3 = c_rc.clone(); + let requests_iface = + telepathy::connection_interface_requests_server(&f, (), move |_| c_rc3.clone()); + + tree = tree.add( + f.object_path(path.clone(), ()) + .introspectable() + .add(conn_iface) + .add(contacts_iface) + .add(requests_iface), + ); tree = tree.add(f.object_path("/", ()).introspectable()); // Setup DBus connection @@ -219,6 +235,18 @@ impl AsRef for std::rc::Rc { } } +impl AsRef for std::rc::Rc { + fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceContacts + 'static) { + &**self + } +} + +impl AsRef for std::rc::Rc { + fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceRequests + 'static) { + &**self + } +} + impl telepathy::Connection for Connection { // In connect(), we start the threads that drive the deltachat context fn connect(&self) -> Result<(), tree::MethodErr> { @@ -443,6 +471,128 @@ impl telepathy::Connection for Connection { } } +impl telepathy::ConnectionInterfaceContacts for Connection { + fn get_contact_attributes( + &self, + handles: Vec, + interfaces: Vec<&str>, + hold: bool, + ) -> Result>, tree::MethodErr> { + println!( + "Connection<{}>::get_contact_attributes({:?}, {:?}, {})", + self.id, handles, interfaces, hold + ); + + let mut out = HashMap::>::new(); + for id in handles.iter() { + // FIXME: work out how to use get_all + let contact = match dc::contact::Contact::get_by_id(&self.ctx.read().unwrap(), *id) { + Ok(c) => c, + Err(_e) => continue, // FIXME: Ignore the error. Whatevs. + }; + + let mut props = HashMap::::new(); + // This is mandatory + props.insert( + "org.freedesktop.Telepathy.Connection/contact-id".to_string(), + arg::Variant(Box::new(contact.get_display_name().to_string())), + ); + + // We don't advertise this interface but empathy is being weird. + // The empty string means "no avatar" + props.insert( + "org.freedesktop.Telepathy.Connection.Interface.Avatars/token".to_string(), + arg::Variant(Box::new("".to_string())), + ); + + out.insert(*id, props); + } + + Ok(out) + } + + fn get_contact_by_id( + &self, + identifier: &str, + interfaces: Vec<&str>, + ) -> Result< + ( + u32, + ::std::collections::HashMap>>, + ), + tree::MethodErr, + > { + println!( + "Connection<{}>::get_contact_by_id({}, {:?})", + self.id, identifier, interfaces + ); + Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented? + } + + fn contact_attribute_interfaces(&self) -> Result, tree::MethodErr> { + println!("Connection<{}>::contact_attribute_interfaces()", self.id); + + Ok(vec![]) + } +} + +impl telepathy::ConnectionInterfaceRequests for Connection { + fn create_channel( + &self, + request: ::std::collections::HashMap<&str, arg::Variant>>, + ) -> Result< + ( + dbus::Path<'static>, + ::std::collections::HashMap>>, + ), + tree::MethodErr, + > { + println!("Connection<{}>::create_channel({:?})", self.id, request); + Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented? + } + + fn ensure_channel( + &self, + request: ::std::collections::HashMap<&str, arg::Variant>>, + ) -> Result< + ( + bool, + dbus::Path<'static>, + ::std::collections::HashMap>>, + ), + tree::MethodErr, + > { + println!("Connection<{}>::ensure_channel({:?})", self.id, request); + Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented? + } + + fn channels( + &self, + ) -> Result< + Vec<( + dbus::Path<'static>, + ::std::collections::HashMap>>, + )>, + tree::MethodErr, + > { + println!("Connection<{}>::channels()", self.id); + Ok(vec![]) + } + + fn requestable_channel_classes( + &self, + ) -> Result< + Vec<( + ::std::collections::HashMap>>, + Vec, + )>, + tree::MethodErr, + > { + println!("Connection<{}>::requestable_channel_classes()", self.id); + Ok(super::requestables()) + } +} + fn escape_one(b: u8) -> String { format!("_{:0<2x}", b) }