Add image receipt to the text channel

This is disturbingly useless with Empathy because it doesn't know how
to display text/html parts, or plain image/png parts either :/

Time to start playing with KDE Spacebar? How does it handle them?
This commit is contained in:
2020-05-27 01:19:43 +01:00
parent b9faad742b
commit 9e764d72a1
4 changed files with 104 additions and 28 deletions

View File

@@ -43,6 +43,7 @@ impl telepathy::ChannelInterfaceMessages for Channel {
};
let ctx = self.ctx.read().unwrap();
let blobdir = ctx.get_blobdir();
let msg_id = match dc::chat::send_msg(&ctx, self.chat_id, &mut delta_msg) {
Ok(msg_id) => msg_id,
@@ -53,7 +54,7 @@ impl telepathy::ChannelInterfaceMessages for Channel {
};
let token = format!("{}", msg_id.to_u32());
let dbus_parts = convert_msg(&delta_msg);
let dbus_parts = convert_msg(blobdir, &delta_msg).map_err(|_| MethodErr::no_arg())?;
let messages_sig = telepathy::ChannelInterfaceMessagesMessageSent {
content: dbus_parts,
@@ -90,7 +91,7 @@ impl telepathy::ChannelInterfaceMessages for Channel {
fn supported_content_types(&self) -> Result<Vec<String>> {
println!("Channel::supported_content_types()");
Ok(vec!["text/plain".to_string()]) // TODO: image support
Ok(vec!["*/*".to_string()])
}
fn message_types(&self) -> Result<Vec<u32>> {
@@ -111,13 +112,15 @@ impl telepathy::ChannelInterfaceMessages for Channel {
let mut out = Vec::<Vec<HashMap<String, VarArg>>>::new();
let ctx = self.ctx.read().unwrap();
let blobdir = ctx.get_blobdir();
for msg_id in dc::chat::get_chat_msgs(&ctx, self.chat_id, 0, None) {
if let Ok(msg) = dc::message::Message::load_from_db(&ctx, msg_id) {
match msg.get_state() {
MessageState::InFresh | MessageState::InNoticed => {
println!(" A message: {:?}", msg);
out.push(convert_msg(&msg))
let parts = convert_msg(blobdir, &msg).map_err(|_| MethodErr::no_arg())?;
out.push(parts);
}
_ => continue,
}

View File

@@ -401,6 +401,7 @@ impl Connection {
let chans = c2.read().unwrap();
let u_ctx = ctx.clone();
let ctx = u_ctx.read().unwrap();
let blobdir = ctx.get_blobdir();
// Autocreate channel if it doesn't already exist
// FIXME: unknown contacts need more care than this
@@ -453,11 +454,16 @@ impl Connection {
continue;
}
let parts = convert_msg(&msg);
let parts = convert_msg(blobdir, &msg);
if parts.is_err() {
println!("can't convert, skipping: {}", parts.unwrap_err());
continue;
}
let sig =
telepathy::ChannelInterfaceMessagesMessageReceived { message: parts }
.to_emit_message(&chan_path);
let sig = telepathy::ChannelInterfaceMessagesMessageReceived {
message: parts.unwrap(),
}
.to_emit_message(&chan_path);
actq.send(DbusAction::Signal(sig)).unwrap();

View File

@@ -1,35 +1,47 @@
use crate::padfoot::{var_i64, var_str, var_u32, VarArg};
use crate::padfoot::{var_bytearray, var_i64, var_str, var_u32, VarArg};
use deltachat::message::Message;
use dc::constants::Viewtype as Vt;
use dc::message::Message;
use deltachat as dc;
use std::collections::HashMap;
type Part = HashMap<String, VarArg>;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
// Turns a deltachat::message::Message into a Telepathy Message_Part_List
pub fn convert_msg(msg: &Message) -> Vec<HashMap<String, VarArg>> {
pub fn convert_msg(blobdir: &std::path::Path, msg: &Message) -> Result<Vec<Part>> {
if msg.is_setupmessage() {
return convert_setupmessage(msg);
return Ok(convert_setupmessage(msg));
}
let mut parts = vec![build_props(msg)];
let mut parts = vec![make_props(msg)];
if let Some(text) = msg.get_text() {
parts.push(build_plain(&text));
}
// TODO: Check. Can a deltachat message have multiple parts? Can an image
// viewtype have text as well?
let result = match msg.get_viewtype() {
Vt::Text => build_txt(msg),
Vt::Unknown => build_unknown(msg),
Vt::Audio | Vt::Voice => build_snd(msg),
Vt::Video => build_vid(msg),
_ => build_attachment(blobdir, msg),
};
// TODO: other parts. Can a deltachat message have multiple parts?
parts
result.map(|mut more| {
parts.append(&mut more);
parts
})
}
fn convert_setupmessage(msg: &Message) -> Vec<HashMap<String, VarArg>> {
fn convert_setupmessage(msg: &Message) -> Vec<Part> {
let msg_id = msg.get_id();
vec![
build_props(msg),
build_plain(&format!("Setup message received. To apply it, reply with:\nIMEX: {} nnnn-nnnn-nnnn-nnnn-nnnn-nnnn-nnnn-nnnn-nnnn\nNo whitespace in the setup-code!", msg_id.to_u32())),
make_props(msg),
make_plain(&format!("Setup message received. To apply it, reply with:\nIMEX: {} nnnn-nnnn-nnnn-nnnn-nnnn-nnnn-nnnn-nnnn-nnnn\nNo whitespace in the setup-code!", msg_id.to_u32())),
]
}
fn build_props(msg: &Message) -> HashMap<String, VarArg> {
fn make_props(msg: &Message) -> Part {
let msg_id = msg.get_id();
let mut out = HashMap::new();
@@ -63,14 +75,65 @@ fn build_props(msg: &Message) -> HashMap<String, VarArg> {
out
}
fn build_plain(text: &str) -> HashMap<String, VarArg> {
fn make_plain(text: &str) -> Part {
make_content("text/plain", None, var_str(text.to_string()))
}
fn make_content(type_: &str, id: Option<&str>, content: VarArg) -> Part {
let mut out = HashMap::new();
out.insert(
"content-type".to_string(),
var_str("text/plain".to_string()),
);
out.insert("content".to_string(), var_str(text.to_string()));
out.insert("content-type".to_string(), var_str(type_.to_string()));
out.insert("content".to_string(), content);
id.map(|txt| out.insert("identifier".to_string(), var_str(txt.to_string())));
out
}
fn build_snd(_msg: &Message) -> Result<Vec<Part>> {
Ok(vec![make_plain("(a sound file was received)")])
}
fn build_txt(msg: &Message) -> Result<Vec<Part>> {
Ok(vec![make_plain(
&msg.get_text().unwrap_or_else(|| "".to_string()),
)])
}
fn build_unknown(_msg: &Message) -> Result<Vec<Part>> {
Ok(vec![make_plain("(a message of unknown type was received)")])
}
fn build_vid(_msg: &Message) -> Result<Vec<Part>> {
Ok(vec![make_plain("(a video was received)")])
}
// The message contains a file. Detect the content-type and construct a part
// containing the data in full.
fn build_attachment(blobdir: &std::path::Path, msg: &Message) -> Result<Vec<Part>> {
let mime = msg
.get_filemime()
.unwrap_or_else(|| "application/octet-stream".to_string());
let filename = msg.get_filename().ok_or("Failed to get filename")?;
let path: std::path::PathBuf = [blobdir, &std::path::Path::new(&filename)].iter().collect();
// let mut path = std::path::PathBuf::from(blobdir);
// path.push(filename);
let data =
std::fs::read(&path).map_err(|e| format!("Failed to read file {:?}: {}", path, e))?;
println!("MIME type for attachment: {}", mime);
let html = make_content(
"text/html",
None,
var_str("<img src=\"cid:picture\" />".to_string()),
);
let txt = make_plain("(an image was sent but cannot be displayed)");
let blob = make_content(&mime, Some("picture"), var_bytearray(data));
Ok(vec![html, txt, blob])
}

View File

@@ -20,6 +20,10 @@ pub fn var_bool(item: bool) -> VarArg {
var_arg(Box::new(item))
}
pub fn var_bytearray(item: std::vec::Vec<u8>) -> VarArg {
var_arg(Box::new(item))
}
pub fn var_u32(item: u32) -> VarArg {
var_arg(Box::new(item))
}