diff --git a/src/padfoot.rs b/src/padfoot.rs index a7a9e16..30b5eb9 100644 --- a/src/padfoot.rs +++ b/src/padfoot.rs @@ -7,6 +7,9 @@ pub use self::connection::*; mod connection_manager; pub use self::connection_manager::*; +mod message; +pub use self::message::*; + mod protocol; pub use self::protocol::*; diff --git a/src/padfoot/channel/messages.rs b/src/padfoot/channel/messages.rs index 228c572..0f65a7f 100644 --- a/src/padfoot/channel/messages.rs +++ b/src/padfoot/channel/messages.rs @@ -1,4 +1,4 @@ -use crate::padfoot::{var_i64, var_str, var_u32, VarArg}; +use crate::padfoot::{convert_msg, VarArg}; use crate::telepathy; use dbus::tree::MethodErr; @@ -61,50 +61,7 @@ impl telepathy::ChannelInterfaceMessages for Channel { if let Ok(msg) = dc::message::Message::load_from_db(&ctx, msg_id) { println!(" A message: {:?}", msg); match msg.get_state() { - MessageState::InFresh | MessageState::InNoticed => { - let mut parts = Vec::new(); - let mut props = HashMap::new(); - props.insert( - "message-token".to_string(), - var_str(format!("{}", msg_id.to_u32())), - ); - props.insert("message-sent".to_string(), var_i64(msg.get_timestamp())); - props.insert( - "message-received".to_string(), - var_i64(msg.get_received_timestamp()), - ); - props.insert("message-sender".to_string(), var_u32(msg.get_from_id())); - // props.insert("message-sender-id", var_str()); // This doesn't need to be sent - // props.insert("sender-nickname", var_str()); // Can we get away without this one? - props.insert("message-type".to_string(), var_u32(0)); // normal - - // These relate to superseded messages - // props.insert("supersedes", var_str()); - // props.insert("original-message-sent", var_i64()); - // props.insert("original-message-received", var_i64()); - - props.insert("pending-message-id".to_string(), var_u32(msg_id.to_u32())); - - parts.push(props); - - // Don't need these - // props.insert("interface", var_str()); - // props.insert("scrollback", var_vool()); - // props.insert("silent", var_bool()); - // props.insert("rescued", var_bool()); - - if let Some(text) = msg.get_text() { - let mut part = HashMap::new(); - part.insert( - "content-type".to_string(), - var_str("text/plain".to_string()), - ); - part.insert("content".to_string(), var_str(text)); - parts.push(part); - } - - out.push(parts); - } + MessageState::InFresh | MessageState::InNoticed => out.push(convert_msg(msg)), _ => continue, } } diff --git a/src/padfoot/channel/type_text.rs b/src/padfoot/channel/type_text.rs index 32f580e..b0e532e 100644 --- a/src/padfoot/channel/type_text.rs +++ b/src/padfoot/channel/type_text.rs @@ -1,6 +1,11 @@ +use crate::padfoot::DbusAction; use crate::telepathy; use crate::telepathy::ChannelInterfaceMessages; + +use dbus::message::SignalArgs; use dbus::tree::MethodErr; +use dc::message::MsgId; +use deltachat as dc; use super::{Channel, Result}; @@ -22,9 +27,32 @@ type PendingMessagesSpec = ( // Most of these methods are deprecated, so should be implemented in terms of // the mandatory Messages interface. impl telepathy::ChannelTypeText for Channel { + // ids is a list of deltachat msg_ids fn acknowledge_pending_messages(&self, ids: Vec) -> Result<()> { println!("Channel::acknowledge_pending_messages({:?})", ids); - Err(MethodErr::no_arg()) + + let ctx = self.ctx.read().unwrap(); + let mut msg_ids = Vec::::new(); + for msg_id in &ids { + msg_ids.push(MsgId::new(*msg_id)); + } + + print!(" Marking messages as seen..."); + let result = dc::message::markseen_msgs(&ctx, &msg_ids); + if result { + println!("OK!"); + + // Emit a PendingMessagesRemoved signal only if all have been removed + let sig = + telepathy::ChannelInterfaceMessagesPendingMessagesRemoved { message_ids: ids } + .to_emit_message(&self.path()); + + self.actq.send(DbusAction::Signal(sig)).unwrap(); + } else { + println!("FAILED!"); + } + + Ok(()) } fn get_message_types(&self) -> Result> { @@ -35,6 +63,7 @@ impl telepathy::ChannelTypeText for Channel { fn list_pending_messages(&self, clear: bool) -> Result> { println!("Channel::list_pending_messages({})", clear); + Err(MethodErr::no_arg()) } diff --git a/src/padfoot/connection.rs b/src/padfoot/connection.rs index 7b2ebca..1b7e9c3 100644 --- a/src/padfoot/connection.rs +++ b/src/padfoot/connection.rs @@ -20,7 +20,7 @@ pub use self::requests::*; mod simple_presence; pub use self::simple_presence::*; -use crate::padfoot::{var_bool, var_str, var_str_vec, var_u32, Channel, VarArg}; +use crate::padfoot::{convert_msg, var_bool, var_str, var_str_vec, var_u32, Channel, VarArg}; use crate::telepathy; use dbus::blocking::{stdintf::org_freedesktop_dbus::RequestNameReply, LocalConnection}; @@ -415,22 +415,37 @@ impl Connection { // Autocreate channel if it doesn't already exist // FIXME: unknown contacts need more care than this if chans.contains_key(&chan_path) { - println!( - "Message {} received for {}, passing it on is TODO!", - msg_id, chan_path - ); + print!("Message {} received for {}...", msg_id, chan_path); + + // Emit new message signals for the channel + if let Ok(msg) = dc::message::Message::load_from_db( + &ctx.clone().read().unwrap(), + msg_id, + ) { + let parts = convert_msg(msg); + + let sig = telepathy::ChannelInterfaceMessagesMessageReceived { + message: parts, + } + .to_emit_message(&chan_path); + + actq.send(DbusAction::Signal(sig)).unwrap(); + + println!("OK!"); + } else { + println!(" couldn't find message not sending signal"); + } + + // FIXME: We MUST also send a Text.Received signal } else { print!("Channel for {} doesn't exist yet, creating it...", chat_id); let contacts = dc::chat::get_chat_contacts(&ctx.clone().read().unwrap(), chat_id); - if contacts.is_empty() { - println!("empty chat! ignoring"); + if contacts.len() != 1 { + println!("...{} contacts in chat, ignoring!", contacts.len()); continue; } - if contacts.len() > 1 { - println!("...{} contacts in chat, ignoring!", contacts.len()) - } let handle = contacts.first().unwrap(); let chan = Channel::new( diff --git a/src/padfoot/message.rs b/src/padfoot/message.rs new file mode 100644 index 0000000..e410094 --- /dev/null +++ b/src/padfoot/message.rs @@ -0,0 +1,55 @@ +use crate::padfoot::{var_i64, var_str, var_u32, VarArg}; + +use deltachat::message::Message; + +use std::collections::HashMap; + +// Turns a deltachat::message::Message into a Telepathy Message_Part_List +pub fn convert_msg(msg: Message) -> Vec> { + let mut parts = Vec::new(); + let mut props = HashMap::new(); + let msg_id = msg.get_id(); + + props.insert( + "message-token".to_string(), + var_str(format!("{}", msg_id.to_u32())), + ); + props.insert("message-sent".to_string(), var_i64(msg.get_timestamp())); + props.insert( + "message-received".to_string(), + var_i64(msg.get_received_timestamp()), + ); + props.insert("message-sender".to_string(), var_u32(msg.get_from_id())); + // props.insert("message-sender-id", var_str()); // This doesn't need to be sent + // props.insert("sender-nickname", var_str()); // Can we get away without this one? + props.insert("message-type".to_string(), var_u32(0)); // normal + + // These relate to superseded messages + // props.insert("supersedes", var_str()); + // props.insert("original-message-sent", var_i64()); + // props.insert("original-message-received", var_i64()); + + props.insert("pending-message-id".to_string(), var_u32(msg_id.to_u32())); + + parts.push(props); + + // Don't need these + // props.insert("interface", var_str()); + // props.insert("scrollback", var_vool()); + // props.insert("silent", var_bool()); + // props.insert("rescued", var_bool()); + + if let Some(text) = msg.get_text() { + let mut part = HashMap::new(); + part.insert( + "content-type".to_string(), + var_str("text/plain".to_string()), + ); + part.insert("content".to_string(), var_str(text)); + parts.push(part); + } + + // TODO: other parts. Can a deltachat message have multiple parts? + + parts +}