Initial protocol implementation

Empathy needs this patch before it will display the settings:
https://gitlab.gnome.org/GNOME/telepathy-account-widgets/-/merge_requests/1
This commit is contained in:
2020-05-09 21:45:29 +01:00
parent c861f6fdd9
commit c643c42fa5
4 changed files with 188 additions and 93 deletions

View File

@@ -2,11 +2,10 @@
Name=padfoot Name=padfoot
BusName=org.freedesktop.Telepathy.ConnectionManager.padfoot BusName=org.freedesktop.Telepathy.ConnectionManager.padfoot
ObjectPath=/org/freedesktop/Telepathy/ConnectionManager/padfoot ObjectPath=/org/freedesktop/Telepathy/ConnectionManager/padfoot
Interfaces=
[Protocol delta] [Protocol delta]
param-account=s required param-account=s required
param-password=s required secret param-password=s required secret
Interfaces=
EnglishName=Delta Chat EnglishName=Delta Chat
VCardField=email
Icon=im-delta Icon=im-delta

View File

@@ -1,49 +1,44 @@
mod padfoot; mod padfoot;
mod telepathy; mod telepathy;
//use dbus::tree::{Interface, MTFn, MethodErr}; use anyhow::{anyhow, Result};
use dbus::{ use dbus::{
blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection}, blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection},
tree::{Factory, MTFn, Tree}, tree::Factory,
}; };
use padfoot::{ConnectionManager, Protocol};
use padfoot::{CMData, ConnectionManager};
use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use anyhow::{anyhow, Result};
const CM_BUS_NAME: &'static str = "org.freedesktop.Telepathy.ConnectionManager.padfoot"; const CM_BUS_NAME: &'static str = "org.freedesktop.Telepathy.ConnectionManager.padfoot";
const CM_OBJECT_PATH: &'static str = "/org/freedesktop/Telepathy/ConnectionManager/padfoot"; const CM_OBJECT_PATH: &'static str = "/org/freedesktop/Telepathy/ConnectionManager/padfoot";
const PROTO_OBJECT_PATH: &'static str =
fn create_tree(cm: &Arc<ConnectionManager>) -> Tree<MTFn<CMData>, CMData> { "/org/freedesktop/Telepathy/ConnectionManager/padfoot/delta";
let f = Factory::new_fn();
let mut tree = f.tree(());
let iface = telepathy::connection_manager_server(&f, (), |m| {
let a: &Arc<ConnectionManager> = 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
}
fn run() -> Result<()> { fn run() -> Result<()> {
let cm: ConnectionManager = ConnectionManager {}; let f = Factory::new_fn::<()>();
let tree = create_tree(&Arc::new(cm)); 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 // Setup DBus connection
let mut c = LocalConnection::new_session()?; let mut c = LocalConnection::new_session()?;
tree.start_receive(&c);
let result = c.request_name(CM_BUS_NAME, false, false, true)?; let result = c.request_name(CM_BUS_NAME, false, false, true)?;
match result { match result {
@@ -53,15 +48,11 @@ fn run() -> Result<()> {
CM_BUS_NAME 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 { loop {
c.process(Duration::from_secs(1))?; c.process(Duration::from_secs(1))?;
println!("Tick");
} }
} }

View File

@@ -2,89 +2,89 @@ use crate::telepathy;
use dbus::{arg, tree}; use dbus::{arg, tree};
use std::collections::HashMap; use std::collections::HashMap;
// FIXME: CM should take an opaque set of protocols to advertise
use super::protocol;
#[derive(Debug)] #[derive(Debug)]
pub struct ConnectionManager {} 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<ConnectionManager>;
}
const PROTO: &'static str = "delta";
pub type ParamSpec = (
String, // Name
u32, // Flags (Conn_Mgr_Param_Flags)
String, // Signature
arg::Variant<Box<dyn arg::RefArg + 'static>>, // Default
);
pub type Dict = HashMap<String, arg::Variant<Box<dyn arg::RefArg + 'static>>>;
// 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 { impl telepathy::ConnectionManager for ConnectionManager {
fn get_parameters(&self, protocol: &str) -> Result<Vec<ParamSpec>, tree::MethodErr> { fn get_parameters(&self, protocol: &str) -> Result<Vec<protocol::ParamSpec>, tree::MethodErr> {
println!("CM::get_parameters({})", protocol); println!("CM::get_parameters({})", protocol);
if protocol != PROTO { match protocol {
return Err(tree::MethodErr::no_arg()); // FIXME: should be NotImplemented? 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<Vec<String>, tree::MethodErr> { fn list_protocols(&self) -> Result<Vec<String>, tree::MethodErr> {
println!("CM::list_protocols()"); println!("CM::list_protocols()");
Ok(vec![PROTO.to_string()]) Ok(vec![protocol::NAME.to_string()])
} }
fn request_connection( fn request_connection(
&self, &self,
protocol: &str, protocol: &str,
parameters: HashMap<&str, arg::Variant<Box<dyn arg::RefArg>>>, parameters: HashMap<&str, protocol::Variant>,
) -> Result<(String, dbus::Path<'static>), tree::MethodErr> { ) -> Result<(String, dbus::Path<'static>), tree::MethodErr> {
println!("CM::request_connection({}, {:?})", protocol, parameters); println!("CM::request_connection({}, {:?})", protocol, parameters);
Err(tree::MethodErr::no_arg()) Err(tree::MethodErr::no_arg())
} }
fn protocols(&self) -> Result<HashMap<String, Dict>, tree::MethodErr> { fn protocols(
&self,
) -> Result<HashMap<String, HashMap<String, protocol::Variant>>, tree::MethodErr> {
println!("CM::protocols()"); println!("CM::protocols()");
// If this map is empty or missing, clients SHOULD fall back to // FIXME: so much duplication
// calling ListProtocols and GetParameters let mut out = HashMap::<String, HashMap<String, protocol::Variant>>::new();
Err(tree::MethodErr::no_arg()) let mut props = HashMap::<String, protocol::Variant>::new();
props.insert(
"org.freedesktop.Telepathy.Protocol.AuthenticationTypes".to_string(),
arg::Variant(Box::new(Vec::<String>::new())),
);
props.insert(
"org.freedesktop.Telepathy.Protocol.ConnectionInterfaces".to_string(),
arg::Variant(Box::new(Vec::<String>::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::<String>::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::<String>::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<Vec<String>, tree::MethodErr> { fn interfaces(&self) -> Result<Vec<String>, tree::MethodErr> {
println!("CM::interfaces()");
Ok(vec![]) Ok(vec![])
} }
} }

View File

@@ -1 +1,106 @@
use crate::telepathy;
use dbus::{arg, tree};
use std::collections::HashMap;
#[derive(Debug)]
pub struct Protocol {} pub struct Protocol {}
pub type ParamSpec = (
String, // Name
u32, // Flags (Conn_Mgr_Param_Flags)
String, // Signature
arg::Variant<Box<dyn arg::RefArg + 'static>>, // Default
);
pub type Variant = arg::Variant<Box<dyn arg::RefArg + 'static>>;
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<ParamSpec> {
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<String, tree::MethodErr> {
println!("Protocol::identify_account({:?})", params);
Err(tree::MethodErr::no_arg())
}
fn normalize_contact(&self, contact_id: &str) -> Result<String, tree::MethodErr> {
println!("Protocol::normalize_contact({})", contact_id);
Err(tree::MethodErr::no_arg())
}
fn interfaces(&self) -> Result<Vec<String>, tree::MethodErr> {
println!("Protocol::interfaces()");
Ok(vec![])
}
fn parameters(&self) -> Result<Vec<ParamSpec>, tree::MethodErr> {
println!("Protocol::parameters()");
Ok(parameters())
}
fn connection_interfaces(&self) -> Result<Vec<String>, tree::MethodErr> {
println!("Protocol::connection_interfaces()");
Ok(vec![])
}
fn requestable_channel_classes(
&self,
) -> Result<
Vec<(
::std::collections::HashMap<String, arg::Variant<Box<dyn arg::RefArg + 'static>>>,
Vec<String>,
)>,
tree::MethodErr,
> {
println!("Protocol::requestable_channel_classes()");
Ok(vec![])
}
fn vcard_field(&self) -> Result<String, tree::MethodErr> {
println!("Protocol::vcard_field()");
Ok("email".to_string())
}
fn english_name(&self) -> Result<String, tree::MethodErr> {
println!("Protocol::english_name()");
Ok("Delta Chat".to_string())
}
fn icon(&self) -> Result<String, tree::MethodErr> {
println!("Protocol::icon()");
Ok("im-delta".to_string())
}
fn authentication_types(&self) -> Result<Vec<String>, tree::MethodErr> {
println!("Protocol::authentication_types()");
Ok(vec![])
}
}