api!: remove Contact.get_name_n_addr() and related APIs

UIs should use display name everywhere and avoid displaying email addresses.

BREAKING CHANGE: dc_contact_get_name_n_addr() CFFI is removed
BREAKING CHANGE: JSON-RPC contact objects don't have nameAndAddr field anymore
This commit is contained in:
link2xt
2026-09-18 17:35:50 +00:00
committed by l
parent 7876115d86
commit e1d58706ce
7 changed files with 8 additions and 69 deletions

View File

@@ -104,7 +104,7 @@ pub fn sanitize_name_and_addr(name: &str, addr: &str) -> (String, String) {
let mut name = sanitize_name(name); let mut name = sanitize_name(name);
// If the 'display name' is just the address, remove it: // If the 'display name' is just the address, remove it:
// Otherwise, the contact would sometimes be shown as "alice@example.com (alice@example.com)" (see `get_name_n_addr()`). // Otherwise, the contact would sometimes be shown as "alice@example.com (alice@example.com)".
// If the display name is empty, DC will just show the address when it needs a display name. // If the display name is empty, DC will just show the address when it needs a display name.
if name == addr { if name == addr {
name = "".to_string(); name = "".to_string();

View File

@@ -4927,7 +4927,6 @@ uint32_t dc_msg_get_saved_msg_id (const dc_msg_t* msg);
* By default, these names are equal, * By default, these names are equal,
* but functions working with contact names * but functions working with contact names
* (e.g. dc_contact_get_name(), dc_contact_get_display_name(), * (e.g. dc_contact_get_name(), dc_contact_get_display_name(),
* dc_contact_get_name_n_addr(),
* dc_create_contact() or dc_add_address_book()) * dc_create_contact() or dc_add_address_book())
* only affect the given-name. * only affect the given-name.
*/ */
@@ -4977,7 +4976,7 @@ char* dc_contact_get_addr (const dc_contact_t* contact);
* The function does not return the contact name as received from the network. * The function does not return the contact name as received from the network.
* *
* This name is typically used in a form where the user can edit the name of a contact. * This name is typically used in a form where the user can edit the name of a contact.
* To get a fine name to display in lists etc., use dc_contact_get_display_name() or dc_contact_get_name_n_addr(). * To get a fine name to display in lists etc., use dc_contact_get_display_name().
* *
* @memberof dc_contact_t * @memberof dc_contact_t
* @param contact The contact object. * @param contact The contact object.
@@ -5032,23 +5031,6 @@ char* dc_contact_get_display_name (const dc_contact_t* contact);
#define dc_contact_get_first_name dc_contact_get_display_name #define dc_contact_get_first_name dc_contact_get_display_name
/**
* Get a summary of name and address.
*
* The returned string is either "Name (email@domain.com)" or just
* "email@domain.com" if the name is unset.
*
* The summary is typically used when asking the user something about the contact.
* The attached e-mail address makes the question unique, e.g. "Chat with Alan Miller (am@uniquedomain.com)?"
*
* @memberof dc_contact_t
* @param contact The contact object.
* @return A summary string, must be released using dc_str_unref().
* Never returns NULL.
*/
char* dc_contact_get_name_n_addr (const dc_contact_t* contact);
/** /**
* Get the contact's profile image. * Get the contact's profile image.
* This is the image set by each remote user on their own * This is the image set by each remote user on their own

View File

@@ -3979,18 +3979,6 @@ pub unsafe extern "C" fn dc_contact_get_display_name(
ffi_contact.contact.get_display_name().strdup() ffi_contact.contact.get_display_name().strdup()
} }
#[unsafe(no_mangle)]
pub unsafe extern "C" fn dc_contact_get_name_n_addr(
contact: *mut dc_contact_t,
) -> *mut libc::c_char {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_name_n_addr()");
return "".strdup();
}
let ffi_contact = unsafe { &*contact };
ffi_contact.contact.get_name_n_addr().strdup()
}
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
pub unsafe extern "C" fn dc_contact_get_profile_image( pub unsafe extern "C" fn dc_contact_get_profile_image(
contact: *mut dc_contact_t, contact: *mut dc_contact_t,

View File

@@ -17,7 +17,6 @@ pub struct ContactObject {
id: u32, id: u32,
name: String, name: String,
profile_image: Option<String>, // BLOBS profile_image: Option<String>, // BLOBS
name_and_addr: String,
is_blocked: bool, is_blocked: bool,
/// Is the contact a key contact. /// Is the contact a key contact.
@@ -57,7 +56,6 @@ impl ContactObject {
id: contact.id.to_u32(), id: contact.id.to_u32(),
name: contact.get_name().to_owned(), name: contact.get_name().to_owned(),
profile_image, //BLOBS profile_image, //BLOBS
name_and_addr: contact.get_name_n_addr(),
is_blocked: contact.is_blocked(), is_blocked: contact.is_blocked(),
is_key_contact: contact.is_key_contact(), is_key_contact: contact.is_key_contact(),
e2ee_avail: contact.e2ee_avail(context).await?, e2ee_avail: contact.e2ee_avail(context).await?,

View File

@@ -1113,11 +1113,11 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
let contact_id = ContactId::new(arg1.parse()?); let contact_id = ContactId::new(arg1.parse()?);
let contact = Contact::get_by_id(&context, contact_id).await?; let contact = Contact::get_by_id(&context, contact_id).await?;
let name_n_addr = contact.get_name_n_addr(); let name = contact.get_display_name();
let addr = contact.get_addr();
let mut res = format!( let mut res = format!(
"Contact info for: {}:\nIcon: {}\n", "Contact info for: {name} ({addr}):\nIcon: {}\n",
name_n_addr,
match contact.get_profile_image(&context).await? { match contact.get_profile_image(&context).await? {
Some(image) => image.to_str().unwrap().to_string(), Some(image) => image.to_str().unwrap().to_string(),
None => "NoIcon".to_string(), None => "NoIcon".to_string(),

View File

@@ -486,8 +486,8 @@ pub struct Contact {
/// The contact ID. /// The contact ID.
pub id: ContactId, pub id: ContactId,
/// Contact name. It is recommended to use `Contact::get_name`, /// Contact name. It is recommended to use `Contact::get_name`
/// `Contact::get_display_name` or `Contact::get_name_n_addr` to access this field. /// or `Contact::get_display_name` to access this field.
/// May be empty, initially set to `authname`. /// May be empty, initially set to `authname`.
name: String, name: String,
@@ -1576,7 +1576,7 @@ WHERE addr=?
/// May be an empty string. /// May be an empty string.
/// ///
/// This name is typically used in a form where the user can edit the name of a contact. /// This name is typically used in a form where the user can edit the name of a contact.
/// To get a fine name to display in lists etc., use `Contact::get_display_name` or `Contact::get_name_n_addr`. /// To get a fine name to display in lists etc., use `Contact::get_display_name`.
pub fn get_name(&self) -> &str { pub fn get_name(&self) -> &str {
&self.name &self.name
} }
@@ -1596,26 +1596,6 @@ WHERE addr=?
&self.addr &self.addr
} }
/// Get a summary of name and address.
///
/// The returned string is either "Name (email@domain.com)" or just
/// "email@domain.com" if the name is unset.
///
/// The result should only be used locally and never sent over the network
/// as it leaks the local contact name.
///
/// The summary is typically used when asking the user something about the contact.
/// The attached email address makes the question unique, eg. "Chat with Alan Miller (am@uniquedomain.com)?"
pub fn get_name_n_addr(&self) -> String {
if !self.name.is_empty() {
format!("{} ({})", self.name, self.addr)
} else if !self.authname.is_empty() {
format!("{} ({})", self.authname, self.addr)
} else {
(&self.addr).into()
}
}
/// Get the contact's profile image. /// Get the contact's profile image.
/// This is the image set by each remote user on their own /// This is the image set by each remote user on their own
/// using set_config(context, "selfavatar", image). /// using set_config(context, "selfavatar", image).

View File

@@ -253,7 +253,6 @@ async fn test_add_or_lookup() {
assert_eq!(contact.get_authname(), "bla foo"); assert_eq!(contact.get_authname(), "bla foo");
assert_eq!(contact.get_display_name(), "Name one"); assert_eq!(contact.get_display_name(), "Name one");
assert_eq!(contact.get_addr(), "one@eins.org"); assert_eq!(contact.get_addr(), "one@eins.org");
assert_eq!(contact.get_name_n_addr(), "Name one (one@eins.org)");
// modify first added contact // modify first added contact
let (contact_id_test, sth_modified) = Contact::add_or_lookup( let (contact_id_test, sth_modified) = Contact::add_or_lookup(
@@ -286,7 +285,6 @@ async fn test_add_or_lookup() {
assert_eq!(contact.get_name(), ""); assert_eq!(contact.get_name(), "");
assert_eq!(contact.get_display_name(), "three@drei.sam"); assert_eq!(contact.get_display_name(), "three@drei.sam");
assert_eq!(contact.get_addr(), "three@drei.sam"); assert_eq!(contact.get_addr(), "three@drei.sam");
assert_eq!(contact.get_name_n_addr(), "three@drei.sam");
// add name to third contact from incoming message (this becomes authorized name) // add name to third contact from incoming message (this becomes authorized name)
let (contact_id_test, sth_modified) = Contact::add_or_lookup( let (contact_id_test, sth_modified) = Contact::add_or_lookup(
@@ -300,7 +298,6 @@ async fn test_add_or_lookup() {
assert_eq!(contact_id, contact_id_test); assert_eq!(contact_id, contact_id_test);
assert_eq!(sth_modified, Modifier::Modified); assert_eq!(sth_modified, Modifier::Modified);
let contact = Contact::get_by_id(&t, contact_id).await.unwrap(); let contact = Contact::get_by_id(&t, contact_id).await.unwrap();
assert_eq!(contact.get_name_n_addr(), "m. serious (three@drei.sam)");
assert!(!contact.is_blocked()); assert!(!contact.is_blocked());
// manually edit name of third contact (does not changed authorized name) // manually edit name of third contact (does not changed authorized name)
@@ -316,7 +313,6 @@ async fn test_add_or_lookup() {
assert_eq!(sth_modified, Modifier::Modified); assert_eq!(sth_modified, Modifier::Modified);
let contact = Contact::get_by_id(&t, contact_id).await.unwrap(); let contact = Contact::get_by_id(&t, contact_id).await.unwrap();
assert_eq!(contact.get_authname(), "m. serious"); assert_eq!(contact.get_authname(), "m. serious");
assert_eq!(contact.get_name_n_addr(), "schnucki (three@drei.sam)");
assert!(!contact.is_blocked()); assert!(!contact.is_blocked());
// Fourth contact: // Fourth contact:
@@ -334,7 +330,6 @@ async fn test_add_or_lookup() {
assert_eq!(contact.get_name(), "Wonderland, Alice"); assert_eq!(contact.get_name(), "Wonderland, Alice");
assert_eq!(contact.get_display_name(), "Wonderland, Alice"); assert_eq!(contact.get_display_name(), "Wonderland, Alice");
assert_eq!(contact.get_addr(), "alice@w.de"); assert_eq!(contact.get_addr(), "alice@w.de");
assert_eq!(contact.get_name_n_addr(), "Wonderland, Alice (alice@w.de)");
// check SELF // check SELF
let contact = Contact::get_by_id(&t, ContactId::SELF).await.unwrap(); let contact = Contact::get_by_id(&t, ContactId::SELF).await.unwrap();
@@ -373,7 +368,6 @@ async fn test_contact_name_changes() -> Result<()> {
assert_eq!(contact.get_authname(), ""); assert_eq!(contact.get_authname(), "");
assert_eq!(contact.get_name(), ""); assert_eq!(contact.get_name(), "");
assert_eq!(contact.get_display_name(), "f@example.org"); assert_eq!(contact.get_display_name(), "f@example.org");
assert_eq!(contact.get_name_n_addr(), "f@example.org");
let contacts = Contact::get_all(&t, 0, Some("f@example.org")).await?; let contacts = Contact::get_all(&t, 0, Some("f@example.org")).await?;
assert_eq!(contacts.len(), 0); assert_eq!(contacts.len(), 0);
@@ -399,7 +393,6 @@ async fn test_contact_name_changes() -> Result<()> {
assert_eq!(contact.get_authname(), "Flobbyfoo"); assert_eq!(contact.get_authname(), "Flobbyfoo");
assert_eq!(contact.get_name(), ""); assert_eq!(contact.get_name(), "");
assert_eq!(contact.get_display_name(), "Flobbyfoo"); assert_eq!(contact.get_display_name(), "Flobbyfoo");
assert_eq!(contact.get_name_n_addr(), "Flobbyfoo (f@example.org)");
let contacts = Contact::get_all(&t, 0, Some("f@example.org")).await?; let contacts = Contact::get_all(&t, 0, Some("f@example.org")).await?;
assert_eq!(contacts.len(), 0); assert_eq!(contacts.len(), 0);
let contacts = Contact::get_all(&t, 0, Some("flobbyfoo")).await?; let contacts = Contact::get_all(&t, 0, Some("flobbyfoo")).await?;
@@ -429,7 +422,6 @@ async fn test_contact_name_changes() -> Result<()> {
assert_eq!(contact.get_authname(), "Foo Flobby"); assert_eq!(contact.get_authname(), "Foo Flobby");
assert_eq!(contact.get_name(), ""); assert_eq!(contact.get_name(), "");
assert_eq!(contact.get_display_name(), "Foo Flobby"); assert_eq!(contact.get_display_name(), "Foo Flobby");
assert_eq!(contact.get_name_n_addr(), "Foo Flobby (f@example.org)");
let contacts = Contact::get_all(&t, 0, Some("f@example.org")).await?; let contacts = Contact::get_all(&t, 0, Some("f@example.org")).await?;
assert_eq!(contacts.len(), 0); assert_eq!(contacts.len(), 0);
let contacts = Contact::get_all(&t, 0, Some("flobbyfoo")).await?; let contacts = Contact::get_all(&t, 0, Some("flobbyfoo")).await?;
@@ -447,7 +439,6 @@ async fn test_contact_name_changes() -> Result<()> {
assert_eq!(contact.get_authname(), "Foo Flobby"); assert_eq!(contact.get_authname(), "Foo Flobby");
assert_eq!(contact.get_name(), "Falk"); assert_eq!(contact.get_name(), "Falk");
assert_eq!(contact.get_display_name(), "Falk"); assert_eq!(contact.get_display_name(), "Falk");
assert_eq!(contact.get_name_n_addr(), "Falk (f@example.org)");
let contacts = Contact::get_all(&t, 0, Some("f@example.org")).await?; let contacts = Contact::get_all(&t, 0, Some("f@example.org")).await?;
assert_eq!(contacts.len(), 0); assert_eq!(contacts.len(), 0);
let contacts = Contact::get_all(&t, 0, Some("falk")).await?; let contacts = Contact::get_all(&t, 0, Some("falk")).await?;