From c643c42fa5a06f6c6932603e0b0c38f9a51beb34 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Sat, 9 May 2020 21:45:29 +0100 Subject: [PATCH] Initial protocol implementation Empathy needs this patch before it will display the settings: https://gitlab.gnome.org/GNOME/telepathy-account-widgets/-/merge_requests/1 --- share/telepathy/managers/padfoot.manager | 3 +- src/main.rs | 63 ++++++------- src/padfoot/connection_manager.rs | 110 +++++++++++------------ src/padfoot/protocol.rs | 105 ++++++++++++++++++++++ 4 files changed, 188 insertions(+), 93 deletions(-) diff --git a/share/telepathy/managers/padfoot.manager b/share/telepathy/managers/padfoot.manager index e6fd59f..215ebd5 100644 --- a/share/telepathy/managers/padfoot.manager +++ b/share/telepathy/managers/padfoot.manager @@ -2,11 +2,10 @@ Name=padfoot BusName=org.freedesktop.Telepathy.ConnectionManager.padfoot ObjectPath=/org/freedesktop/Telepathy/ConnectionManager/padfoot -Interfaces= [Protocol delta] param-account=s required param-password=s required secret -Interfaces= EnglishName=Delta Chat +VCardField=email Icon=im-delta diff --git a/src/main.rs b/src/main.rs index 2a4fd50..1946a37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,49 +1,44 @@ mod padfoot; mod telepathy; -//use dbus::tree::{Interface, MTFn, MethodErr}; +use anyhow::{anyhow, Result}; use dbus::{ blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection}, - tree::{Factory, MTFn, Tree}, + tree::Factory, }; - -use padfoot::{CMData, ConnectionManager}; - -use std::sync::Arc; +use padfoot::{ConnectionManager, Protocol}; use std::time::Duration; -use anyhow::{anyhow, Result}; - const CM_BUS_NAME: &'static str = "org.freedesktop.Telepathy.ConnectionManager.padfoot"; const CM_OBJECT_PATH: &'static str = "/org/freedesktop/Telepathy/ConnectionManager/padfoot"; - -fn create_tree(cm: &Arc) -> Tree, CMData> { - let f = Factory::new_fn(); - let mut tree = f.tree(()); - - let iface = telepathy::connection_manager_server(&f, (), |m| { - let a: &Arc = m.path.get_data(); - let b: &ConnectionManager = &a; - - b - }); - - tree = tree.add( - f.object_path(CM_OBJECT_PATH, cm.clone()) - .introspectable() - .add(iface), - ); - tree = tree.add(f.object_path("/", cm.clone()).introspectable()); - - tree -} +const PROTO_OBJECT_PATH: &'static str = + "/org/freedesktop/Telepathy/ConnectionManager/padfoot/delta"; fn run() -> Result<()> { - let cm: ConnectionManager = ConnectionManager {}; - let tree = create_tree(&Arc::new(cm)); + let f = Factory::new_fn::<()>(); + let mut tree = f.tree(()); + + let proto: &'static Protocol = &Protocol {}; + let cm: &'static ConnectionManager = &ConnectionManager {}; + let cm_iface = telepathy::connection_manager_server(&f, (), move |_m| cm); + let proto_iface = telepathy::protocol_server(&f, (), move |_m| proto); + + tree = tree.add( + f.object_path(CM_OBJECT_PATH, ()) + .introspectable() + .add(cm_iface), + ); + tree = tree.add( + f.object_path(PROTO_OBJECT_PATH, ()) + .introspectable() + .add(proto_iface), + ); + + tree = tree.add(f.object_path("/", ()).introspectable()); // Setup DBus connection let mut c = LocalConnection::new_session()?; + tree.start_receive(&c); let result = c.request_name(CM_BUS_NAME, false, false, true)?; match result { @@ -53,15 +48,11 @@ fn run() -> Result<()> { CM_BUS_NAME )) } - _ => {} // All other responses we can get are a success + _ => println!("{} listening on {}", c.unique_name(), CM_BUS_NAME), // All other responses we can get are a success }; - println!("Bus registered: {}", CM_BUS_NAME); - tree.start_receive(&c); - loop { c.process(Duration::from_secs(1))?; - println!("Tick"); } } diff --git a/src/padfoot/connection_manager.rs b/src/padfoot/connection_manager.rs index 18c7cea..d4e03c7 100644 --- a/src/padfoot/connection_manager.rs +++ b/src/padfoot/connection_manager.rs @@ -2,89 +2,89 @@ use crate::telepathy; use dbus::{arg, tree}; use std::collections::HashMap; +// FIXME: CM should take an opaque set of protocols to advertise +use super::protocol; + #[derive(Debug)] pub struct ConnectionManager {} -#[derive(Copy, Clone, Default, Debug)] -pub struct CMData; - -impl dbus::tree::DataType for CMData { - type Tree = (); - type Property = (); - type Interface = (); - type Method = (); - type Signal = (); - type ObjectPath = std::sync::Arc; -} - -const PROTO: &'static str = "delta"; - -pub type ParamSpec = ( - String, // Name - u32, // Flags (Conn_Mgr_Param_Flags) - String, // Signature - arg::Variant>, // Default -); - -pub type Dict = HashMap>>; - -// FIXME: these should come from codegen -const FLAG_REQUIRED: u32 = 1; -//const FLAG_REGISTER: u32 = 2; -//const FLAG_HAS_DEFAULT: u32 = 4; -const FLAG_SECRET: u32 = 8; -//const FLAG_DBUS_PROP: u32 = 16; - impl telepathy::ConnectionManager for ConnectionManager { - fn get_parameters(&self, protocol: &str) -> Result, tree::MethodErr> { + fn get_parameters(&self, protocol: &str) -> Result, tree::MethodErr> { println!("CM::get_parameters({})", protocol); - if protocol != PROTO { - return Err(tree::MethodErr::no_arg()); // FIXME: should be NotImplemented? + match protocol { + protocol::NAME => Ok(protocol::parameters()), + _ => Err(tree::MethodErr::no_arg()), // FIXME: should be NotImplemented? } - - // TODO: query the protocol for these? - Ok(vec![ - ( - "account".to_string(), - FLAG_REQUIRED, - "s".to_string(), - arg::Variant(Box::new("".to_string())), - ), - ( - "password".to_string(), - FLAG_REQUIRED | FLAG_SECRET, - "s".to_string(), - arg::Variant(Box::new("".to_string())), - ), - ]) } fn list_protocols(&self) -> Result, tree::MethodErr> { println!("CM::list_protocols()"); - Ok(vec![PROTO.to_string()]) + Ok(vec![protocol::NAME.to_string()]) } fn request_connection( &self, protocol: &str, - parameters: HashMap<&str, arg::Variant>>, + parameters: HashMap<&str, protocol::Variant>, ) -> Result<(String, dbus::Path<'static>), tree::MethodErr> { println!("CM::request_connection({}, {:?})", protocol, parameters); Err(tree::MethodErr::no_arg()) } - fn protocols(&self) -> Result, tree::MethodErr> { + fn protocols( + &self, + ) -> Result>, tree::MethodErr> { println!("CM::protocols()"); - // If this map is empty or missing, clients SHOULD fall back to - // calling ListProtocols and GetParameters - Err(tree::MethodErr::no_arg()) + // FIXME: so much duplication + let mut out = HashMap::>::new(); + let mut props = HashMap::::new(); + + props.insert( + "org.freedesktop.Telepathy.Protocol.AuthenticationTypes".to_string(), + arg::Variant(Box::new(Vec::::new())), + ); + + props.insert( + "org.freedesktop.Telepathy.Protocol.ConnectionInterfaces".to_string(), + arg::Variant(Box::new(Vec::::new())), + ); + props.insert( + "org.freedesktop.Telepathy.Protocol.EnglishName".to_string(), + arg::Variant(Box::new("Delta Chat".to_string())), + ); + props.insert( + "org.freedesktop.Telepathy.Protocol.Icon".to_string(), + arg::Variant(Box::new("im-delta".to_string())), + ); + props.insert( + "org.freedesktop.Telepathy.Protocol.Interfaces".to_string(), + arg::Variant(Box::new(Vec::::new())), + ); + props.insert( + "org.freedesktop.Telepathy.Protocol.Parameters".to_string(), + arg::Variant(Box::new(protocol::parameters())), + ); + props.insert( + "org.freedesktop.Telepathy.Protocol.RequestableChannelClasses".to_string(), + arg::Variant(Box::new(Vec::::new())), + ); + props.insert( + "org.freedesktop.Telepathy.Protocol.VCardField".to_string(), + arg::Variant(Box::new("email".to_string())), + ); + + out.insert(protocol::NAME.to_string(), props); + + Ok(out) } fn interfaces(&self) -> Result, tree::MethodErr> { + println!("CM::interfaces()"); + Ok(vec![]) } } diff --git a/src/padfoot/protocol.rs b/src/padfoot/protocol.rs index 3dbbcdd..bd18306 100644 --- a/src/padfoot/protocol.rs +++ b/src/padfoot/protocol.rs @@ -1 +1,106 @@ +use crate::telepathy; +use dbus::{arg, tree}; +use std::collections::HashMap; + +#[derive(Debug)] pub struct Protocol {} + +pub type ParamSpec = ( + String, // Name + u32, // Flags (Conn_Mgr_Param_Flags) + String, // Signature + arg::Variant>, // Default +); + +pub type Variant = arg::Variant>; + +pub const NAME: &'static str = "delta"; + +// FIXME: these should come from codegen +//const FLAG_NONE: u32 = 0; +const FLAG_REQUIRED: u32 = 1; +//const FLAG_REGISTER: u32 = 2; +//const FLAG_HAS_DEFAULT: u32 = 4; +const FLAG_SECRET: u32 = 8; +//const FLAG_DBUS_PROP: u32 = 16; + +pub fn parameters() -> Vec { + vec![ + ( + "account".to_string(), + FLAG_REQUIRED, + "s".to_string(), + arg::Variant(Box::new("".to_string())), + ), + ( + "password".to_string(), + FLAG_REQUIRED | FLAG_SECRET, + "s".to_string(), + arg::Variant(Box::new("".to_string())), + ), + ] +} + +impl telepathy::Protocol for Protocol { + fn identify_account(&self, params: HashMap<&str, Variant>) -> Result { + println!("Protocol::identify_account({:?})", params); + + Err(tree::MethodErr::no_arg()) + } + + fn normalize_contact(&self, contact_id: &str) -> Result { + println!("Protocol::normalize_contact({})", contact_id); + + Err(tree::MethodErr::no_arg()) + } + + fn interfaces(&self) -> Result, tree::MethodErr> { + println!("Protocol::interfaces()"); + + Ok(vec![]) + } + fn parameters(&self) -> Result, tree::MethodErr> { + println!("Protocol::parameters()"); + + Ok(parameters()) + } + + fn connection_interfaces(&self) -> Result, tree::MethodErr> { + println!("Protocol::connection_interfaces()"); + + Ok(vec![]) + } + fn requestable_channel_classes( + &self, + ) -> Result< + Vec<( + ::std::collections::HashMap>>, + Vec, + )>, + tree::MethodErr, + > { + println!("Protocol::requestable_channel_classes()"); + + Ok(vec![]) + } + fn vcard_field(&self) -> Result { + println!("Protocol::vcard_field()"); + + Ok("email".to_string()) + } + fn english_name(&self) -> Result { + println!("Protocol::english_name()"); + + Ok("Delta Chat".to_string()) + } + fn icon(&self) -> Result { + println!("Protocol::icon()"); + + Ok("im-delta".to_string()) + } + fn authentication_types(&self) -> Result, tree::MethodErr> { + println!("Protocol::authentication_types()"); + + Ok(vec![]) + } +}