git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 4/5] mailmap: use case-sensitive comparisons for local-parts and names

From
brian m. carlson <sandals@crustytoothpaste.net>
Date
Jan 3, 2021, 21:18 UTC
Message-ID
<20210103211849.2691287-5-sandals@crustytoothpaste.net>
In-Reply-To
<20210103211849.2691287-1-sandals@crustytoothpaste.net>

RFC 5321 is clear that the local-part of an email address (the part before the at sign) is case sensitive, and this has been the case since the original RFC 821. It directs us that "the local-part MUST be interpreted and assigned semantics only by the host specified in the domain part of the address."

Since we are not that party, it's not correct for us to compare them case insensitively. However, we do still want to compare the domain parts case insensitively, so let's add a helper that downcases the domain and then compare byte by byte.

Similarly, it's not possible for us to correctly case-fold text in a locale-insensitive way, so our handling of personal names has also been subject to bugs. Additionally, we've never handled non-ASCII characters correctly, which means that our previous comparisons really only worked well for a fraction of the people on the planet. Since our code wasn't right and it's basically impossible to compare personal names without regard to case, let's also switch our matching of names to be byte by byte.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 mailmap.c          | 27 ++++++++++++++++++++++++---
 t/t4203-mailmap.sh |  4 ++--
 2 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/mailmap.c b/mailmap.c
index d3287b409a..5c52dbb7e0 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -64,7 +64,22 @@ static void free_mailmap_entry(void *p, const char *s)
  */
 static int namemap_cmp(const char *a, const char *b)
 {
-	return strcasecmp(a, b);
+	return strcmp(a, b);
+}
+
+/*
+ * Lowercases the domain (and only the domain) part of an email address.  The
+ * local-part, which is defined by RFC 5321 to be case sensitive, is not
+ * affected.
+ */
+static char *lowercase_email(char *s)
+{
+	char *end = strchrnul(s, '@');
+	while (*end) {
+		*end = tolower(*end);
+		end++;
+	}
+	return s;
 }
 
 static void add_mapping(struct string_list *map,
@@ -74,9 +89,13 @@ static void add_mapping(struct string_list *map,
 	struct mailmap_entry *me;
 	struct string_list_item *item;
 
+	lowercase_email(new_email);
+
 	if (old_email == NULL) {
 		old_email = new_email;
 		new_email = NULL;
+	} else {
+		lowercase_email(old_email);
 	}
 
 	item = string_list_insert(map, old_email);
@@ -300,7 +319,7 @@ static struct string_list_item *lookup_prefix(struct string_list *map,
 	 * real location of the key if one exists.
 	 */
 	while (0 <= --i && i < map->nr) {
-		int cmp = strncasecmp(map->items[i].string, string, len);
+		int cmp = strncmp(map->items[i].string, string, len);
 		if (cmp < 0)
 			/*
 			 * "i" points at a key definitely below the prefix;
@@ -323,6 +342,7 @@ int map_user(struct mailmap *map,
 	     const char **email, size_t *emaillen,
 	     const char **name, size_t *namelen)
 {
+	char *searchable_email = xstrndup(*email, *emaillen);
 	struct string_list_item *item;
 	struct mailmap_entry *me;
 
@@ -330,7 +350,8 @@ int map_user(struct mailmap *map,
 		 (int)*namelen, debug_str(*name),
 		 (int)*emaillen, debug_str(*email));
 
-	item = lookup_prefix(map->mailmap, *email, *emaillen);
+	item = lookup_prefix(map->mailmap, searchable_email, *emaillen);
+	free(searchable_email);
 	if (item != NULL) {
 		me = (struct mailmap_entry *)item->util;
 		if (me->namemap.nr) {
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 32e849504c..df4a0e03cc 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -187,7 +187,7 @@ nick1 (1):
 
 EOF
 
-test_expect_failure 'name entry after email entry, case-sensitive local-part' '
+test_expect_success 'name entry after email entry, case-sensitive local-part' '
 	mkdir -p internal_mailmap &&
 	echo "<bugs@company.xy> <bugs@company.xx>" >internal_mailmap/.mailmap &&
 	echo "Internal Guy <BUGS@company.xx>" >>internal_mailmap/.mailmap &&
@@ -195,7 +195,7 @@ test_expect_failure 'name entry after email entry, case-sensitive local-part' '
 	test_cmp expect actual
 '
 
-test_expect_failure 'name entry after email entry, case-sensitive personal name' '
+test_expect_success 'name entry after email entry, case-sensitive personal name' '
 	mkdir -p internal_mailmap &&
 	echo "<bugs@company.xy> <bugs@company.xx>" >internal_mailmap/.mailmap &&
 	echo "Nick1 <bugs@company.xx> NICK1 <bugs@company.xx>" >internal_mailmap/.mailmap &&
Previous: brian m. carlsonNext: Ævar Arnfjörð Bjarmason
Message 8 of 19 in “Hashed mailmap”
  1. 0/5 Hashed mailmapbrian m. carlson, Jan 3, 2021
  2. 1/5 mailmap: add a function to inspect the number of entriesbrian m. carlson, Jan 3, 2021
  3. Ævar Arnfjörð BjarmasonJan 4, 2021
  4. René ScharfeJan 4, 2021
  5. 2/5 mailmap: switch to opaque structbrian m. carlson, Jan 3, 2021
  6. Ævar Arnfjörð BjarmasonJan 4, 2021
  7. 3/5 t4203: add failing test for case-sensitive local-parts and namesbrian m. carlson, Jan 3, 2021
  8. 4/5 mailmap: use case-sensitive comparisons for local-parts and namesbrian m. carlson, Jan 3, 2021
  9. Ævar Arnfjörð BjarmasonJan 4, 2021
  10. Junio C HamanoJan 6, 2021
  11. Ævar Arnfjörð BjarmasonJan 12, 2021
  12. 5/5 mailmap: support hashed entries in mailmapsbrian m. carlson, Jan 3, 2021
  13. Ævar Arnfjörð BjarmasonJan 5, 2021
  14. brian m. carlsonJan 6, 2021
  15. Ævar Arnfjörð BjarmasonJan 10, 2021
  16. brian m. carlsonJan 10, 2021
  17. Junio C HamanoJan 5, 2021
  18. brian m. carlsonJan 6, 2021
  19. Junio C HamanoJan 6, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.