Skip to content

Commit

Permalink
feat: Display vCard contact name in message summary
Browse files Browse the repository at this point in the history
  • Loading branch information
iequidoo committed May 22, 2024
1 parent 907d3ef commit d66685e
Show file tree
Hide file tree
Showing 15 changed files with 122 additions and 62 deletions.
14 changes: 10 additions & 4 deletions deltachat-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3815,10 +3815,16 @@ pub unsafe extern "C" fn dc_msg_set_file(
return;
}
let ffi_msg = &mut *msg;
ffi_msg.message.set_file(
to_string_lossy(file),
to_opt_string_lossy(filemime).as_deref(),
)
block_on(async move {
ffi_msg
.message
.set_file(
&*ffi_msg.context,
to_string_lossy(file),
to_opt_string_lossy(filemime).as_deref(),
)
.await;
});
}

#[no_mangle]
Expand Down
6 changes: 3 additions & 3 deletions deltachat-jsonrpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1924,7 +1924,7 @@ impl CommandApi {
let ctx = self.get_context(account_id).await?;

let mut msg = Message::new(Viewtype::Sticker);
msg.set_file(&sticker_path, None);
msg.set_file(&ctx, &sticker_path, None).await;

// JSON-rpc does not need heuristics to turn [Viewtype::Sticker] into [Viewtype::Image]
msg.force_sticker();
Expand Down Expand Up @@ -2160,7 +2160,7 @@ impl CommandApi {
});
message.set_text(text.unwrap_or_default());
if let Some(file) = file {
message.set_file(file, None);
message.set_file(&ctx, file, None).await;
}
if let Some((latitude, longitude)) = location {
message.set_location(latitude, longitude);
Expand Down Expand Up @@ -2208,7 +2208,7 @@ impl CommandApi {
));
draft.set_text(text.unwrap_or_default());
if let Some(file) = file {
draft.set_file(file, None);
draft.set_file(&ctx, file, None).await;
}
if let Some(id) = quoted_message_id {
draft
Expand Down
2 changes: 1 addition & 1 deletion deltachat-jsonrpc/src/api/types/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ impl MessageData {
message.set_override_sender_name(self.override_sender_name);
}
if let Some(file) = self.file {
message.set_file(file, None);
message.set_file(context, file, None).await;
}
if let Some((latitude, longitude)) = self.location {
message.set_location(latitude, longitude);
Expand Down
2 changes: 1 addition & 1 deletion deltachat-repl/src/cmdline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
} else {
Viewtype::File
});
msg.set_file(arg1, None);
msg.set_file(&context, arg1, None).await;
msg.set_text(arg2.to_string());
chat::send_msg(&context, sel_chat.as_ref().unwrap().get_id(), &mut msg).await?;
}
Expand Down
8 changes: 4 additions & 4 deletions src/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1301,7 +1301,7 @@ mod tests {
}

let mut msg = Message::new(viewtype);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&alice, file.to_str().unwrap(), None).await;
let chat = alice.create_chat(&bob).await;
let sent = alice.send_msg(chat.id, &mut msg).await;
let alice_msg = alice.get_last_msg().await;
Expand Down Expand Up @@ -1347,7 +1347,7 @@ mod tests {
.await
.context("failed to write file")?;
let mut msg = Message::new(Viewtype::Image);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&alice, file.to_str().unwrap(), None).await;
let chat = alice.create_chat(&bob).await;
let sent = alice.send_msg(chat.id, &mut msg).await;
let bob_msg = bob.recv_msg(&sent).await;
Expand All @@ -1374,7 +1374,7 @@ mod tests {
let file = t.get_blobdir().join("anyfile.dat");
fs::write(&file, b"bla").await?;
let mut msg = Message::new(Viewtype::File);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&t, file.to_str().unwrap(), None).await;
let prepared_id = chat::prepare_msg(&t, chat_id, &mut msg).await?;
assert_eq!(prepared_id, msg.id);
assert!(msg.is_increation());
Expand All @@ -1394,7 +1394,7 @@ mod tests {
let file = t.dir.path().join("anyfile.dat");
fs::write(&file, b"bla").await?;
let mut msg = Message::new(Viewtype::File);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&t, file.to_str().unwrap(), None).await;
assert!(chat::prepare_msg(&t, chat_id, &mut msg).await.is_err());

