Skip to content

Commit 7f6beee

Browse files
d2weberiequidoo
andauthored
feat: put "biography" in the vCard (#6819)
Co-authored-by: iequidoo <117991069+iequidoo@users.noreply.github.com>
1 parent 1509240 commit 7f6beee

File tree

4 files changed

+28
-0
lines changed

4 files changed

+28
-0
lines changed

deltachat-contact-tools/src/vcard.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub struct VcardContact {
2020
pub key: Option<String>,
2121
/// The contact's profile image (=avatar) in Base64, vcard property `photo`
2222
pub profile_image: Option<String>,
23+
/// The biography, stored in the vcard property `note`
24+
pub biography: Option<String>,
2325
/// The timestamp when the vcard was created / last updated, vcard property `rev`
2426
pub timestamp: Result<i64>,
2527
}
@@ -60,6 +62,9 @@ pub fn make_vcard(contacts: &[VcardContact]) -> String {
6062
if let Some(profile_image) = &c.profile_image {
6163
res += &format!("PHOTO:data:image/jpeg;base64,{profile_image}\r\n");
6264
}
65+
if let Some(biography) = &c.biography {
66+
res += &format!("NOTE:{biography}\r\n");
67+
}
6368
if let Some(timestamp) = format_timestamp(c) {
6469
res += &format!("REV:{timestamp}\r\n");
6570
}
@@ -186,6 +191,7 @@ pub fn parse_vcard(vcard: &str) -> Vec<VcardContact> {
186191
let mut addr = None;
187192
let mut key = None;
188193
let mut photo = None;
194+
let mut biography = None;
189195
let mut datetime = None;
190196

191197
for mut line in lines.by_ref() {
@@ -205,6 +211,8 @@ pub fn parse_vcard(vcard: &str) -> Vec<VcardContact> {
205211
key.get_or_insert(k);
206212
} else if let Some(p) = base64_photo(line) {
207213
photo.get_or_insert(p);
214+
} else if let Some((_params, bio)) = vcard_property(line, "note") {
215+
biography.get_or_insert(bio);
208216
} else if let Some((_params, rev)) = vcard_property(line, "rev") {
209217
datetime.get_or_insert(rev);
210218
} else if line.eq_ignore_ascii_case("END:VCARD") {
@@ -216,6 +224,7 @@ pub fn parse_vcard(vcard: &str) -> Vec<VcardContact> {
216224
addr,
217225
key: key.map(|s| s.to_string()),
218226
profile_image: photo.map(|s| s.to_string()),
227+
biography: biography.map(|b| b.to_owned()),
219228
timestamp: datetime
220229
.context("No timestamp in vcard")
221230
.and_then(parse_datetime),

deltachat-contact-tools/src/vcard/vcard_tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,15 @@ fn test_make_and_parse_vcard() {
9191
authname: "Alice Wonderland".to_string(),
9292
key: Some("[base64-data]".to_string()),
9393
profile_image: Some("image in Base64".to_string()),
94+
biography: Some("Hi, I'm Alice".to_string()),
9495
timestamp: Ok(1713465762),
9596
},
9697
VcardContact {
9798
addr: "bob@example.com".to_string(),
9899
authname: "".to_string(),
99100
key: None,
100101
profile_image: None,
102+
biography: None,
101103
timestamp: Ok(0),
102104
},
103105
];
@@ -108,6 +110,7 @@ fn test_make_and_parse_vcard() {
108110
FN:Alice Wonderland\r\n\
109111
KEY:data:application/pgp-keys;base64,[base64-data]\r\n\
110112
PHOTO:data:image/jpeg;base64,image in Base64\r\n\
113+
NOTE:Hi, I'm Alice\r\n\
111114
REV:20240418T184242Z\r\n\
112115
END:VCARD\r\n",
113116
"BEGIN:VCARD\r\n\

src/contact.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ pub async fn make_vcard(context: &Context, contacts: &[ContactId]) -> Result<Str
287287
authname: c.authname,
288288
key,
289289
profile_image,
290+
biography: Some(c.status).filter(|s| !s.is_empty()),
290291
// Use the current time to not reveal our or contact's online time.
291292
timestamp: Ok(now),
292293
});
@@ -423,6 +424,14 @@ async fn import_vcard_contact(context: &Context, contact: &VcardContact) -> Resu
423424
);
424425
}
425426
}
427+
if let Some(biography) = &contact.biography {
428+
if let Err(e) = set_status(context, id, biography.to_owned(), false, false).await {
429+
warn!(
430+
context,
431+
"import_vcard_contact: Could not set biography for {}: {e:#}.", contact.addr
432+
);
433+
}
434+
}
426435
Ok(id)
427436
}
428437

