301 lines
9.4 KiB
Rust
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)
|
|
}
|
|
}
|