Ok(())
Expand Down
14 changes: 7 additions & 7 deletions src/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6420,7 +6420,7 @@ mod tests {
tokio::fs::write(&file, bytes).await?;

let mut msg = Message::new(Viewtype::Sticker);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&alice, file.to_str().unwrap(), None).await;

let sent_msg = alice.send_msg(alice_chat.id, &mut msg).await;
let mime = sent_msg.payload();
Expand Down Expand Up @@ -6484,14 +6484,14 @@ mod tests {

// Images without force_sticker should be turned into [Viewtype::Image]
let mut msg = Message::new(Viewtype::Sticker);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&alice, file.to_str().unwrap(), None).await;
let sent_msg = alice.send_msg(alice_chat.id, &mut msg).await;
let msg = bob.recv_msg(&sent_msg).await;
assert_eq!(msg.get_viewtype(), Viewtype::Image);

// Images with `force_sticker = true` should keep [Viewtype::Sticker]
let mut msg = Message::new(Viewtype::Sticker);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&alice, file.to_str().unwrap(), None).await;
msg.force_sticker();
let sent_msg = alice.send_msg(alice_chat.id, &mut msg).await;
let msg = bob.recv_msg(&sent_msg).await;
Expand All @@ -6500,7 +6500,7 @@ mod tests {
// Images with `force_sticker = true` should keep [Viewtype::Sticker]
// even on drafted messages
let mut msg = Message::new(Viewtype::Sticker);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&alice, file.to_str().unwrap(), None).await;
msg.force_sticker();
alice_chat
.id
Expand Down Expand Up @@ -6539,7 +6539,7 @@ mod tests {
let file = alice.get_blobdir().join(file_name);
tokio::fs::write(&file, bytes).await?;
let mut msg = Message::new(Viewtype::Sticker);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&alice, file.to_str().unwrap(), None).await;

// send sticker to bob
let sent_msg = alice.send_msg(alice_chat.get_id(), &mut msg).await;
Expand Down Expand Up @@ -7116,7 +7116,7 @@ mod tests {
let file = t.get_blobdir().join(name);
tokio::fs::write(&file, bytes).await?;
let mut msg = Message::new(msg_type);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(t, file.to_str().unwrap(), None).await;
send_msg(t, chat_id, &mut msg).await
}

Expand Down Expand Up @@ -7271,7 +7271,7 @@ mod tests {
let file = dir.path().join("harmless_file.\u{202e}txt.exe");
fs::write(&file, "aaa").await?;
let mut msg = Message::new(Viewtype::File);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&alice, file.to_str().unwrap(), None).await;
let msg = bob.recv_msg(&alice.send_msg(chat_id, &mut msg).await).await;

