From d4e93269f280a57863f55f30a910afabaf424c24 Mon Sep 17 00:00:00 2001 From: Martin Lambers Date: Sat, 28 Sep 2024 13:13:37 +0200 Subject: [PATCH] Properly encode non-ASCII strings in the From header This fixes Github issue #162. --- src/msmtp.c | 4 +++- src/tools.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tools.h | 8 ++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/msmtp.c b/src/msmtp.c index 95297a6..75a4a29 100644 --- a/src/msmtp.c +++ b/src/msmtp.c @@ -4187,8 +4187,10 @@ int main(int argc, char *argv[]) { if (account->from_full_name) { + char *enc_name = encode_for_header(account->from_full_name); fprintf(prepend_header_tmpfile, "From: %s <%s>\n", - account->from_full_name, account->from); + enc_name, account->from); + free(enc_name); } else { diff --git a/src/tools.c b/src/tools.c index d029f24..11718d3 100644 --- a/src/tools.c +++ b/src/tools.c @@ -50,9 +50,11 @@ #include #ifdef ENABLE_NLS # include +# include #endif #include "xalloc.h" +#include "base64.h" #include "tools.h" @@ -907,3 +909,57 @@ int check_hostname_matches_domain(const char *hostname, const char *domain) return (hostname[hostname_len - 1 - domain_len] == '.' && strcasecmp(hostname + (hostname_len - domain_len), domain) == 0) ? 1 : 0; } + + +/* + * encode_for_header() + * + * see tools.h + */ + +char *encode_for_header(const char *s) +{ + int needsEncoding = 0; + for (int i = 0; s[i]; i++) + { + if (s[i] < 32 || s[i] >= 127) + { + needsEncoding = 1; + break; + } + } + if (needsEncoding) + { + /* create a string of the form "=?ENCODING?B?BASE64STRING?=" */ + size_t s_len = strlen(s); + size_t b64_s_len = BASE64_LENGTH(s_len); + char* encoding = xstrdup( +#ifdef ENABLE_NLS + nl_langinfo(CODESET) +#else + "UTF-8"; +#endif + ); + size_t e_len = strlen(encoding); + size_t enc_len = 2 + e_len + 3 + b64_s_len + 3; + char *enc = xmalloc(enc_len + 1); + size_t i = 0; + enc[i++] = '='; + enc[i++] = '?'; + for (size_t j = 0; j < e_len; j++) + { + enc[i++] = tolower(encoding[j]); + } + free(encoding); + enc[i++] = '?'; + enc[i++] = 'B'; + enc[i++] = '?'; + base64_encode(s, s_len, enc + i, enc_len - i + 1); + strcat(enc, "?="); + return enc; + } + else + { + return xstrdup(s); + } +} diff --git a/src/tools.h b/src/tools.h index 86ba9ff..ebdeb73 100644 --- a/src/tools.h +++ b/src/tools.h @@ -259,4 +259,12 @@ void split_mail_address(const char *address, char **local_part, char **domain_pa */ int check_hostname_matches_domain(const char *hostname, const char *domain); +/* + * encode_for_header() + * + * Encode a string so that it can be used in a mail header. + * The result is allocated and needs to be freed. + */ +char *encode_for_header(const char *s); + #endif