From e6eb4eff3e9fac6b26b7afac88265348e3322868 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 6 Jul 2018 12:47:44 +0200 Subject: [PATCH] collect functions working with addresses in dc_contact --- src/dc_aheader.c | 4 +- src/dc_contact.c | 129 ++++++++++++++++++++++++------------------- src/dc_contact.h | 17 ++++-- src/dc_context.c | 20 +------ src/dc_context.h | 1 - src/dc_mimeparser.c | 6 +- src/dc_qr.c | 2 +- src/dc_receive_imf.c | 14 ++--- src/dc_securejoin.c | 2 +- 9 files changed, 99 insertions(+), 96 deletions(-) diff --git a/src/dc_aheader.c b/src/dc_aheader.c index 40b04904..785399a3 100644 --- a/src/dc_aheader.c +++ b/src/dc_aheader.c @@ -115,7 +115,7 @@ static int add_attribute(dc_aheader_t* aheader, const char* name, const char* va || aheader->addr /* email already given */) { return 0; } - aheader->addr = dc_normalize_addr(value); + aheader->addr = dc_addr_normalize(value); return 1; } #if 0 /* autocrypt 11/2017 no longer uses the type attribute and it will make the autocrypt header invalid */ @@ -289,7 +289,7 @@ dc_aheader_t* dc_aheader_new_from_imffields(const char* wanted_from, const struc /* header found, check if it is valid and matched the wanted address */ dc_aheader_t* test = dc_aheader_new(); if (!dc_aheader_set_from_string(test, optional_field->fld_value) - || strcasecmp(test->addr, wanted_from)!=0) { + || dc_addr_cmp(test->addr, wanted_from)!=0) { dc_aheader_unref(test); test = NULL; } diff --git a/src/dc_contact.c b/src/dc_contact.c index 4d23a2e3..dd9f887d 100644 --- a/src/dc_contact.c +++ b/src/dc_contact.c @@ -34,7 +34,6 @@ * objects using dc_get_contact(). * * @private @memberof dc_contact_t - * * @return The contact object. Must be freed using dc_contact_unref() when done. */ dc_contact_t* dc_contact_new(dc_context_t* context) @@ -56,9 +55,7 @@ dc_contact_t* dc_contact_new(dc_context_t* context) * Free a contact object. * * @memberof dc_contact_t - * * @param contact The contact object as created eg. by dc_get_contact(). - * * @return None. */ void dc_contact_unref(dc_contact_t* contact) @@ -79,9 +76,7 @@ void dc_contact_unref(dc_contact_t* contact) * use dc_contact_unref(). * * @private @memberof dc_contact_t - * * @param contact The contact object to free. - * * @return None. */ void dc_contact_empty(dc_contact_t* contact) @@ -115,9 +110,7 @@ void dc_contact_empty(dc_contact_t* contact) * Get the ID of the contact. * * @memberof dc_contact_t - * * @param contact The contact object. - * * @return the ID of the contact, 0 on errors. */ uint32_t dc_contact_get_id(const dc_contact_t* contact) @@ -133,9 +126,7 @@ uint32_t dc_contact_get_id(const dc_contact_t* contact) * Get email address. The email address is always set for a contact. * * @memberof dc_contact_t - * * @param contact The contact object. - * * @return String with the email address, must be free()'d. Never returns NULL. */ char* dc_contact_get_addr(const dc_contact_t* contact) @@ -157,9 +148,7 @@ char* dc_contact_get_addr(const dc_contact_t* contact) * To get a fine name to display in lists etc., use dc_contact_get_display_name() or dc_contact_get_name_n_addr(). * * @memberof dc_contact_t - * * @param contact The contact object. - * * @return String with the name to display, must be free()'d. Empty string if unset, never returns NULL. */ char* dc_contact_get_name(const dc_contact_t* contact) @@ -180,9 +169,7 @@ char* dc_contact_get_name(const dc_contact_t* contact) * To get the name editable in a formular, use dc_contact_get_name(). * * @memberof dc_contact_t - * * @param contact The contact object. - * * @return String with the name to display, must be free()'d. Never returns NULL. */ char* dc_contact_get_display_name(const dc_contact_t* contact) @@ -211,9 +198,7 @@ char* dc_contact_get_display_name(const dc_contact_t* contact) * The summary must not be spreaded via mail (To:, CC: ...) as it as it may contain sth. like "Daddy". * * @memberof dc_contact_t - * * @param contact The contact object. - * * @return Summary string, must be free()'d. Never returns NULL. */ char* dc_contact_get_name_n_addr(const dc_contact_t* contact) @@ -236,9 +221,7 @@ char* dc_contact_get_name_n_addr(const dc_contact_t* contact) * If the display name is not set, the e-mail address is returned. * * @memberof dc_contact_t - * * @param contact The contact object. - * * @return String with the name to display, must be free()'d. Never returns NULL. */ char* dc_contact_get_first_name(const dc_contact_t* contact) @@ -261,9 +244,7 @@ char* dc_contact_get_first_name(const dc_contact_t* contact) * To block or unblock a contact, use dc_block_contact(). * * @memberof dc_contact_t - * * @param contact The contact object. - * * @return 1=contact is blocked, 0=contact is not blocked. */ int dc_contact_is_blocked(const dc_contact_t* contact) @@ -302,9 +283,7 @@ cleanup: * The UI may draw a checkbox or sth. like that beside verified contacts. * * @memberof dc_contact_t - * * @param contact The contact object. - * * @return 0: contact is not verified. * 2: SELF and contact have verified their fingerprints in both directions; in the UI typically checkmarks are shown. */ @@ -338,9 +317,7 @@ cleanup: * If there is no space in the string, the whole string is returned. * * @private @memberof dc_contact_t - * * @param full_name Full name of the contact. - * * @return String with the first name, must be free()'d after usage. */ char* dc_get_first_name(const char* full_name) @@ -375,10 +352,8 @@ char* dc_get_first_name(const char* full_name) * Typically, this function is not needed as it is called implicitly by dc_add_address_book() * * @private @memberof dc_contact_t - * * @param full_name Buffer with the name, is modified during processing; the * resulting string may be shorter but never longer. - * * @return None. But the given buffer may be modified. */ void dc_normalize_name(char* full_name) @@ -418,35 +393,6 @@ void dc_normalize_name(char* full_name) } -/** - * Normalize an email address. - * - * Normalization includes: - * - removing `mailto:` prefix - * - * Not sure if we should also unifiy international characters before the @, - * see also https://autocrypt.readthedocs.io/en/latest/address-canonicalization.html - * - * @private @memberof dc_contact_t - * - * @param email_addr__ The email address to normalize. - * - * @return The normalized email address, must be free()'d. NULL is never returned. - */ -char* dc_normalize_addr(const char* email_addr__) -{ - char* addr = dc_strdup(email_addr__); - dc_trim(addr); - if (strncmp(addr, "mailto:", 7)==0) { - char* old = addr; - addr = dc_strdup(&old[7]); - free(old); - dc_trim(addr); - } - return addr; -} - - /** * Library-internal. * @@ -498,12 +444,63 @@ cleanup: } +/******************************************************************************* + * Working with e-mail-addresses + ******************************************************************************/ + + +/** + * Normalize an email address. + * + * Normalization includes: + * - Trimming + * - removing `mailto:` prefix + * + * Not sure if we should also unifiy international characters before the @, + * see also https://autocrypt.readthedocs.io/en/latest/address-canonicalization.html + * + * @private @memberof dc_contact_t + * @param addr The email address to normalize. + * @return The normalized email address, must be free()'d. NULL is never returned. + */ +char* dc_addr_normalize(const char* addr) +{ + char* addr_normalized = dc_strdup(addr); + dc_trim(addr_normalized); + if (strncmp(addr_normalized, "mailto:", 7)==0) { + char* old = addr_normalized; + addr_normalized = dc_strdup(&old[7]); + free(old); + dc_trim(addr_normalized); + } + return addr_normalized; +} + + +/** + * Compare two e-mail-addresses. + * The adresses will be normalized before compare and the comparison is case-insensitive. + * + * @private @memberof dc_contact_t + * @return 0: addresses are equal, >0: addr1 is larger than addr2, <0: addr1 is smaller than addr2 + */ +int dc_addr_cmp(const char* addr1, const char* addr2) +{ + char* norm1 = dc_addr_normalize(addr1); + char* norm2 = dc_addr_normalize(addr2); + int ret = strcasecmp(addr1, addr2); + free(norm1); + free(norm2); + return ret; +} + + /** * Check if a given e-mail-address is equal to the configured-self-address. * * @private @memberof dc_contact_t */ -int dc_addr_is_self(dc_context_t* context, const char* addr) +int dc_addr_equals_self(dc_context_t* context, const char* addr) { int ret = 0; char* normalized_addr = NULL; @@ -513,7 +510,7 @@ int dc_addr_is_self(dc_context_t* context, const char* addr) goto cleanup; } - normalized_addr = dc_normalize_addr(addr); + normalized_addr = dc_addr_normalize(addr); if (NULL==(self_addr=dc_sqlite3_get_config(context->sql, "configured_addr", NULL))) { goto cleanup; @@ -526,3 +523,23 @@ cleanup: free(normalized_addr); return ret; } + + +int dc_addr_equals_contact(dc_context_t* context, const char* addr, uint32_t contact_id) +{ + int addr_are_equal = 0; + if (addr) { + dc_contact_t* contact = dc_contact_new(context); + if (dc_contact_load_from_db(contact, context->sql, contact_id)) { + if (contact->addr) { + char* normalized_addr = dc_addr_normalize(addr); + if (strcasecmp(contact->addr, normalized_addr)==0) { + addr_are_equal = 1; + } + free(normalized_addr); + } + } + dc_contact_unref(contact); + } + return addr_are_equal; +} diff --git a/src/dc_contact.h b/src/dc_contact.h index 4e434a21..a9690a6f 100644 --- a/src/dc_contact.h +++ b/src/dc_contact.h @@ -78,12 +78,17 @@ struct _dc_contact #define DC_ORIGIN_MIN_VERIFIED (DC_ORIGIN_INCOMING_REPLY_TO) /* contacts with at least this origin value are verified and known not to be spam */ #define DC_ORIGIN_MIN_START_NEW_NCHAT (0x7FFFFFFF) /* contacts with at least this origin value start a new "normal" chat, defaults to off */ -int dc_contact_load_from_db (dc_contact_t*, dc_sqlite3_t*, uint32_t contact_id); -int dc_contact_n_peerstate_are_verified(const dc_contact_t*, const dc_apeerstate_t*); -void dc_normalize_name (char* full_name); -char* dc_normalize_addr (const char* email_addr); -char* dc_get_first_name (const char* full_name); -int dc_addr_is_self (dc_context_t*, const char* addr); + +int dc_contact_load_from_db (dc_contact_t*, dc_sqlite3_t*, uint32_t contact_id); +int dc_contact_n_peerstate_are_verified (const dc_contact_t*, const dc_apeerstate_t*); + +void dc_normalize_name (char* full_name); +char* dc_get_first_name (const char* full_name); + +int dc_addr_cmp (const char* addr1, const char* addr2); +char* dc_addr_normalize (const char* addr); +int dc_addr_equals_self (dc_context_t*, const char* addr); +int dc_addr_equals_contact (dc_context_t*, const char* addr, uint32_t contact_id); #ifdef __cplusplus diff --git a/src/dc_context.c b/src/dc_context.c index 01951e7b..fa555b59 100644 --- a/src/dc_context.c +++ b/src/dc_context.c @@ -2901,7 +2901,7 @@ uint32_t dc_add_or_lookup_contact( dc_context_t* context, /* normalize the email-address: - remove leading `mailto:` */ - addr = dc_normalize_addr(addr__); + addr = dc_addr_normalize(addr__); /* rough check if email-address is valid */ if (strlen(addr) < 3 || strchr(addr, '@')==NULL || strchr(addr, '.')==NULL) { @@ -3614,24 +3614,6 @@ cleanup: } -int dc_contact_addr_equals(dc_context_t* context, uint32_t contact_id, const char* other_addr) -{ - int addr_are_equal = 0; - if (other_addr) { - dc_contact_t* contact = dc_contact_new(context); - if (dc_contact_load_from_db(contact, context->sql, contact_id)) { - if (contact->addr) { - if (strcasecmp(contact->addr, other_addr)==0) { - addr_are_equal = 1; - } - } - } - dc_contact_unref(contact); - } - return addr_are_equal; -} - - /******************************************************************************* * Handle Messages ******************************************************************************/ diff --git a/src/dc_context.h b/src/dc_context.h index ac1ae8c1..3caf43f4 100644 --- a/src/dc_context.h +++ b/src/dc_context.h @@ -135,7 +135,6 @@ uint32_t dc_add_or_lookup_contact (dc_context_t*, const int dc_get_contact_origin (dc_context_t*, uint32_t id, int* ret_blocked); int dc_is_contact_blocked (dc_context_t*, uint32_t id); int dc_real_contact_exists (dc_context_t*, uint32_t id); -int dc_contact_addr_equals (dc_context_t*, uint32_t contact_id, const char* other_addr); void dc_scaleup_contact_origin (dc_context_t*, uint32_t contact_id, int origin); void dc_unarchive_chat (dc_context_t*, uint32_t chat_id); size_t dc_get_chat_cnt (dc_context_t*); diff --git a/src/dc_mimeparser.c b/src/dc_mimeparser.c index d9328391..b7d42ba2 100644 --- a/src/dc_mimeparser.c +++ b/src/dc_mimeparser.c @@ -415,7 +415,7 @@ static void mailimf_get_recipients__add_addr(dc_hash_t* recipients, struct maili { /* only used internally by mailimf_get_recipients() */ if (mb) { - char* addr_norm = dc_normalize_addr(mb->mb_addr_spec); + char* addr_norm = dc_addr_normalize(mb->mb_addr_spec); dc_hash_insert(recipients, addr_norm, strlen(addr_norm), (void*)1); free(addr_norm); } @@ -586,7 +586,7 @@ char* mailimf_find_first_addr(const struct mailimf_mailbox_list* mb_list) for (cur = clist_begin(mb_list->mb_list); cur!=NULL ; cur=clist_next(cur)) { struct mailimf_mailbox* mb = (struct mailimf_mailbox*)clist_content(cur); if (mb && mb->mb_addr_spec) { - return dc_normalize_addr(mb->mb_addr_spec); + return dc_addr_normalize(mb->mb_addr_spec); } } return NULL; @@ -1878,7 +1878,7 @@ int dc_mimeparser_sender_equals_recipient(dc_mimeparser_t* mimeparser) goto cleanup; } - from_addr_norm = dc_normalize_addr(mb->mb_addr_spec); + from_addr_norm = dc_addr_normalize(mb->mb_addr_spec); /* get To:/Cc: and check there is exactly one recipent */ recipients = mailimf_get_recipients(mimeparser->header_root); diff --git a/src/dc_qr.c b/src/dc_qr.c index d2cbd8c7..d920523b 100644 --- a/src/dc_qr.c +++ b/src/dc_qr.c @@ -176,7 +176,7 @@ dc_lot_t* dc_check_qr(dc_context_t* context, const char* qr) if (addr) { char* temp = dc_urldecode(addr); free(addr); addr = temp; /* urldecoding is needed at least for OPENPGP4FPR but should not hurt in the other cases */ - temp = dc_normalize_addr(addr); free(addr); addr = temp; + temp = dc_addr_normalize(addr); free(addr); addr = temp; if (strlen(addr) < 3 || strchr(addr, '@')==NULL || strchr(addr, '.')==NULL) { qr_parsed->state = DC_QR_ERROR; diff --git a/src/dc_receive_imf.c b/src/dc_receive_imf.c index 4ca14939..637e52bc 100644 --- a/src/dc_receive_imf.c +++ b/src/dc_receive_imf.c @@ -49,7 +49,7 @@ static void add_or_lookup_contact_by_addr(dc_context_t* context, const char* dis *check_self = 0; char* self_addr = dc_sqlite3_get_config(context->sql, "configured_addr", ""); - if (strcasecmp(self_addr, addr_spec)==0) { + if (dc_addr_cmp(self_addr, addr_spec)==0) { *check_self = 1; } free(self_addr); @@ -800,7 +800,7 @@ static void create_or_lookup_group(dc_context_t* context, dc_mimeparser_t* mime_ && grpid && grpname && X_MrRemoveFromGrp==NULL /*otherwise, a pending "quit" message may pop up*/ - && (!group_explicitly_left || (X_MrAddToGrp&&strcasecmp(self_addr,X_MrAddToGrp)==0)) /*re-create explicitly left groups only if ourself is re-added*/ + && (!group_explicitly_left || (X_MrAddToGrp&&dc_addr_cmp(self_addr,X_MrAddToGrp)==0)) /*re-create explicitly left groups only if ourself is re-added*/ ) { int create_verified = 0; @@ -886,13 +886,13 @@ static void create_or_lookup_group(dc_context_t* context, dc_mimeparser_t* mime_ sqlite3_step(stmt); sqlite3_finalize(stmt); - if (skip==NULL || strcasecmp(self_addr, skip) != 0) { + if (skip==NULL || dc_addr_cmp(self_addr, skip) != 0) { dc_add_to_chat_contacts_table(context, chat_id, DC_CONTACT_ID_SELF); } if (from_id > DC_CONTACT_ID_LAST_SPECIAL) { - if (dc_contact_addr_equals(context, from_id, self_addr)==0 - && (skip==NULL || dc_contact_addr_equals(context, from_id, skip)==0)) { + if (dc_addr_equals_contact(context, self_addr, from_id)==0 + && (skip==NULL || dc_addr_equals_contact(context, skip, from_id)==0)) { dc_add_to_chat_contacts_table(context, chat_id, from_id); } } @@ -900,8 +900,8 @@ static void create_or_lookup_group(dc_context_t* context, dc_mimeparser_t* mime_ for (i = 0; i < to_ids_cnt; i++) { uint32_t to_id = dc_array_get_id(to_ids, i); /* to_id is only once in to_ids and is non-special */ - if (dc_contact_addr_equals(context, to_id, self_addr)==0 - && (skip==NULL || dc_contact_addr_equals(context, to_id, skip)==0)) { + if (dc_addr_equals_contact(context, self_addr, to_id)==0 + && (skip==NULL || dc_addr_equals_contact(context, skip, to_id)==0)) { dc_add_to_chat_contacts_table(context, chat_id, to_id); } } diff --git a/src/dc_securejoin.c b/src/dc_securejoin.c index 6f88024a..924a71f8 100644 --- a/src/dc_securejoin.c +++ b/src/dc_securejoin.c @@ -740,7 +740,7 @@ int dc_handle_securejoin_handshake(dc_context_t* context, dc_mimeparser_t* mimep context->cb(context, DC_EVENT_CONTACTS_CHANGED, 0/*no select event*/, 0); if (join_vg) { - if (!dc_addr_is_self(context, lookup_field(mimeparser, "Chat-Group-Member-Added"))) { + if (!dc_addr_equals_self(context, lookup_field(mimeparser, "Chat-Group-Member-Added"))) { dc_log_info(context, 0, "Message belongs to a different handshake (scaled up contact anyway to allow creation of group)."); goto cleanup; }