Split padfoot/connection.rs into multiple files
This commit is contained in:
@@ -31,6 +31,7 @@ Here's where we're at right now:
|
|||||||
- [x] Connect to deltachat-core-rust
|
- [x] Connect to deltachat-core-rust
|
||||||
- [x] Set up an account via autoconfiguration
|
- [x] Set up an account via autoconfiguration
|
||||||
- [x] Appear as online in Empathy
|
- [x] Appear as online in Empathy
|
||||||
|
- [~] Disconnect!
|
||||||
- [ ] Set up an account manually
|
- [ ] Set up an account manually
|
||||||
- [ ] Contacts handling
|
- [ ] Contacts handling
|
||||||
- [ ] Text messages
|
- [ ] Text messages
|
||||||
|
@@ -1,9 +1,26 @@
|
|||||||
|
mod avatars;
|
||||||
|
pub use self::avatars::*;
|
||||||
|
|
||||||
|
mod connection;
|
||||||
|
pub use self::connection::*;
|
||||||
|
|
||||||
|
mod contacts;
|
||||||
|
pub use self::contacts::*;
|
||||||
|
|
||||||
|
mod contact_list;
|
||||||
|
pub use self::contact_list::*;
|
||||||
|
|
||||||
|
mod requests;
|
||||||
|
pub use self::requests::*;
|
||||||
|
|
||||||
|
mod simple_presence;
|
||||||
|
pub use self::simple_presence::*;
|
||||||
|
|
||||||
use crate::telepathy;
|
use crate::telepathy;
|
||||||
use crate::telepathy::ConnectionInterfaceContacts;
|
|
||||||
use dbus::blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection};
|
use dbus::blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection};
|
||||||
use dbus::channel::Sender;
|
use dbus::channel::Sender;
|
||||||
use dbus::message::SignalArgs;
|
use dbus::tree::MethodErr;
|
||||||
use dbus::{arg, tree};
|
|
||||||
|
|
||||||
use dc::config::Config;
|
use dc::config::Config;
|
||||||
use dc::context::Context;
|
use dc::context::Context;
|
||||||
@@ -11,20 +28,11 @@ use dc::Event;
|
|||||||
use deltachat as dc;
|
use deltachat as dc;
|
||||||
|
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub const CONN_BUS_NAME: &'static str = "org.freedesktop.Telepathy.Connection.padfoot.delta";
|
pub const CONN_BUS_NAME: &str = "org.freedesktop.Telepathy.Connection.padfoot.delta";
|
||||||
pub const CONN_OBJECT_PATH: &'static str = "/org/freedesktop/Telepathy/Connection/padfoot/delta";
|
pub const CONN_OBJECT_PATH: &str = "/org/freedesktop/Telepathy/Connection/padfoot/delta";
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
enum ConnState {
|
|
||||||
Initial,
|
|
||||||
Connected,
|
|
||||||
Disconnected,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
// A Deltachast connection uses email addresses as handles, and delta's Db IDs
|
// A Deltachast connection uses email addresses as handles, and delta's Db IDs
|
||||||
@@ -38,26 +46,9 @@ pub struct Connection {
|
|||||||
msgq: Arc<Mutex<VecDeque<dbus::Message>>>,
|
msgq: Arc<Mutex<VecDeque<dbus::Message>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connection_interfaces() -> Vec<String> {
|
|
||||||
vec![
|
|
||||||
"org.freedesktop.Telepathy.Connection".to_string(),
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.Avatars".to_string(),
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.Contacts".to_string(),
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.ContactList".to_string(),
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.Requests".to_string(),
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.SimplePresence".to_string(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<dyn telepathy::Connection + 'static> for std::rc::Rc<Connection> {
|
|
||||||
fn as_ref(&self) -> &(dyn telepathy::Connection + 'static) {
|
|
||||||
&**self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
pub fn new(params: HashMap<&str, super::Variant>) -> Result<Self, dbus::tree::MethodErr> {
|
pub fn new(params: HashMap<&str, super::Variant>) -> Result<Self, MethodErr> {
|
||||||
let err = Err(dbus::tree::MethodErr::no_arg());
|
let err = Err(MethodErr::no_arg());
|
||||||
|
|
||||||
let acct = match params.get("account") {
|
let acct = match params.get("account") {
|
||||||
Some(variant) => match variant.0.as_str() {
|
Some(variant) => match variant.0.as_str() {
|
||||||
@@ -78,7 +69,7 @@ impl Connection {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut dbfile = directories::ProjectDirs::from("gs", "ur", "telepathy-padfoot")
|
let mut dbfile = directories::ProjectDirs::from("gs", "ur", "telepathy-padfoot")
|
||||||
.ok_or_else(|| tree::MethodErr::no_arg())
|
.ok_or(MethodErr::no_arg())
|
||||||
.and_then(|p| Ok(p.data_local_dir().to_path_buf()))?;
|
.and_then(|p| Ok(p.data_local_dir().to_path_buf()))?;
|
||||||
|
|
||||||
dbfile.push(&id);
|
dbfile.push(&id);
|
||||||
@@ -130,22 +121,22 @@ impl Connection {
|
|||||||
let ctx =
|
let ctx =
|
||||||
Context::new(Box::new(f), "telepathy-padfoot".to_string(), dbfile).map_err(|e| {
|
Context::new(Box::new(f), "telepathy-padfoot".to_string(), dbfile).map_err(|e| {
|
||||||
println!("Connection<{}>: couldn't get delta context: {}", id, e);
|
println!("Connection<{}>: couldn't get delta context: {}", id, e);
|
||||||
tree::MethodErr::no_arg() // FIXME: better error handling
|
MethodErr::no_arg() // FIXME: better error handling
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
ctx.set_config(Config::Addr, Some(&acct))
|
ctx.set_config(Config::Addr, Some(&acct))
|
||||||
.map_err(|_e| tree::MethodErr::no_arg())?;
|
.map_err(|_e| MethodErr::no_arg())?;
|
||||||
ctx.set_config(Config::MailPw, Some(&password))
|
ctx.set_config(Config::MailPw, Some(&password))
|
||||||
.map_err(|_e| tree::MethodErr::no_arg())?;
|
.map_err(|_e| MethodErr::no_arg())?;
|
||||||
ctx.set_config(Config::SentboxWatch, Some(&"Sent"))
|
ctx.set_config(Config::SentboxWatch, Some(&"Sent"))
|
||||||
.map_err(|_e| tree::MethodErr::no_arg())?;
|
.map_err(|_e| MethodErr::no_arg())?;
|
||||||
|
|
||||||
if !ctx.is_configured() {
|
if !ctx.is_configured() {
|
||||||
ctx.configure();
|
ctx.configure();
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Connection {
|
Ok(Connection {
|
||||||
id: id,
|
id,
|
||||||
ctx: Arc::new(RwLock::new(ctx)),
|
ctx: Arc::new(RwLock::new(ctx)),
|
||||||
state: Arc::new(RwLock::new(ConnState::Initial)),
|
state: Arc::new(RwLock::new(ConnState::Initial)),
|
||||||
msgq: msgq.clone(),
|
msgq: msgq.clone(),
|
||||||
@@ -164,7 +155,7 @@ impl Connection {
|
|||||||
let id = self.id.clone();
|
let id = self.id.clone();
|
||||||
let c_rc = std::rc::Rc::new(self);
|
let c_rc = std::rc::Rc::new(self);
|
||||||
|
|
||||||
let f = tree::Factory::new_fn::<()>();
|
let f = dbus::tree::Factory::new_fn::<()>();
|
||||||
let mut tree = f.tree(());
|
let mut tree = f.tree(());
|
||||||
|
|
||||||
let c_rc1 = c_rc.clone();
|
let c_rc1 = c_rc.clone();
|
||||||
@@ -228,12 +219,10 @@ impl Connection {
|
|||||||
// Set up delta jobs last in case registering to DBUS fails
|
// Set up delta jobs last in case registering to DBUS fails
|
||||||
// "Borrowed" from https://github.com/deltachat/deltachat-core-rust/blob/master/examples/simple.rs
|
// "Borrowed" from https://github.com/deltachat/deltachat-core-rust/blob/master/examples/simple.rs
|
||||||
while *state.read().unwrap() != ConnState::Disconnected {
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
match c.process(Duration::from_millis(100)) {
|
if let Err(e) = c.process(Duration::from_millis(100)) {
|
||||||
Err(e) => {
|
println!("Error processing: {}", e);
|
||||||
println!("Error processing: {}", e);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spend a bit of time sending any outgoing messages - signals, mostly
|
// Spend a bit of time sending any outgoing messages - signals, mostly
|
||||||
@@ -264,655 +253,6 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl telepathy::Connection for Connection {
|
|
||||||
// In connect(), we start the threads that drive the deltachat context
|
|
||||||
fn connect(&self) -> Result<(), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::connect()", self.id);
|
|
||||||
|
|
||||||
let inbox_ctx = self.ctx.clone();
|
|
||||||
let state = self.state.clone();
|
|
||||||
let id = self.id.clone();
|
|
||||||
let _inbox_thread = thread::spawn(move || {
|
|
||||||
while *state.read().unwrap() != ConnState::Disconnected {
|
|
||||||
dc::job::perform_inbox_jobs(&inbox_ctx.read().unwrap());
|
|
||||||
if *state.read().unwrap() != ConnState::Disconnected {
|
|
||||||
dc::job::perform_inbox_fetch(&inbox_ctx.read().unwrap());
|
|
||||||
|
|
||||||
if *state.read().unwrap() != ConnState::Disconnected {
|
|
||||||
dc::job::perform_inbox_idle(&inbox_ctx.read().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Connection<{}>::connect(): inbox thread exited", id);
|
|
||||||
});
|
|
||||||
|
|
||||||
let smtp_ctx = self.ctx.clone();
|
|
||||||
let state = self.state.clone();
|
|
||||||
let id = self.id.clone();
|
|
||||||
let _smtp_thread = thread::spawn(move || {
|
|
||||||
while *state.read().unwrap() != ConnState::Disconnected {
|
|
||||||
dc::job::perform_smtp_jobs(&smtp_ctx.read().unwrap());
|
|
||||||
if *state.read().unwrap() != ConnState::Disconnected {
|
|
||||||
dc::job::perform_smtp_idle(&smtp_ctx.read().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Connection<{}>::connect(): smtp thread exited", id);
|
|
||||||
});
|
|
||||||
|
|
||||||
let mvbox_ctx = self.ctx.clone();
|
|
||||||
let state = self.state.clone();
|
|
||||||
let id = self.id.clone();
|
|
||||||
let _mvbox_thread = thread::spawn(move || {
|
|
||||||
while *state.read().unwrap() != ConnState::Disconnected {
|
|
||||||
dc::job::perform_mvbox_fetch(&mvbox_ctx.read().unwrap());
|
|
||||||
if *state.read().unwrap() != ConnState::Disconnected {
|
|
||||||
dc::job::perform_mvbox_idle(&mvbox_ctx.read().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Connection<{}>::connect(): mvbox thread exited", id);
|
|
||||||
});
|
|
||||||
|
|
||||||
let sentbox_ctx = self.ctx.clone();
|
|
||||||
let state = self.state.clone();
|
|
||||||
let id = self.id.clone();
|
|
||||||
let _sentbox_thread = thread::spawn(move || {
|
|
||||||
while *state.read().unwrap() != ConnState::Disconnected {
|
|
||||||
dc::job::perform_sentbox_fetch(&sentbox_ctx.read().unwrap());
|
|
||||||
if *state.read().unwrap() != ConnState::Disconnected {
|
|
||||||
dc::job::perform_sentbox_idle(&sentbox_ctx.read().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Connection<{}>::connect(): sentbox thread exited", id);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Just pretend to be connected all the time for now. Tracking IMAP+SMTP
|
|
||||||
// state is a pain
|
|
||||||
let state = self.state.clone();
|
|
||||||
let mut w = state.write().unwrap();
|
|
||||||
*w = ConnState::Connected;
|
|
||||||
|
|
||||||
// Emit a StatusChanged signal for the benefit of others, but the caller
|
|
||||||
// learns from our RPC response
|
|
||||||
let sig = telepathy::ConnectionStatusChanged {
|
|
||||||
status: 0, // Connected
|
|
||||||
reason: 1, // Requested
|
|
||||||
};
|
|
||||||
|
|
||||||
let dbus_conn_path = dbus::strings::Path::new(self.path().to_string())
|
|
||||||
.expect("Object path should meet DBUS requirements");
|
|
||||||
|
|
||||||
self.msgq
|
|
||||||
.clone()
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.push_back(sig.to_emit_message(&dbus_conn_path));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disconnect(&self) -> Result<(), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::disconnect()", self.id);
|
|
||||||
|
|
||||||
let state = self.state.clone();
|
|
||||||
let mut w = state.write().unwrap();
|
|
||||||
*w = ConnState::Disconnected;
|
|
||||||
|
|
||||||
// FIXME: we need to signal to the CM that they should remove the
|
|
||||||
// connection from the active list
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn interfaces(&self) -> Result<Vec<String>, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::interfaces()", self.id);
|
|
||||||
|
|
||||||
self.get_interfaces()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_interfaces(&self) -> Result<Vec<String>, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::get_interfaces()", self.id);
|
|
||||||
|
|
||||||
Ok(connection_interfaces())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_protocol(&self) -> Result<String, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::get_protocol()", self.id);
|
|
||||||
|
|
||||||
Ok(super::PROTO_NAME.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_handle(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::self_handle()", self.id);
|
|
||||||
|
|
||||||
self.get_self_handle()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_self_handle(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::get_self_handle()", self.id);
|
|
||||||
|
|
||||||
Ok(dc::constants::DC_CONTACT_ID_SELF)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn status(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::status()", self.id);
|
|
||||||
|
|
||||||
self.get_status()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_status(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
match *self.state.clone().read().unwrap() {
|
|
||||||
ConnState::Initial | ConnState::Disconnected => Ok(2),
|
|
||||||
ConnState::Connected => Ok(0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hold_handles(&self, handle_type: u32, handles: Vec<u32>) -> Result<(), tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::hold_handles({}, {:?})",
|
|
||||||
self.id, handle_type, handles
|
|
||||||
);
|
|
||||||
|
|
||||||
// Since HasImmortalHandles is true, this doesn't need to do anything
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inspect_handles(
|
|
||||||
&self,
|
|
||||||
handle_type: u32,
|
|
||||||
handles: Vec<u32>,
|
|
||||||
) -> Result<Vec<String>, tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::inspect_handles({}, {:?})",
|
|
||||||
self.id, handle_type, handles
|
|
||||||
);
|
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list_channels(
|
|
||||||
&self,
|
|
||||||
) -> Result<Vec<(dbus::Path<'static>, String, u32, u32)>, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::list_channels()", self.id);
|
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn release_handles(&self, handle_type: u32, handles: Vec<u32>) -> Result<(), tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::release_handles({}, {:?})",
|
|
||||||
self.id, handle_type, handles
|
|
||||||
);
|
|
||||||
|
|
||||||
// Since HasImmortalHandles is true, we don't need to do anything
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_channel(
|
|
||||||
&self,
|
|
||||||
type_: &str,
|
|
||||||
handle_type: u32,
|
|
||||||
handle: u32,
|
|
||||||
suppress_handler: bool,
|
|
||||||
) -> Result<dbus::Path<'static>, tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::request_channel({}, {}, {}, {})",
|
|
||||||
self.id, type_, handle_type, handle, suppress_handler
|
|
||||||
);
|
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_handles(
|
|
||||||
&self,
|
|
||||||
handle_type: u32,
|
|
||||||
identifiers: Vec<&str>,
|
|
||||||
) -> Result<Vec<u32>, tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::request_handles({}, {:?})",
|
|
||||||
self.id, handle_type, identifiers
|
|
||||||
);
|
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_client_interest(&self, tokens: Vec<&str>) -> Result<(), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::add_client_interest({:?})", self.id, tokens);
|
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_client_interest(&self, tokens: Vec<&str>) -> Result<(), tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::remove_client_interest({:?})",
|
|
||||||
self.id, tokens
|
|
||||||
);
|
|
||||||
Err(tree::MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_id(&self) -> Result<String, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::self_id()", self.id);
|
|
||||||
|
|
||||||
let contact = match dc::contact::Contact::get_by_id(
|
|
||||||
&self.ctx.read().unwrap(),
|
|
||||||
dc::constants::DC_CONTACT_ID_SELF,
|
|
||||||
) {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
|
||||||
println!(" err: {}", e);
|
|
||||||
return Err(tree::MethodErr::no_arg());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(contact.get_addr().to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_immortal_handles(&self) -> Result<bool, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::has_immortal_handles()", self.id);
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<dyn telepathy::ConnectionInterfaceAvatars + 'static> for std::rc::Rc<Connection> {
|
|
||||||
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceAvatars + 'static) {
|
|
||||||
&**self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: come back and do this properly, I'm just putting it in for consistency
|
|
||||||
impl telepathy::ConnectionInterfaceAvatars for Connection {
|
|
||||||
fn get_avatar_requirements(
|
|
||||||
&self,
|
|
||||||
) -> Result<(Vec<String>, u16, u16, u16, u16, u32), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::get_avatar_requirements()", self.id);
|
|
||||||
Ok((vec![], 0, 0, 0, 0, 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_avatar_tokens(&self, contacts: Vec<u32>) -> Result<Vec<String>, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::get_avatar_tokens({:?})", self.id, contacts);
|
|
||||||
Ok(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_known_avatar_tokens(
|
|
||||||
&self,
|
|
||||||
contacts: Vec<u32>,
|
|
||||||
) -> Result<::std::collections::HashMap<u32, String>, tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::get_known_avatar_tokens({:?})",
|
|
||||||
self.id, contacts
|
|
||||||
);
|
|
||||||
Ok(HashMap::<u32, String>::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_avatar(&self, contact: u32) -> Result<(Vec<u8>, String), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::request_avatar({})", self.id, contact);
|
|
||||||
Ok((vec![], "".to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_avatars(&self, contacts: Vec<u32>) -> Result<(), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::request_avatar({:?})", self.id, contacts);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_avatar(&self, _avatar: Vec<u8>, mimetype: &str) -> Result<String, tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::set_avatar((data), {:?})",
|
|
||||||
self.id, mimetype
|
|
||||||
);
|
|
||||||
Ok("".to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_avatar(&self) -> Result<(), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::clear_avatar()", self.id);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supported_avatar_mimetypes(&self) -> Result<Vec<String>, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::supported_avatar_mimetypes()", self.id);
|
|
||||||
Ok(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn minimum_avatar_height(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::minimum_avatar_height()", self.id);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn minimum_avatar_width(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::minimum_avatar_width()", self.id);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recommended_avatar_height(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::recommended_avatar_height()", self.id);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recommended_avatar_width(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::recommended_avatar_width()", self.id);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn maximum_avatar_height(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::maximum_avatar_height()", self.id);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn maximum_avatar_width(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::maximum_avatar_width()", self.id);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn maximum_avatar_bytes(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::maximum_avatar_bytes()", self.id);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<dyn telepathy::ConnectionInterfaceContacts + 'static> for std::rc::Rc<Connection> {
|
|
||||||
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceContacts + 'static) {
|
|
||||||
&**self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl telepathy::ConnectionInterfaceContacts for Connection {
|
|
||||||
fn get_contact_attributes(
|
|
||||||
&self,
|
|
||||||
handles: Vec<u32>,
|
|
||||||
interfaces: Vec<&str>,
|
|
||||||
hold: bool,
|
|
||||||
) -> Result<HashMap<u32, HashMap<String, super::Variant>>, tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::get_contact_attributes({:?}, {:?}, {})",
|
|
||||||
self.id, handles, interfaces, hold
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut out = HashMap::<u32, HashMap<String, super::Variant>>::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, // Invalid IDs are silently ignored
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut props = HashMap::<String, super::Variant>::new();
|
|
||||||
// This is mandatory
|
|
||||||
props.insert(
|
|
||||||
"org.freedesktop.Telepathy.Connection/contact-id".to_string(),
|
|
||||||
arg::Variant(Box::new(contact.get_addr().to_string())),
|
|
||||||
);
|
|
||||||
|
|
||||||
// The empty string means "no avatar"
|
|
||||||
props.insert(
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.Avatars/token".to_string(),
|
|
||||||
arg::Variant(Box::new("".to_string())),
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: we need to publish DBUS services on these endpoints
|
|
||||||
props.insert(
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.ContactList/publish".to_string(),
|
|
||||||
arg::Variant(Box::new(4)),
|
|
||||||
);
|
|
||||||
|
|
||||||
props.insert(
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.ContactList/subscribe".to_string(),
|
|
||||||
arg::Variant(Box::new(4)),
|
|
||||||
);
|
|
||||||
|
|
||||||
out.insert(*id, props);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_contact_by_id(
|
|
||||||
&self,
|
|
||||||
identifier: &str,
|
|
||||||
interfaces: Vec<&str>,
|
|
||||||
) -> Result<
|
|
||||||
(
|
|
||||||
u32,
|
|
||||||
::std::collections::HashMap<String, arg::Variant<Box<dyn arg::RefArg + 'static>>>,
|
|
||||||
),
|
|
||||||
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<Vec<String>, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::contact_attribute_interfaces()", self.id);
|
|
||||||
|
|
||||||
Ok(vec![
|
|
||||||
"org.freedesktop.Telepathy.Connection".to_string(),
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.Avatars".to_string(),
|
|
||||||
"org.freedesktop.Telepathy.Connection.Interface.ContactList".to_string(),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<dyn telepathy::ConnectionInterfaceContactList + 'static> for std::rc::Rc<Connection> {
|
|
||||||
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceContactList + 'static) {
|
|
||||||
&**self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: come back and do this properly later
|
|
||||||
impl telepathy::ConnectionInterfaceContactList for Connection {
|
|
||||||
fn get_contact_list_attributes(
|
|
||||||
&self,
|
|
||||||
interfaces: Vec<&str>,
|
|
||||||
hold: bool,
|
|
||||||
) -> Result<HashMap<u32, HashMap<String, super::Variant>>, tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::get_contact_list_attributes({:?}, {})",
|
|
||||||
self.id, interfaces, hold
|
|
||||||
);
|
|
||||||
|
|
||||||
let ids = match dc::contact::Contact::get_all(
|
|
||||||
&self.ctx.read().unwrap(),
|
|
||||||
dc::constants::DC_GCL_ADD_SELF.try_into().unwrap(),
|
|
||||||
None::<String>,
|
|
||||||
) {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
|
||||||
println!(" err: {}", e);
|
|
||||||
return Err(tree::MethodErr::no_arg());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.get_contact_attributes(ids, vec![], true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_subscription(
|
|
||||||
&self,
|
|
||||||
contacts: Vec<u32>,
|
|
||||||
message: &str,
|
|
||||||
) -> Result<(), tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::request_subscription({:?}, {})",
|
|
||||||
self.id, contacts, message
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn authorize_publication(&self, contacts: Vec<u32>) -> Result<(), tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::authorize_publication({:?})",
|
|
||||||
self.id, contacts
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn remove_contacts(&self, contacts: Vec<u32>) -> Result<(), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::remove_contacts({:?})", self.id, contacts);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn unsubscribe(&self, contacts: Vec<u32>) -> Result<(), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::unsubscribe({:?})", self.id, contacts);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unpublish(&self, contacts: Vec<u32>) -> Result<(), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::unpublish({:?})", self.id, contacts);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn download(&self) -> Result<(), tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::download()", self.id);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contact_list_state(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::contact_list_state()", self.id);
|
|
||||||
Ok(3) // Success
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contact_list_persists(&self) -> Result<bool, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::contact_list_persists()", self.id);
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_change_contact_list(&self) -> Result<bool, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::can_change_contact_list()", self.id);
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
fn request_uses_message(&self) -> Result<bool, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::request_uses_message()", self.id);
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn download_at_connection(&self) -> Result<bool, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::download_at_connection()", self.id);
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<dyn telepathy::ConnectionInterfaceRequests + 'static> for std::rc::Rc<Connection> {
|
|
||||||
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceRequests + 'static) {
|
|
||||||
&**self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl telepathy::ConnectionInterfaceRequests for Connection {
|
|
||||||
fn create_channel(
|
|
||||||
&self,
|
|
||||||
request: ::std::collections::HashMap<&str, arg::Variant<Box<dyn arg::RefArg>>>,
|
|
||||||
) -> Result<
|
|
||||||
(
|
|
||||||
dbus::Path<'static>,
|
|
||||||
::std::collections::HashMap<String, arg::Variant<Box<dyn arg::RefArg + 'static>>>,
|
|
||||||
),
|
|
||||||
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<Box<dyn arg::RefArg>>>,
|
|
||||||
) -> Result<
|
|
||||||
(
|
|
||||||
bool,
|
|
||||||
dbus::Path<'static>,
|
|
||||||
::std::collections::HashMap<String, arg::Variant<Box<dyn arg::RefArg + 'static>>>,
|
|
||||||
),
|
|
||||||
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<String, arg::Variant<Box<dyn arg::RefArg + 'static>>>,
|
|
||||||
)>,
|
|
||||||
tree::MethodErr,
|
|
||||||
> {
|
|
||||||
println!("Connection<{}>::channels()", self.id);
|
|
||||||
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!("Connection<{}>::requestable_channel_classes()", self.id);
|
|
||||||
Ok(super::requestables())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type SimplePresenceSpec = (
|
|
||||||
u32, // connection presence type
|
|
||||||
String, // status
|
|
||||||
String, // status message
|
|
||||||
);
|
|
||||||
|
|
||||||
pub type SimpleStatusSpec = (
|
|
||||||
u32, // connection presence type
|
|
||||||
bool, // may set on self?
|
|
||||||
bool, // can have message?
|
|
||||||
);
|
|
||||||
|
|
||||||
impl AsRef<dyn telepathy::ConnectionInterfaceSimplePresence + 'static> for std::rc::Rc<Connection> {
|
|
||||||
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceSimplePresence + 'static) {
|
|
||||||
&**self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl telepathy::ConnectionInterfaceSimplePresence for Connection {
|
|
||||||
fn set_presence(&self, status: &str, status_message: &str) -> Result<(), tree::MethodErr> {
|
|
||||||
println!(
|
|
||||||
"Connection<{}>::set_presence({}, {:?})",
|
|
||||||
self.id, status, status_message
|
|
||||||
);
|
|
||||||
|
|
||||||
// FIXME: emit a presence changed signal
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_presences(
|
|
||||||
&self,
|
|
||||||
contacts: Vec<u32>,
|
|
||||||
) -> Result<HashMap<u32, SimplePresenceSpec>, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::get_presences({:?})", self.id, contacts);
|
|
||||||
|
|
||||||
let mut out = HashMap::<u32, SimplePresenceSpec>::new();
|
|
||||||
|
|
||||||
for id in contacts {
|
|
||||||
out.insert(id, (2, "available".to_string(), "".to_string())); // Available
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn statuses(&self) -> Result<HashMap<String, SimpleStatusSpec>, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::statuses()", self.id);
|
|
||||||
|
|
||||||
let mut out = HashMap::<String, SimpleStatusSpec>::new();
|
|
||||||
|
|
||||||
out.insert("available".to_string(), (2, true, false));
|
|
||||||
out.insert("offline".to_string(), (1, true, false));
|
|
||||||
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn maximum_status_message_length(&self) -> Result<u32, tree::MethodErr> {
|
|
||||||
println!("Connection<{}>::maximum_status_message_length()", self.id);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn escape_one(b: u8) -> String {
|
fn escape_one(b: u8) -> String {
|
||||||
format!("_{:0<2x}", b)
|
format!("_{:0<2x}", b)
|
||||||
}
|
}
|
||||||
@@ -920,7 +260,7 @@ fn escape_one(b: u8) -> String {
|
|||||||
// Some non-empty sequence of ASCII letters, digits and underscores
|
// Some non-empty sequence of ASCII letters, digits and underscores
|
||||||
fn escape(s: String) -> String {
|
fn escape(s: String) -> String {
|
||||||
// Special-case the empty string
|
// Special-case the empty string
|
||||||
if s.len() == 0 {
|
if s.is_empty() {
|
||||||
return "_".to_string();
|
return "_".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
99
src/padfoot/connection/avatars.rs
Normal file
99
src/padfoot/connection/avatars.rs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
use crate::telepathy;
|
||||||
|
|
||||||
|
use dbus::tree::MethodErr;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::Connection;
|
||||||
|
|
||||||
|
impl AsRef<dyn telepathy::ConnectionInterfaceAvatars + 'static> for std::rc::Rc<Connection> {
|
||||||
|
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceAvatars + 'static) {
|
||||||
|
&**self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: come back and do this properly, I'm just putting it in for consistency
|
||||||
|
impl telepathy::ConnectionInterfaceAvatars for Connection {
|
||||||
|
fn get_avatar_requirements(&self) -> Result<(Vec<String>, u16, u16, u16, u16, u32), MethodErr> {
|
||||||
|
println!("Connection<{}>::get_avatar_requirements()", self.id);
|
||||||
|
Ok((vec![], 0, 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_avatar_tokens(&self, contacts: Vec<u32>) -> Result<Vec<String>, MethodErr> {
|
||||||
|
println!("Connection<{}>::get_avatar_tokens({:?})", self.id, contacts);
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_known_avatar_tokens(
|
||||||
|
&self,
|
||||||
|
contacts: Vec<u32>,
|
||||||
|
) -> Result<::std::collections::HashMap<u32, String>, MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::get_known_avatar_tokens({:?})",
|
||||||
|
self.id, contacts
|
||||||
|
);
|
||||||
|
Ok(HashMap::<u32, String>::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_avatar(&self, contact: u32) -> Result<(Vec<u8>, String), MethodErr> {
|
||||||
|
println!("Connection<{}>::request_avatar({})", self.id, contact);
|
||||||
|
Ok((vec![], "".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_avatars(&self, contacts: Vec<u32>) -> Result<(), MethodErr> {
|
||||||
|
println!("Connection<{}>::request_avatar({:?})", self.id, contacts);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_avatar(&self, _avatar: Vec<u8>, mimetype: &str) -> Result<String, MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::set_avatar((data), {:?})",
|
||||||
|
self.id, mimetype
|
||||||
|
);
|
||||||
|
Ok("".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_avatar(&self) -> Result<(), MethodErr> {
|
||||||
|
println!("Connection<{}>::clear_avatar()", self.id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supported_avatar_mimetypes(&self) -> Result<Vec<String>, MethodErr> {
|
||||||
|
println!("Connection<{}>::supported_avatar_mimetypes()", self.id);
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minimum_avatar_height(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::minimum_avatar_height()", self.id);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minimum_avatar_width(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::minimum_avatar_width()", self.id);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recommended_avatar_height(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::recommended_avatar_height()", self.id);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recommended_avatar_width(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::recommended_avatar_width()", self.id);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maximum_avatar_height(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::maximum_avatar_height()", self.id);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maximum_avatar_width(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::maximum_avatar_width()", self.id);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maximum_avatar_bytes(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::maximum_avatar_bytes()", self.id);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
277
src/padfoot/connection/connection.rs
Normal file
277
src/padfoot/connection/connection.rs
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
use crate::telepathy;
|
||||||
|
|
||||||
|
use dbus::message::SignalArgs;
|
||||||
|
use dbus::tree::MethodErr;
|
||||||
|
use deltachat as dc;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
use super::Connection;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum ConnState {
|
||||||
|
Initial,
|
||||||
|
Connected,
|
||||||
|
Disconnected,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connection_interfaces() -> Vec<String> {
|
||||||
|
vec![
|
||||||
|
"org.freedesktop.Telepathy.Connection".to_string(),
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.Avatars".to_string(),
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.Contacts".to_string(),
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.ContactList".to_string(),
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.Requests".to_string(),
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.SimplePresence".to_string(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<dyn telepathy::Connection + 'static> for std::rc::Rc<Connection> {
|
||||||
|
fn as_ref(&self) -> &(dyn telepathy::Connection + 'static) {
|
||||||
|
&**self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl telepathy::Connection for Connection {
|
||||||
|
// In connect(), we start the threads that drive the deltachat context
|
||||||
|
fn connect(&self) -> Result<(), MethodErr> {
|
||||||
|
println!("Connection<{}>::connect()", self.id);
|
||||||
|
|
||||||
|
let inbox_ctx = self.ctx.clone();
|
||||||
|
let state = self.state.clone();
|
||||||
|
let id = self.id.clone();
|
||||||
|
let _inbox_thread = thread::spawn(move || {
|
||||||
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
|
dc::job::perform_inbox_jobs(&inbox_ctx.read().unwrap());
|
||||||
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
|
dc::job::perform_inbox_fetch(&inbox_ctx.read().unwrap());
|
||||||
|
|
||||||
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
|
dc::job::perform_inbox_idle(&inbox_ctx.read().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Connection<{}>::connect(): inbox thread exited", id);
|
||||||
|
});
|
||||||
|
|
||||||
|
let smtp_ctx = self.ctx.clone();
|
||||||
|
let state = self.state.clone();
|
||||||
|
let id = self.id.clone();
|
||||||
|
let _smtp_thread = thread::spawn(move || {
|
||||||
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
|
dc::job::perform_smtp_jobs(&smtp_ctx.read().unwrap());
|
||||||
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
|
dc::job::perform_smtp_idle(&smtp_ctx.read().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Connection<{}>::connect(): smtp thread exited", id);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mvbox_ctx = self.ctx.clone();
|
||||||
|
let state = self.state.clone();
|
||||||
|
let id = self.id.clone();
|
||||||
|
let _mvbox_thread = thread::spawn(move || {
|
||||||
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
|
dc::job::perform_mvbox_fetch(&mvbox_ctx.read().unwrap());
|
||||||
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
|
dc::job::perform_mvbox_idle(&mvbox_ctx.read().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Connection<{}>::connect(): mvbox thread exited", id);
|
||||||
|
});
|
||||||
|
|
||||||
|
let sentbox_ctx = self.ctx.clone();
|
||||||
|
let state = self.state.clone();
|
||||||
|
let id = self.id.clone();
|
||||||
|
let _sentbox_thread = thread::spawn(move || {
|
||||||
|
while *state.read().unwrap() != ConnState::Disconnected {
|
||||||
|
dc::job::perform_sentbox_fetch(&sentbox_ctx.read().unwrap());
|
||||||
|
if *state.read().unwrap() != ConnState::Disconnected {
|
||||||
|
dc::job::perform_sentbox_idle(&sentbox_ctx.read().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Connection<{}>::connect(): sentbox thread exited", id);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Just pretend to be connected all the time for now. Tracking IMAP+SMTP
|
||||||
|
// state is a pain
|
||||||
|
let state = self.state.clone();
|
||||||
|
let mut w = state.write().unwrap();
|
||||||
|
*w = ConnState::Connected;
|
||||||
|
|
||||||
|
// Emit a StatusChanged signal for the benefit of others, but the caller
|
||||||
|
// learns from our RPC response
|
||||||
|
let sig = telepathy::ConnectionStatusChanged {
|
||||||
|
status: 0, // Connected
|
||||||
|
reason: 1, // Requested
|
||||||
|
};
|
||||||
|
|
||||||
|
let dbus_conn_path = dbus::strings::Path::new(self.path())
|
||||||
|
.expect("Object path should meet DBUS requirements");
|
||||||
|
|
||||||
|
self.msgq
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push_back(sig.to_emit_message(&dbus_conn_path));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disconnect(&self) -> Result<(), MethodErr> {
|
||||||
|
println!("Connection<{}>::disconnect()", self.id);
|
||||||
|
|
||||||
|
let state = self.state.clone();
|
||||||
|
let mut w = state.write().unwrap();
|
||||||
|
*w = ConnState::Disconnected;
|
||||||
|
|
||||||
|
// FIXME: we need to signal to the CM that they should remove the
|
||||||
|
// connection from the active list
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interfaces(&self) -> Result<Vec<String>, MethodErr> {
|
||||||
|
println!("Connection<{}>::interfaces()", self.id);
|
||||||
|
|
||||||
|
self.get_interfaces()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_interfaces(&self) -> Result<Vec<String>, MethodErr> {
|
||||||
|
println!("Connection<{}>::get_interfaces()", self.id);
|
||||||
|
|
||||||
|
Ok(connection_interfaces())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_protocol(&self) -> Result<String, MethodErr> {
|
||||||
|
println!("Connection<{}>::get_protocol()", self.id);
|
||||||
|
|
||||||
|
Ok(crate::padfoot::PROTO_NAME.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn self_handle(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::self_handle()", self.id);
|
||||||
|
|
||||||
|
self.get_self_handle()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_self_handle(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::get_self_handle()", self.id);
|
||||||
|
|
||||||
|
Ok(dc::constants::DC_CONTACT_ID_SELF)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::status()", self.id);
|
||||||
|
|
||||||
|
self.get_status()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_status(&self) -> Result<u32, MethodErr> {
|
||||||
|
match *self.state.clone().read().unwrap() {
|
||||||
|
ConnState::Initial | ConnState::Disconnected => Ok(2),
|
||||||
|
ConnState::Connected => Ok(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hold_handles(&self, handle_type: u32, handles: Vec<u32>) -> Result<(), MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::hold_handles({}, {:?})",
|
||||||
|
self.id, handle_type, handles
|
||||||
|
);
|
||||||
|
|
||||||
|
// Since HasImmortalHandles is true, this doesn't need to do anything
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inspect_handles(
|
||||||
|
&self,
|
||||||
|
handle_type: u32,
|
||||||
|
handles: Vec<u32>,
|
||||||
|
) -> Result<Vec<String>, MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::inspect_handles({}, {:?})",
|
||||||
|
self.id, handle_type, handles
|
||||||
|
);
|
||||||
|
Err(MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_channels(&self) -> Result<Vec<(dbus::Path<'static>, String, u32, u32)>, MethodErr> {
|
||||||
|
println!("Connection<{}>::list_channels()", self.id);
|
||||||
|
Err(MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release_handles(&self, handle_type: u32, handles: Vec<u32>) -> Result<(), MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::release_handles({}, {:?})",
|
||||||
|
self.id, handle_type, handles
|
||||||
|
);
|
||||||
|
|
||||||
|
// Since HasImmortalHandles is true, we don't need to do anything
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_channel(
|
||||||
|
&self,
|
||||||
|
type_: &str,
|
||||||
|
handle_type: u32,
|
||||||
|
handle: u32,
|
||||||
|
suppress_handler: bool,
|
||||||
|
) -> Result<dbus::Path<'static>, MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::request_channel({}, {}, {}, {})",
|
||||||
|
self.id, type_, handle_type, handle, suppress_handler
|
||||||
|
);
|
||||||
|
Err(MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_handles(
|
||||||
|
&self,
|
||||||
|
handle_type: u32,
|
||||||
|
identifiers: Vec<&str>,
|
||||||
|
) -> Result<Vec<u32>, MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::request_handles({}, {:?})",
|
||||||
|
self.id, handle_type, identifiers
|
||||||
|
);
|
||||||
|
Err(MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_client_interest(&self, tokens: Vec<&str>) -> Result<(), MethodErr> {
|
||||||
|
println!("Connection<{}>::add_client_interest({:?})", self.id, tokens);
|
||||||
|
Err(MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_client_interest(&self, tokens: Vec<&str>) -> Result<(), MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::remove_client_interest({:?})",
|
||||||
|
self.id, tokens
|
||||||
|
);
|
||||||
|
Err(MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn self_id(&self) -> Result<String, MethodErr> {
|
||||||
|
println!("Connection<{}>::self_id()", self.id);
|
||||||
|
|
||||||
|
let contact = match dc::contact::Contact::get_by_id(
|
||||||
|
&self.ctx.read().unwrap(),
|
||||||
|
dc::constants::DC_CONTACT_ID_SELF,
|
||||||
|
) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
println!(" err: {}", e);
|
||||||
|
return Err(MethodErr::no_arg());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(contact.get_addr().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_immortal_handles(&self) -> Result<bool, MethodErr> {
|
||||||
|
println!("Connection<{}>::has_immortal_handles()", self.id);
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
103
src/padfoot/connection/contact_list.rs
Normal file
103
src/padfoot/connection/contact_list.rs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
use crate::telepathy;
|
||||||
|
|
||||||
|
use dbus::arg::{RefArg, Variant};
|
||||||
|
use dbus::tree::MethodErr;
|
||||||
|
use deltachat::constants::DC_GCL_ADD_SELF;
|
||||||
|
use deltachat::contact::Contact;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use telepathy::ConnectionInterfaceContacts; // for get_contact_attributes
|
||||||
|
|
||||||
|
use super::Connection;
|
||||||
|
|
||||||
|
impl AsRef<dyn telepathy::ConnectionInterfaceContactList + 'static> for std::rc::Rc<Connection> {
|
||||||
|
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceContactList + 'static) {
|
||||||
|
&**self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: extract a utility module for this?
|
||||||
|
type VarArg = Variant<Box<dyn RefArg + 'static>>;
|
||||||
|
|
||||||
|
// FIXME: come back and do this properly later
|
||||||
|
impl telepathy::ConnectionInterfaceContactList for Connection {
|
||||||
|
fn get_contact_list_attributes(
|
||||||
|
&self,
|
||||||
|
interfaces: Vec<&str>,
|
||||||
|
hold: bool,
|
||||||
|
) -> Result<HashMap<u32, HashMap<String, VarArg>>, MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::get_contact_list_attributes({:?}, {})",
|
||||||
|
self.id, interfaces, hold
|
||||||
|
);
|
||||||
|
|
||||||
|
let ctx = &self.ctx.read().unwrap();
|
||||||
|
let ids = match Contact::get_all(ctx, DC_GCL_ADD_SELF.try_into().unwrap(), None::<String>) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
println!(" err: {}", e);
|
||||||
|
return Err(MethodErr::no_arg());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.get_contact_attributes(ids, vec![], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_subscription(&self, contacts: Vec<u32>, message: &str) -> Result<(), MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::request_subscription({:?}, {})",
|
||||||
|
self.id, contacts, message
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn authorize_publication(&self, contacts: Vec<u32>) -> Result<(), MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::authorize_publication({:?})",
|
||||||
|
self.id, contacts
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn remove_contacts(&self, contacts: Vec<u32>) -> Result<(), MethodErr> {
|
||||||
|
println!("Connection<{}>::remove_contacts({:?})", self.id, contacts);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn unsubscribe(&self, contacts: Vec<u32>) -> Result<(), MethodErr> {
|
||||||
|
println!("Connection<{}>::unsubscribe({:?})", self.id, contacts);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unpublish(&self, contacts: Vec<u32>) -> Result<(), MethodErr> {
|
||||||
|
println!("Connection<{}>::unpublish({:?})", self.id, contacts);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn download(&self) -> Result<(), MethodErr> {
|
||||||
|
println!("Connection<{}>::download()", self.id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contact_list_state(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::contact_list_state()", self.id);
|
||||||
|
Ok(3) // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contact_list_persists(&self) -> Result<bool, MethodErr> {
|
||||||
|
println!("Connection<{}>::contact_list_persists()", self.id);
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_change_contact_list(&self) -> Result<bool, MethodErr> {
|
||||||
|
println!("Connection<{}>::can_change_contact_list()", self.id);
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
fn request_uses_message(&self) -> Result<bool, MethodErr> {
|
||||||
|
println!("Connection<{}>::request_uses_message()", self.id);
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn download_at_connection(&self) -> Result<bool, MethodErr> {
|
||||||
|
println!("Connection<{}>::download_at_connection()", self.id);
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
90
src/padfoot/connection/contacts.rs
Normal file
90
src/padfoot/connection/contacts.rs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
use crate::telepathy;
|
||||||
|
|
||||||
|
use dbus::arg::{RefArg, Variant};
|
||||||
|
use dbus::tree::MethodErr;
|
||||||
|
use deltachat::contact::Contact;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::Connection;
|
||||||
|
|
||||||
|
impl AsRef<dyn telepathy::ConnectionInterfaceContacts + 'static> for std::rc::Rc<Connection> {
|
||||||
|
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceContacts + 'static) {
|
||||||
|
&**self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: extract a utility module for this?
|
||||||
|
type VarArgs = Variant<Box<dyn RefArg + 'static>>;
|
||||||
|
|
||||||
|
impl telepathy::ConnectionInterfaceContacts for Connection {
|
||||||
|
fn get_contact_attributes(
|
||||||
|
&self,
|
||||||
|
handles: Vec<u32>,
|
||||||
|
interfaces: Vec<&str>,
|
||||||
|
hold: bool,
|
||||||
|
) -> Result<HashMap<u32, HashMap<String, VarArgs>>, MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::get_contact_attributes({:?}, {:?}, {})",
|
||||||
|
self.id, handles, interfaces, hold
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut out = HashMap::<u32, HashMap<String, VarArgs>>::new();
|
||||||
|
for id in handles.iter() {
|
||||||
|
// FIXME: work out how to use get_all
|
||||||
|
let contact = match Contact::get_by_id(&self.ctx.read().unwrap(), *id) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(_e) => continue, // Invalid IDs are silently ignored
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut props = HashMap::<String, VarArgs>::new();
|
||||||
|
// This is mandatory
|
||||||
|
props.insert(
|
||||||
|
"org.freedesktop.Telepathy.Connection/contact-id".to_string(),
|
||||||
|
Variant(Box::new(contact.get_addr().to_string())),
|
||||||
|
);
|
||||||
|
|
||||||
|
// The empty string means "no avatar"
|
||||||
|
props.insert(
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.Avatars/token".to_string(),
|
||||||
|
Variant(Box::new("".to_string())),
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: we need to publish DBUS services on these endpoints
|
||||||
|
props.insert(
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.ContactList/publish".to_string(),
|
||||||
|
Variant(Box::new(4)),
|
||||||
|
);
|
||||||
|
|
||||||
|
props.insert(
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.ContactList/subscribe".to_string(),
|
||||||
|
Variant(Box::new(4)),
|
||||||
|
);
|
||||||
|
|
||||||
|
out.insert(*id, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_contact_by_id(
|
||||||
|
&self,
|
||||||
|
identifier: &str,
|
||||||
|
interfaces: Vec<&str>,
|
||||||
|
) -> Result<(u32, HashMap<String, VarArgs>), MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::get_contact_by_id({}, {:?})",
|
||||||
|
self.id, identifier, interfaces
|
||||||
|
);
|
||||||
|
Err(MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contact_attribute_interfaces(&self) -> Result<Vec<String>, MethodErr> {
|
||||||
|
println!("Connection<{}>::contact_attribute_interfaces()", self.id);
|
||||||
|
|
||||||
|
Ok(vec![
|
||||||
|
"org.freedesktop.Telepathy.Connection".to_string(),
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.Avatars".to_string(),
|
||||||
|
"org.freedesktop.Telepathy.Connection.Interface.ContactList".to_string(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
47
src/padfoot/connection/requests.rs
Normal file
47
src/padfoot/connection/requests.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use crate::telepathy;
|
||||||
|
|
||||||
|
use dbus::arg::{RefArg, Variant};
|
||||||
|
use dbus::tree::MethodErr;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::Connection;
|
||||||
|
|
||||||
|
// TODO: extract a utility module for this?
|
||||||
|
type VarArg = Variant<Box<dyn RefArg + 'static>>;
|
||||||
|
|
||||||
|
impl AsRef<dyn telepathy::ConnectionInterfaceRequests + 'static> for std::rc::Rc<Connection> {
|
||||||
|
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceRequests + 'static) {
|
||||||
|
&**self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl telepathy::ConnectionInterfaceRequests for Connection {
|
||||||
|
fn create_channel(
|
||||||
|
&self,
|
||||||
|
request: HashMap<&str, VarArg>,
|
||||||
|
) -> Result<(dbus::Path<'static>, HashMap<String, VarArg>), MethodErr> {
|
||||||
|
println!("Connection<{}>::create_channel({:?})", self.id, request);
|
||||||
|
|
||||||
|
Err(MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_channel(
|
||||||
|
&self,
|
||||||
|
request: HashMap<&str, VarArg>,
|
||||||
|
) -> Result<(bool, dbus::Path<'static>, HashMap<String, VarArg>), MethodErr> {
|
||||||
|
println!("Connection<{}>::ensure_channel({:?})", self.id, request);
|
||||||
|
Err(MethodErr::no_arg()) // FIXME: should be NotImplemented?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn channels(&self) -> Result<Vec<(dbus::Path<'static>, HashMap<String, VarArg>)>, MethodErr> {
|
||||||
|
println!("Connection<{}>::channels()", self.id);
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn requestable_channel_classes(
|
||||||
|
&self,
|
||||||
|
) -> Result<Vec<(HashMap<String, VarArg>, Vec<String>)>, MethodErr> {
|
||||||
|
println!("Connection<{}>::requestable_channel_classes()", self.id);
|
||||||
|
Ok(crate::padfoot::requestables())
|
||||||
|
}
|
||||||
|
}
|
68
src/padfoot/connection/simple_presence.rs
Normal file
68
src/padfoot/connection/simple_presence.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
use crate::telepathy;
|
||||||
|
|
||||||
|
use dbus::tree::MethodErr;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::Connection;
|
||||||
|
|
||||||
|
pub type SimplePresenceSpec = (
|
||||||
|
u32, // connection presence type
|
||||||
|
String, // status
|
||||||
|
String, // status message
|
||||||
|
);
|
||||||
|
|
||||||
|
pub type SimpleStatusSpec = (
|
||||||
|
u32, // connection presence type
|
||||||
|
bool, // may set on self?
|
||||||
|
bool, // can have message?
|
||||||
|
);
|
||||||
|
|
||||||
|
impl AsRef<dyn telepathy::ConnectionInterfaceSimplePresence + 'static> for std::rc::Rc<Connection> {
|
||||||
|
fn as_ref(&self) -> &(dyn telepathy::ConnectionInterfaceSimplePresence + 'static) {
|
||||||
|
&**self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl telepathy::ConnectionInterfaceSimplePresence for Connection {
|
||||||
|
fn set_presence(&self, status: &str, status_message: &str) -> Result<(), MethodErr> {
|
||||||
|
println!(
|
||||||
|
"Connection<{}>::set_presence({}, {:?})",
|
||||||
|
self.id, status, status_message
|
||||||
|
);
|
||||||
|
|
||||||
|
// FIXME: emit a presence changed signal
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_presences(
|
||||||
|
&self,
|
||||||
|
contacts: Vec<u32>,
|
||||||
|
) -> Result<HashMap<u32, SimplePresenceSpec>, MethodErr> {
|
||||||
|
println!("Connection<{}>::get_presences({:?})", self.id, contacts);
|
||||||
|
|
||||||
|
let mut out = HashMap::<u32, SimplePresenceSpec>::new();
|
||||||
|
|
||||||
|
for id in contacts {
|
||||||
|
out.insert(id, (2, "available".to_string(), "".to_string())); // Available
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn statuses(&self) -> Result<HashMap<String, SimpleStatusSpec>, MethodErr> {
|
||||||
|
println!("Connection<{}>::statuses()", self.id);
|
||||||
|
|
||||||
|
let mut out = HashMap::<String, SimpleStatusSpec>::new();
|
||||||
|
|
||||||
|
out.insert("available".to_string(), (2, true, false));
|
||||||
|
out.insert("offline".to_string(), (1, true, false));
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maximum_status_message_length(&self) -> Result<u32, MethodErr> {
|
||||||
|
println!("Connection<{}>::maximum_status_message_length()", self.id);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
@@ -4,9 +4,9 @@ use dbus::{arg, message::SignalArgs, tree};
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
|
|
||||||
pub const CM_BUS_NAME: &'static str = "org.freedesktop.Telepathy.ConnectionManager.padfoot";
|
pub const CM_BUS_NAME: &str = "org.freedesktop.Telepathy.ConnectionManager.padfoot";
|
||||||
pub const CM_CONN_BUS_NAME: &'static str = "org.freedesktop.Telepathy.Connection.padfoot";
|
pub const CM_CONN_BUS_NAME: &str = "org.freedesktop.Telepathy.Connection.padfoot";
|
||||||
pub const CM_OBJECT_PATH: &'static str = "/org/freedesktop/Telepathy/ConnectionManager/padfoot";
|
pub const CM_OBJECT_PATH: &str = "/org/freedesktop/Telepathy/ConnectionManager/padfoot";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ConnectionManager {
|
pub struct ConnectionManager {
|
||||||
@@ -50,7 +50,7 @@ impl ConnectionManager {
|
|||||||
return Ok((bus, dbus_conn_path));
|
return Ok((bus, dbus_conn_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
conns.insert(path.clone());
|
conns.insert(path);
|
||||||
|
|
||||||
// FIXME: this thread races with the responses we send. It's possible
|
// FIXME: this thread races with the responses we send. It's possible
|
||||||
// the remotes will try to use the new names before they exist on the
|
// the remotes will try to use the new names before they exist on the
|
||||||
|
@@ -2,12 +2,9 @@ use crate::telepathy;
|
|||||||
use dbus::{arg, tree};
|
use dbus::{arg, tree};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub const PROTO_OBJECT_PATH: &'static str =
|
pub const PROTO_OBJECT_PATH: &str = "/org/freedesktop/Telepathy/ConnectionManager/padfoot/delta";
|
||||||
"/org/freedesktop/Telepathy/ConnectionManager/padfoot/delta";
|
pub const PROTO_BUS_NAME: &str = "org.freedesktop.Telepathy.ConnectionManager.padfoot.delta";
|
||||||
pub const PROTO_BUS_NAME: &'static str =
|
pub const PROTO_NAME: &str = "delta";
|
||||||
"org.freedesktop.Telepathy.ConnectionManager.padfoot.delta";
|
|
||||||
|
|
||||||
pub const PROTO_NAME: &'static str = "delta";
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Protocol {}
|
pub struct Protocol {}
|
||||||
|
Reference in New Issue
Block a user