// the file bob receives should not contain BIDI-control characters
Expand Down
4 changes: 3 additions & 1 deletion src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,9 @@ mod tests {
let file = alice.get_blobdir().join("minimal.xdc");
tokio::fs::write(&file, include_bytes!("../test-data/webxdc/minimal.xdc")).await?;
let mut instance = Message::new(Viewtype::File);
instance.set_file(file.to_str().unwrap(), None);
instance
.set_file(&alice, file.to_str().unwrap(), None)
.await;
let _sent1 = alice.send_msg(chat_id, &mut instance).await;

alice
Expand Down
3 changes: 2 additions & 1 deletion src/imex/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,8 @@ mod tests {
let file = ctx0.get_blobdir().join("hello.txt");
fs::write(&file, "i am attachment").await.unwrap();
let mut msg = Message::new(Viewtype::File);
msg.set_file(file.to_str().unwrap(), Some("text/plain"));
msg.set_file(&ctx0, file.to_str().unwrap(), Some("text/plain"))
.await;
send_msg(&ctx0, self_chat.id, &mut msg).await.unwrap();

// Prepare to transfer backup.
Expand Down
2 changes: 1 addition & 1 deletion src/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,7 @@ Content-Disposition: attachment; filename="location.kml"
let file = alice.get_blobdir().join(file_name);
tokio::fs::write(&file, bytes).await?;
let mut msg = Message::new(Viewtype::Image);
msg.set_file(file.to_str().unwrap(), None);
msg.set_file(&alice, file.to_str().unwrap(), None).await;
let sent = alice.send_msg(alice_chat.id, &mut msg).await;
let alice_msg = Message::load_from_db(&alice, sent.sender_msg_id).await?;
assert_eq!(alice_msg.has_location(), false);
Expand Down
37 changes: 34 additions & 3 deletions src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ use crate::ephemeral::{start_ephemeral_timers_msgids, Timer as EphemeralTimer};
use crate::events::EventType;
use crate::imap::markseen_on_imap_table;
use crate::location::delete_poi_location;
use crate::mimeparser::{parse_message_id, SystemMessage};
use crate::log::LogExt;
use crate::mimeparser::{get_vcard_summary, parse_message_id, SystemMessage};
use crate::param::{Param, Params};
use crate::pgp::split_armored_data;
use crate::reaction::get_msg_reactions;
Expand Down Expand Up @@ -1056,12 +1057,30 @@ impl Message {
/// This function does not use the file or check if it exists,
/// the file will only be used when the message is prepared
/// for sending.
pub fn set_file(&mut self, file: impl ToString, filemime: Option<&str>) {
if let Some(name) = Path::new(&file.to_string()).file_name() {
pub async fn set_file(
&mut self,
context: &Context,
file: impl ToString,
filemime: Option<&str>,
) {
let file = file.to_string();
let path = Path::new(&file);
if let Some(name) = path.file_name() {
if let Some(name) = name.to_str() {
self.param.set(Param::Filename, name);
}
}
if self.viewtype == Viewtype::Vcard {
if let Ok(vcard) = fs::read(path)
.await
.context("Could not read {path}")
.log_err(context)
{
self.try_set_vcard(context, &vcard);
} else {
self.viewtype = Viewtype::File;
}
}
self.param.set(Param::File, file);
self.param.set_optional(Param::MimeType, filemime);
}
Expand All @@ -1078,9 +1097,21 @@ impl Message {
self.param.set(Param::Filename, suggested_name);
self.param.set(Param::File, blob.as_name());
self.param.set_optional(Param::MimeType, filemime);
if self.viewtype == Viewtype::Vcard {
self.try_set_vcard(context, data);
}
Ok(())
}

fn try_set_vcard(&mut self, context: &Context, vcard: &[u8]) {
if let Some(summary) = get_vcard_summary(vcard) {
self.param.set(Param::Summary1, summary);
} else {
warn!(context, "try_set_vcard: Not a valid DeltaChat vCard.");
self.viewtype = Viewtype::File;
}
}

/// Set different sender name for a message.
/// This overrides the name set by the `set_config()`-option `displayname`.
pub fn set_override_sender_name(&mut self, name: Option<String>) {
Expand Down
37 changes: 24 additions & 13 deletions src/mimeparser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,7 @@ impl MimeMessage {
return Ok(());
}
}
let mut param = Params::new();
let msg_type = if context
.is_webxdc_file(filename, decoded_data)
.await
Expand Down Expand Up @@ -1276,6 +1277,13 @@ impl MimeMessage {
.unwrap_or_default();
self.webxdc_status_update = Some(serialized);
return Ok(());
} else if msg_type == Viewtype::Vcard {
if let Some(summary) = get_vcard_summary(decoded_data) {
param.set(Param::Summary1, summary);
msg_type
} else {
Viewtype::File
}
} else {
msg_type
};
Expand All @@ -1299,18 +1307,19 @@ impl MimeMessage {
let mut part = Part::default();
if mime_type.type_() == mime::IMAGE {
if let Ok((width, height)) = get_filemeta(decoded_data) {
part.param.set_int(Param::Width, width as i32);
part.param.set_int(Param::Height, height as i32);
param.set_int(Param::Width, width as i32);
param.set_int(Param::Height, height as i32);
}
}

part.typ = msg_type;
part.org_filename = Some(filename.to_string());
part.mimetype = Some(mime_type);
part.bytes = decoded_data.len();
part.param.set(Param::File, blob.as_name());
part.param.set(Param::Filename, filename);
part.param.set(Param::MimeType, raw_mime);
param.set(Param::File, blob.as_name());
param.set(Param::Filename, filename);
param.set(Param::MimeType, raw_mime);
part.param = param;
part.is_related = is_related;

self.do_add_single_part(part);
Expand Down Expand Up @@ -1937,7 +1946,7 @@ fn get_mime_type(

let viewtype = match mimetype.type_() {
mime::TEXT => match mimetype.subtype() {
mime::VCARD if is_valid_deltachat_vcard(mail) => Viewtype::Vcard,
mime::VCARD => Viewtype::Vcard,
mime::PLAIN | mime::HTML if !is_attachment_disposition(mail) => Viewtype::Text,
_ => Viewtype::File,
},
Expand Down Expand Up @@ -1988,15 +1997,17 @@ fn is_attachment_disposition(mail: &mailparse::ParsedMail<'_>) -> bool {
.any(|(key, _value)| key.starts_with("filename"))
}

fn is_valid_deltachat_vcard(mail: &mailparse::ParsedMail) -> bool {
let Ok(body) = &mail.get_body() else {
return false;
/// Returns the 1st part of summary text (i.e. before the dash if any) for a valid DeltaChat vCard.
pub(crate) fn get_vcard_summary(vcard: &[u8]) -> Option<String> {
let vcard = str::from_utf8(vcard).ok()?;
let contacts = deltachat_contact_tools::parse_vcard(vcard);
let [c] = &contacts[..] else {
return None;
};
let contacts = deltachat_contact_tools::parse_vcard(body);
if let [c] = &contacts[..] {
return deltachat_contact_tools::may_be_valid_addr(&c.addr);
if !deltachat_contact_tools::may_be_valid_addr(&c.addr) {
return None;
}
false
Some(c.display_name().to_string())
}

/// Tries to get attachment filename.
Expand Down
3 changes: 3 additions & 0 deletions src/param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ pub enum Param {
/// For Messages: quoted text.
Quote = b'q',

/// For Messages: the 1st part of summary text (i.e. before the dash if any).
Summary1 = b'4',

/// For Messages
Cmd = b'S',

Expand Down
5 changes: 4 additions & 1 deletion src/receive_imf/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3042,7 +3042,9 @@ async fn test_long_and_duplicated_filenames() -> Result<()> {
tokio::fs::write(&attachment, content.as_bytes()).await?;

let mut msg_alice = Message::new(Viewtype::File);
msg_alice.set_file(attachment.to_str().unwrap(), None);
msg_alice
.set_file(&alice, attachment.to_str().unwrap(), None)
.await;
let alice_chat = alice.create_chat(&bob).await;
let sent = alice.send_msg(alice_chat.id, &mut msg_alice).await;
println!("{}", sent.payload());
Expand Down Expand Up @@ -4551,6 +4553,7 @@ async fn test_receive_vcard() -> Result<()> {

if vcard_contains_address {
assert_eq!(rcvd.viewtype, Viewtype::Vcard);
assert_eq!(rcvd.get_summary_text(&bob).await, "👤 Claire");
} else {
// VCards without an email address are not "deltachat contacts",
// so they are shown as files
Expand Down
Loading

0 comments on commit d66685e

Please sign in to comment.