src/contact/contact_tests.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,13 +1054,16 @@ async fn test_make_n_import_vcard() -> Result<()> {
10541054
let alice = &tcm.alice().await;
10551055
let bob = &tcm.bob().await;
10561056
bob.set_config(Config::Displayname, Some("Bob")).await?;
1057+
bob.set_config(Config::Selfstatus, Some("It's me, bob"))
1058+
.await?;
10571059
let avatar_path = bob.dir.path().join("avatar.png");
10581060
let avatar_bytes = include_bytes!("../../test-data/image/avatar64x64.png");
10591061
let avatar_base64 = base64::engine::general_purpose::STANDARD.encode(avatar_bytes);
10601062
tokio::fs::write(&avatar_path, avatar_bytes).await?;
10611063
bob.set_config(Config::Selfavatar, Some(avatar_path.to_str().unwrap()))
10621064
.await?;
10631065
let bob_addr = bob.get_config(Config::Addr).await?.unwrap();
1066+
let bob_biography = bob.get_config(Config::Selfstatus).await?.unwrap();
10641067
let chat = bob.create_chat(alice).await;
10651068
let sent_msg = bob.send_text(chat.id, "moin").await;
10661069
alice.recv_msg(&sent_msg).await;
@@ -1086,12 +1089,14 @@ async fn test_make_n_import_vcard() -> Result<()> {
10861089
assert_eq!(contacts[0].authname, "Bob".to_string());
10871090
assert_eq!(*contacts[0].key.as_ref().unwrap(), key_base64);
10881091
assert_eq!(*contacts[0].profile_image.as_ref().unwrap(), avatar_base64);
1092+
assert_eq!(*contacts[0].biography.as_ref().unwrap(), bob_biography);
10891093
let timestamp = *contacts[0].timestamp.as_ref().unwrap();
10901094
assert!(t0 <= timestamp && timestamp <= t1);
10911095
assert_eq!(contacts[1].addr, "fiona@example.net".to_string());
10921096
assert_eq!(contacts[1].authname, "".to_string());
10931097
assert_eq!(contacts[1].key, None);
10941098
assert_eq!(contacts[1].profile_image, None);
1099+
assert_eq!(contacts[1].biography, None);
10951100
let timestamp = *contacts[1].timestamp.as_ref().unwrap();
10961101
assert!(t0 <= timestamp && timestamp <= t1);
10971102

@@ -1114,6 +1119,7 @@ async fn test_make_n_import_vcard() -> Result<()> {
11141119
assert_eq!(contacts[0].authname, "Bob".to_string());
11151120
assert_eq!(*contacts[0].key.as_ref().unwrap(), key_base64);
11161121
assert_eq!(*contacts[0].profile_image.as_ref().unwrap(), avatar_base64);
1122+
assert_eq!(*contacts[0].biography.as_ref().unwrap(), bob_biography);
11171123
assert!(contacts[0].timestamp.is_ok());
11181124
assert_eq!(contacts[1].addr, "fiona@example.net".to_string());
11191125

@@ -1145,6 +1151,7 @@ async fn test_make_n_import_vcard() -> Result<()> {
11451151
assert_eq!(contacts[0].authname, "".to_string());
11461152
assert_eq!(contacts[0].key, None);
11471153
assert_eq!(contacts[0].profile_image, None);
1154+
assert_eq!(contacts[0].biography, None);
11481155
assert!(contacts[0].timestamp.is_ok());
11491156

11501157
Ok(())

0 commit comments

Comments
 (0)