Files
telepathy-padfoot/src/padfoot/connection/connection.rs

301 lines
9.4 KiB
Rust

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();
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();
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();
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();
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 ctx = self.ctx.read().unwrap();
let state = self.state.clone();
let mut w = state.write().unwrap();
*w = ConnState::Disconnected;
dc::job::interrupt_inbox_idle(&ctx);
dc::job::interrupt_smtp_idle(&ctx);
dc::job::interrupt_sentbox_idle(&ctx);
dc::job::interrupt_mvbox_idle(&ctx);
// 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)
}
}