[M-git] Mahogany sources repository. branch master updated. v0.67-877-gbcc0c9d1
vadz via Mahogany-cvsupdates <[email protected]> Fri, 21 Mar 2025 03:59:40 +0000
| Newsgroups | gmane.mail.mahogany.cvs |
|---|---|
| Message-ID | <[email protected]> |
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Mahogany sources repository.".
The branch, master has been updated
via bcc0c9d101a040236ffe7d16c659956ebc0eb536 (commit)
via 1ce4e762a220d22008d95c29033b475dc41bbf11 (commit)
via 583336819f11ab5e23bddfff15be73b6daa35854 (commit)
via 570b1608a0d04a22ea2d106e53ebbe9dcbc82c37 (commit)
via 7517e90b2e31776448ff881a3cfaa1435f55a6ce (commit)
via 50790426be9c783e4edea4a2e3ecc807efc90594 (commit)
via 044f6c4bc0c2a405f81617a9abd67929b9cd0077 (commit)
via ba821e338687c1602fc536c3db591c10ca281a8a (commit)
via f14cf32b94dd6d98b4ccf4bd52f1e787bceab2a3 (commit)
via 9f4b95a7555bf07860a2286f1f04b66885e0b71a (commit)
via ba1921ea80e18ca17d4978c5a57da36625c7233f (commit)
via 3d1f4cf9b4ac17f17b49f49145d51e3c0c131d4a (commit)
via 1ac798f306170815921c6d482d668cf27ede5e88 (commit)
via 868edf0e0f3facab75414106cbc04f2b27ed05b9 (commit)
via 409d6974435db410434831eed0ef2d561fcb6569 (commit)
via 6a5486de8057dc3e64036d61c67e769ccae2f8a6 (commit)
via 06d5b206e24809152471268a618bd0283722e4ee (commit)
via 64372212fc20adc244123679f96a2f5612b147d0 (commit)
via 610297bac03abfb00321bd71289c82067f51a858 (commit)
via 43f8634ada42e8e998e9962c7f1fdea7adb4a07e (commit)
via a1e6cff79899ea701e8e6e033618a622d501a674 (commit)
via 5bc4dbcf83c197a1ede8eac399b55d6a1ecb50dc (commit)
from eb1e403d031263ca26c36b5cb70aa45ea627d6dc (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit bcc0c9d101a040236ffe7d16c659956ebc0eb536
Author: Vadim Zeitlin <[email protected]>
Date: Fri Mar 21 04:56:49 2025 +0100
Strip literal CR LF from the internal header representation
Having CR LF in the "References:" header broke its value in the outgoing
messages after recent changes to MIME::EncodeHeader() which resulted in
not just throwing away all whitespace characters in the header when
encoding it.
It's not completely clear if AddHeaderEntry() should be given strings
with CR LF or if they should be stripped at some higher level, but for
now do it here to at least ensure that the program generates correct
outgoing messages.
diff --git a/src/gui/wxComposeView.cpp b/src/gui/wxComposeView.cpp
index f49cec7d..736bd151 100644
--- a/src/gui/wxComposeView.cpp
+++ b/src/gui/wxComposeView.cpp
@@ -5375,8 +5375,26 @@ void wxComposeView::OnSendThreadDone(wxThreadEvent& evt)
}
void
-wxComposeView::AddHeaderEntry(const String& name, const String& value)
+wxComposeView::AddHeaderEntry(const String& name, const String& valueOrig)
{
+ // We may need to unfold the header if it contains line folds, we don't want
+ // to have them in the logical header value that we store internally.
+ String value;
+ for ( size_t pos = 0;; )
+ {
+ auto eol = valueOrig.find("\r\n ", pos);
+ if ( eol == String::npos )
+ {
+ value.append(valueOrig, pos, String::npos);
+ break;
+ }
+
+ value.append(valueOrig, pos, eol - pos);
+ value += ' ';
+
+ pos = eol + 3;
+ }
+
// first check if we don't already have a header with this name
const StringList::iterator end = m_extraHeadersNames.end();
for ( StringList::iterator i = m_extraHeadersNames.begin(),
commit 1ce4e762a220d22008d95c29033b475dc41bbf11
Author: Vadim Zeitlin <[email protected]>
Date: Fri Mar 21 04:18:10 2025 +0100
Default encoding to UTF-8 in the MIME encoding test
This is by far the most common.
diff --git a/tests/mime/decode.cpp b/tests/mime/decode.cpp
index 168d4b03..04c9ce77 100644
--- a/tests/mime/decode.cpp
+++ b/tests/mime/decode.cpp
@@ -337,7 +337,7 @@ int main()
{
const char *encoded;
const char *utf8;
- wxFontEncoding enc;
+ wxFontEncoding enc = wxFONTENCODING_UTF8;
const char *encodedAlt = nullptr;
} data[] =
{
@@ -365,8 +365,7 @@ int main()
},
{
"=?UTF-8?Q?Ludovic_P=C3=A9net?=",
- "Ludovic P\303\251net",
- wxFONTENCODING_UTF8
+ "Ludovic P\303\251net"
},
{
@@ -380,8 +379,7 @@ int main()
{
"=?UTF-8?Q?2006_=D0=92_=D0=A6_2007?=",
- "2006 \xD0\x92 \xD0\xA6 2007",
- wxFONTENCODING_UTF8
+ "2006 \xD0\x92 \xD0\xA6 2007"
},
{
commit 583336819f11ab5e23bddfff15be73b6daa35854
Author: Vadim Zeitlin <[email protected]>
Date: Fri Mar 21 04:10:50 2025 +0100
Decide which RFC 2047 encoding to use based on input contents
Use Base64 if it's going to be more compact and only use QP if there are
relatively few characters to encode.
This requires modifying the test to accept Base64 encoding of QP-encoded
strings.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index f56b613d..93100d69 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -432,26 +432,6 @@ static inline bool NeedsEncodingInHeader(unsigned c)
return c < 20 || c >= 127;
}
-// return true if the string contains any characters which must be encoded
-static bool NeedsEncoding(const String& in)
-{
- // if input contains "=?", encode it anyhow to avoid generating invalid
- // encoded words
- if ( in.find(_T("=?")) != wxString::npos )
- return true;
-
- // only encode the strings which contain the characters unallowed in RFC
- // 822 headers
- for ( auto c : in )
- {
- if ( NeedsEncodingInHeader(c.GetValue()) )
- return true;
- }
-
- // string has only valid chars, don't encode
- return false;
-}
-
// Some constants used by the encoding functions below.
static constexpr size_t RFC2047_MAXWORD_LEN = 75;
static constexpr size_t MIME_WORD_OVERHEAD = 7; // =?...?X?...?=
@@ -609,7 +589,35 @@ EncodeTextBase64(const char* in, const std::string& csName)
std::string MIME::EncodeHeader(const String& in, wxFontEncoding enc)
{
- if ( !NeedsEncoding(in) )
+ // First check if this text needs to be encoded at all.
+ size_t countNeedsEncoding = 0;
+ for ( auto c : in )
+ {
+ if ( NeedsEncodingInHeader(c.GetValue()) )
+ countNeedsEncoding++;
+ }
+
+ // We arbitrarily decide that if more than 1/4 of the string needs to be
+ // encoded, we'll encode it using Base64, otherwise we'll use QP to keep it
+ // roughly readable even in the encoded form.
+ MIME::Encoding enc2047 = MIME::Encoding_Unknown;
+ if ( !countNeedsEncoding )
+ {
+ // if input contains "=?", encode it anyhow to avoid generating invalid
+ // encoded words
+ if ( in.find(_T("=?")) != wxString::npos )
+ enc2047 = MIME::Encoding_QuotedPrintable;
+ }
+ else if ( countNeedsEncoding >= in.length() / 4 )
+ {
+ enc2047 = MIME::Encoding_Base64;
+ }
+ else
+ {
+ enc2047 = MIME::Encoding_QuotedPrintable;
+ }
+
+ if ( enc2047 == MIME::Encoding_Unknown )
return std::string(in.ToAscii());
// If we were given an explicit encoding to use, check if we can use it, and
@@ -642,11 +650,11 @@ std::string MIME::EncodeHeader(const String& in, wxFontEncoding enc)
}
std::string out;
- switch ( MIME::GetEncodingForFontEncoding(enc) )
+ switch ( enc2047 )
{
case MIME::Encoding_Unknown:
- FAIL_MSG( "using unknown MIME encoding?" );
- wxFALLTHROUGH;
+ FAIL_MSG( "unreachable" );
+ break;
case MIME::Encoding_QuotedPrintable:
out = EncodeTextQP(inbuf.data(), csName);
diff --git a/tests/mime/decode.cpp b/tests/mime/decode.cpp
index 6f6d1f42..168d4b03 100644
--- a/tests/mime/decode.cpp
+++ b/tests/mime/decode.cpp
@@ -338,6 +338,7 @@ int main()
const char *encoded;
const char *utf8;
wxFontEncoding enc;
+ const char *encodedAlt = nullptr;
} data[] =
{
{
@@ -373,7 +374,8 @@ int main()
" =?UTF-8?Q?=D0=B8=D0=BD?=",
"\xD0\x92\xD0\xB0\xD0\xB4\xD0\xB8\xD0\xBC "
"\xD0\xA6\xD0\xB5\xD0\xB9\xD1\x82\xD0\xBB\xD0\xB8\xD0\xBD",
- wxFONTENCODING_UTF8
+ wxFONTENCODING_UTF8,
+ "=?UTF-8?B?0JLQsNC00LjQvCDQptC10LnRgtC70LjQvQ==?="
},
{
@@ -385,7 +387,8 @@ int main()
{
"=?UTF-8?Q?=D0=92_=D0=A6_2007?=",
"\xD0\x92 \xD0\xA6 2007",
- wxFONTENCODING_UTF8
+ wxFONTENCODING_UTF8,
+ "=?UTF-8?B?0JIg0KYgMjAwNw==?="
},
};
@@ -407,7 +410,7 @@ int main()
continue;
const std::string buf = MIME::EncodeHeader(s, d.enc);
- if ( buf != d.encoded )
+ if ( buf != d.encoded && (!d.encodedAlt || buf != d.encodedAlt) )
{
printf("ERROR: encoding #%u: expected \"%s\", got \"%s\"\n",
n, d.encoded, buf.c_str());
commit 570b1608a0d04a22ea2d106e53ebbe9dcbc82c37
Author: Vadim Zeitlin <[email protected]>
Date: Fri Mar 21 04:11:56 2025 +0100
Remove redundant encoding enum declaration
This is the same thing as MIME::Encoding.
No real changes.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 088ebac0..f56b613d 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -235,12 +235,7 @@ String DecodeHeaderOnce(const String& in, wxFontEncoding *pEncoding)
}
// get the encoding in RFC 2047 sense
- enum
- {
- Encoding_Unknown,
- Encoding_Base64,
- Encoding_QuotedPrintable
- } enc2047 = Encoding_Unknown;
+ MIME::Encoding enc2047 = MIME::Encoding_Unknown;
++p; // skip '?'
@@ -256,14 +251,14 @@ String DecodeHeaderOnce(const String& in, wxFontEncoding *pEncoding)
if ( *(p + 1) == '?' )
{
if ( *p == 'B' || *p == 'b' )
- enc2047 = Encoding_Base64;
+ enc2047 = MIME::Encoding_Base64;
else if ( *p == 'Q' || *p == 'q' )
- enc2047 = Encoding_QuotedPrintable;
+ enc2047 = MIME::Encoding_QuotedPrintable;
}
//else: multi letter encoding unrecognized
}
- if ( enc2047 == Encoding_Unknown )
+ if ( enc2047 == MIME::Encoding_Unknown )
{
wxLogDebug(_T("Unrecognized header encoding in '%s'."), in.c_str());
@@ -324,7 +319,7 @@ String DecodeHeaderOnce(const String& in, wxFontEncoding *pEncoding)
// now decode the text using c-client functions
unsigned long len;
void *text;
- if ( enc2047 == Encoding_Base64 )
+ if ( enc2047 == MIME::Encoding_Base64 )
{
text = rfc822_base64(UCHAR_CCAST(encWord.data()), lenEncWord, &len);
}
commit 7517e90b2e31776448ff881a3cfaa1435f55a6ce
Author: Vadim Zeitlin <[email protected]>
Date: Fri Mar 21 04:01:11 2025 +0100
Return std::string from EncodeHeader()
This avoids extra conversions with wxString and using std::string in the
interface is just generally cleaner than using wxCharBuffer.
No real changes.
diff --git a/include/mail/MimeDecode.h b/include/mail/MimeDecode.h
index c20a3f0f..ce2a0fbc 100644
--- a/include/mail/MimeDecode.h
+++ b/include/mail/MimeDecode.h
@@ -66,7 +66,7 @@ String GetCharsetForFontEncoding(wxFontEncoding enc);
use the encoding of the current locale
@return the encoded text or NULL buffer if encoding failed
*/
-wxCharBuffer
+std::string
EncodeHeader(const wxString& in, wxFontEncoding enc = wxFONTENCODING_SYSTEM);
/**
diff --git a/src/gui/wxComposeView.cpp b/src/gui/wxComposeView.cpp
index 603d96f1..f49cec7d 100644
--- a/src/gui/wxComposeView.cpp
+++ b/src/gui/wxComposeView.cpp
@@ -5402,7 +5402,7 @@ wxComposeView::AddHeaderEntry(const String& name, const String& value)
// if we didn't find it, add a new one
m_extraHeadersNames.push_back(name.utf8_string());
- m_extraHeadersValues.push_back(MIME::EncodeHeader(value).data());
+ m_extraHeadersValues.push_back(MIME::EncodeHeader(value));
}
bool wxComposeView::IsPGPSigningEnabled() const
diff --git a/src/mail/AddressCC.cpp b/src/mail/AddressCC.cpp
index fa69be51..577b412c 100644
--- a/src/mail/AddressCC.cpp
+++ b/src/mail/AddressCC.cpp
@@ -576,7 +576,7 @@ ParseAddressList(const String& address,
{
String personal = wxString::FromUTF8(adr2->personal);
fs_give((void **)&adr2->personal);
- adr2->personal = cpystr(MIME::EncodeHeader(personal, enc));
+ adr2->personal = cpystr(MIME::EncodeHeader(personal, enc).c_str());
}
}
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 197c6ef2..088ebac0 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -462,8 +462,8 @@ static constexpr size_t RFC2047_MAXWORD_LEN = 75;
static constexpr size_t MIME_WORD_OVERHEAD = 7; // =?...?X?...?=
// encode the text in the charset with the given name in QP
-static String
-EncodeTextQP(const char* in, const String& csName)
+static std::string
+EncodeTextQP(const char* in, const std::string& csName)
{
// encode the text splitting it in the chunks such that they will be no
// longer than maximum length each
@@ -471,7 +471,7 @@ EncodeTextQP(const char* in, const String& csName)
const char* const HEX_DIGITS = "0123456789ABCDEF";
- String out;
+ std::string out;
out.reserve(strlen(in) + overhead);
// Each iteration of this loop corresponds to a physical line.
@@ -543,14 +543,14 @@ EncodeTextQP(const char* in, const String& csName)
}
// same as the function above but use Base64 encoding
-static String
-EncodeTextBase64(const char* in, const String& csName)
+static std::string
+EncodeTextBase64(const char* in, const std::string& csName)
{
const size_t overhead = MIME_WORD_OVERHEAD + csName.length();
// encode the word splitting it in the chunks such that they will be no
// longer than maximum length each
- String out;
+ std::string out;
out.reserve(strlen(in) + overhead);
auto *s = reinterpret_cast<const unsigned char*>(in);
@@ -594,10 +594,14 @@ EncodeTextBase64(const char* in, const String& csName)
}
// put into string as we might want to do some more replacements...
- String encword(wxString::FromAscii(CHAR_CAST(textEnc), lenEnc));
+ std::string encword(CHAR_CAST(textEnc), lenEnc);
// append this word to the header
- out << _T("=?") << csName << _T("?B?") << encword << _T("?=");
+ out += "=?";
+ out += csName;
+ out += "?B?";
+ out += encword;
+ out += "?=";
fs_give((void **)&textEnc);
@@ -608,10 +612,10 @@ EncodeTextBase64(const char* in, const String& csName)
return out;
}
-wxCharBuffer MIME::EncodeHeader(const String& in, wxFontEncoding enc)
+std::string MIME::EncodeHeader(const String& in, wxFontEncoding enc)
{
if ( !NeedsEncoding(in) )
- return in.ToAscii();
+ return std::string(in.ToAscii());
// If we were given an explicit encoding to use, check if we can use it, and
// if not fall back to the same UTF-8 (which can always be used) as we use
@@ -623,12 +627,12 @@ wxCharBuffer MIME::EncodeHeader(const String& in, wxFontEncoding enc)
}
// get the name of the charset to use
- String csName = MIME::GetCharsetForFontEncoding(enc);
+ std::string csName = MIME::GetCharsetForFontEncoding(enc).utf8_string();
if ( csName.empty() )
{
FAIL_MSG( _T("should have a valid charset name!") );
- csName = _T("UNKNOWN");
+ csName = "UNKNOWN";
}
wxCharBuffer inbuf;
@@ -642,7 +646,7 @@ wxCharBuffer MIME::EncodeHeader(const String& in, wxFontEncoding enc)
inbuf = in.utf8_str();
}
- String out;
+ std::string out;
switch ( MIME::GetEncodingForFontEncoding(enc) )
{
case MIME::Encoding_Unknown:
@@ -658,7 +662,7 @@ wxCharBuffer MIME::EncodeHeader(const String& in, wxFontEncoding enc)
break;
}
- return out.ToAscii();
+ return out;
}
String MIME::DecodeText(const char *p, size_t len, wxFontEncoding enc)
diff --git a/src/mail/SendMessageCC.cpp b/src/mail/SendMessageCC.cpp
index c223dc99..f915ffd3 100644
--- a/src/mail/SendMessageCC.cpp
+++ b/src/mail/SendMessageCC.cpp
@@ -835,12 +835,12 @@ SendMessageCC::SetSubject(const String& subject)
// don't encode the headers of an existing message second time, we want to
// preserve them as they are
- wxCharBuffer buf;
+ std::string buf;
if ( m_cloneOfExisting )
buf = subject.ToAscii();
else
buf = MIME::EncodeHeader(subject, m_encHeaders);
- m_Envelope->subject = cpystr(buf);
+ m_Envelope->subject = cpystr(buf.c_str());
}
void
@@ -1331,8 +1331,8 @@ SendMessageCC::Build(bool forStorage)
continue;
}
- const wxCharBuffer value(MIME::EncodeHeader(i->m_value));
- if ( !value )
+ const std::string value(MIME::EncodeHeader(i->m_value));
+ if ( value.empty() )
{
wxLogError(_("Invalid value \"%s\" for the custom header \"%s\""),
i->m_value.c_str(), i->m_name.c_str());
@@ -1349,7 +1349,7 @@ SendMessageCC::Build(bool forStorage)
// Conversion to ASCII is safe because HeaderName::IsValid() would have
// returned false if we had any non-ASCII characters in the name.
m_headerNames[h] = strutil_strdup(i->m_name.ToAscii());
- m_headerValues[h] = strutil_strdup(value);
+ m_headerValues[h] = strutil_strdup(value.c_str());
h++;
}
@@ -1586,7 +1586,7 @@ SendMessageCC::AddPart(MimeType::Primary type,
}
par->attribute = strdup(name.ToAscii());
- par->value = strdup(MIME::EncodeHeader(i->value));
+ par->value = strdup(MIME::EncodeHeader(i->value).c_str());
par->next = lastpar;
lastpar = par;
}
@@ -1638,7 +1638,7 @@ SendMessageCC::AddPart(MimeType::Primary type,
{
PARAMETER *par = mail_newbody_parameter();
par->attribute = strdup(i->name.ToAscii());
- par->value = strdup(MIME::EncodeHeader(i->value));
+ par->value = strdup(MIME::EncodeHeader(i->value).c_str());
par->next = NULL;
if(lastpar)
lastpar->next = par;
diff --git a/tests/mime/decode.cpp b/tests/mime/decode.cpp
index 36d91829..6f6d1f42 100644
--- a/tests/mime/decode.cpp
+++ b/tests/mime/decode.cpp
@@ -406,11 +406,11 @@ int main()
if ( d.enc == wxFONTENCODING_DEFAULT )
continue;
- const wxCharBuffer buf = MIME::EncodeHeader(s, d.enc);
- if ( strcmp(buf, d.encoded) != 0 )
+ const std::string buf = MIME::EncodeHeader(s, d.enc);
+ if ( buf != d.encoded )
{
printf("ERROR: encoding #%u: expected \"%s\", got \"%s\"\n",
- n, d.encoded, (const char *)buf);
+ n, d.encoded, buf.c_str());
}
}
commit 50790426be9c783e4edea4a2e3ecc807efc90594
Author: Vadim Zeitlin <[email protected]>
Date: Fri Mar 21 03:47:52 2025 +0100
Rewrite headers QP MIME encoding code once again
The previous version was still wrong as it didn't handle spaces between
words correctly any longer.
Simplify things by always encoding, instead of deciding whether to
encode for each word separately, this is not significantly less readable
in the encoded form (if we even still care about this) but much simpler
and more obviously correct.
Also perform our own QP-encoding instead of using c-client function,
it's so simple that it's much easier to do it like this.
Update the tests to match the results of the encoding algorithm now.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 46fddd47..197c6ef2 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -465,101 +465,78 @@ static constexpr size_t MIME_WORD_OVERHEAD = 7; // =?...?X?...?=
static String
EncodeTextQP(const char* in, const String& csName)
{
- // encode the word splitting it in the chunks such that they will be no
+ // encode the text splitting it in the chunks such that they will be no
// longer than maximum length each
const size_t overhead = MIME_WORD_OVERHEAD + csName.length();
+ const char* const HEX_DIGITS = "0123456789ABCDEF";
+
String out;
out.reserve(strlen(in) + overhead);
- auto *s = reinterpret_cast<const unsigned char*>(in);
- while ( *s )
+ // Each iteration of this loop corresponds to a physical line.
+ while ( *in )
{
- // if we wrapped, insert a line break
if ( !out.empty() )
out += "\r\n ";
- // how many characters may we put in this encoded word?
- size_t len = 0;
+ out += "=?";
+ out += csName;
+ out += "?Q?";
- // take into account the length of "=?charset?...?="
- int lenRemaining = RFC2047_MAXWORD_LEN - overhead;
-
- // for QP we need to examine all characters
- for ( ; s[len]; len++ )
+ // Iterate over the characters that fit into the current line.
+ size_t lineLen = overhead;
+ for ( ;; ++in )
{
- const unsigned char c = s[len];
-
- // normal characters stand for themselves in QP, the encoded ones
- // take 3 positions (=XX)
- lenRemaining -= (NeedsEncodingInHeader(c) || strchr("=?", c))
- ? 3 : 1;
+ const unsigned char c = *in;
- if ( lenRemaining <= 0 )
- {
- // can't put any more chars into this word
+ if ( c == '\0' )
break;
- }
- }
-
- // do encode this word
- unsigned char *text = const_cast<unsigned char*>(s); // cast for cclient
-
- // length of the encoded text and the text itself
- unsigned long lenEnc;
- unsigned char *textEnc;
-
- textEnc = rfc822_8bit(text, len, &lenEnc);
-
- // put into string as we might want to do some more replacements...
- String encword(wxString::FromAscii(CHAR_CAST(textEnc), lenEnc));
- // hack: rfc822_8bit() doesn't encode spaces normally but we must
- // do it inside the headers
- //
- // we also have to encode '?'s in the headers which are not encoded by it
- String encword2;
- encword2.reserve(encword.length());
-
- bool replaced = false;
- for ( const wxChar *p = encword.c_str(); *p; p++ )
- {
- switch ( *p )
+ // If this character is 0, we must encode "c" instead.
+ unsigned char unencoded = '\0';
+ switch ( c )
{
case ' ':
- encword2 += '_'; // More readable than =20
- break;
-
- case '\t':
- encword2 += _T("=09");
+ // Encode spaces as underscores rather than =20, as this is more
+ // readable, even if both are allowed.
+ unencoded = '_';
break;
+ // These characters need to be encoded in headers to avoid
+ // clashing with the encoded word syntax. In principle, we could
+ // let them remain unencoded if they don't occur in the same
+ // combination as in the encoded word syntax, but for now keep
+ // things simple and always encode them.
+ case '=':
case '?':
- encword2 += _T("=3F");
break;
default:
- encword2 += *p;
-
- // skip assignment to replaced below
- continue;
+ if ( !NeedsEncodingInHeader(c) )
+ unencoded = c;
+ break;
}
- replaced = true;
- }
-
- if ( replaced )
- {
- encword = encword2;
- }
+ const auto lenNeeded = unencoded ? 1 : 3;
+ if ( lineLen + lenNeeded > RFC2047_MAXWORD_LEN )
+ break;
- // append this word to the header
- out << _T("=?") << csName << _T("?Q?") << encword << _T("?=");
+ if ( unencoded )
+ {
+ out += unencoded;
+ }
+ else
+ {
+ out += '=';
+ out += HEX_DIGITS[c >> 4];
+ out += HEX_DIGITS[c & 0xf];
+ }
- fs_give((void **)&textEnc);
+ lineLen += lenNeeded;
+ }
- // skip the already encoded part
- s += len;
+ out += "?=";
}
return out;
diff --git a/tests/mime/decode.cpp b/tests/mime/decode.cpp
index 8473f719..36d91829 100644
--- a/tests/mime/decode.cpp
+++ b/tests/mime/decode.cpp
@@ -358,32 +358,32 @@ int main()
wxFONTENCODING_KOI8
},
{
- "Ludovic =?ISO-8859-1?Q?P=E9net?= <[email protected]>",
- "Ludovic P\303\251net <[email protected]>",
+ "=?ISO-8859-1?Q?Ludovic_P=E9net?=",
+ "Ludovic P\303\251net",
wxFONTENCODING_ISO8859_1
},
{
- "Ludovic =?UTF-8?Q?P=C3=A9net?= <[email protected]>",
- "Ludovic P\303\251net <[email protected]>",
+ "=?UTF-8?Q?Ludovic_P=C3=A9net?=",
+ "Ludovic P\303\251net",
wxFONTENCODING_UTF8
},
{
- "=?UTF-8?Q?=D0=92=D0=B0=D0=B4=D0=B8=D0=BC_"
- "=D0=A6=D0=B5=D0=B9=D1=82=D0=BB=D0=B8=D0=BD?=",
+ "=?UTF-8?Q?=D0=92=D0=B0=D0=B4=D0=B8=D0=BC_=D0=A6=D0=B5=D0=B9=D1=82=D0=BB?=\r\n"
+ " =?UTF-8?Q?=D0=B8=D0=BD?=",
"\xD0\x92\xD0\xB0\xD0\xB4\xD0\xB8\xD0\xBC "
"\xD0\xA6\xD0\xB5\xD0\xB9\xD1\x82\xD0\xBB\xD0\xB8\xD0\xBD",
wxFONTENCODING_UTF8
},
{
- "2006 =?UTF-8?Q?=D0=92_=D0=A6?= 2007",
+ "=?UTF-8?Q?2006_=D0=92_=D0=A6_2007?=",
"2006 \xD0\x92 \xD0\xA6 2007",
wxFONTENCODING_UTF8
},
{
- "=?UTF-8?Q?=D0=92_=D0=A6?= 2007",
+ "=?UTF-8?Q?=D0=92_=D0=A6_2007?=",
"\xD0\x92 \xD0\xA6 2007",
wxFONTENCODING_UTF8
},
commit 044f6c4bc0c2a405f81617a9abd67929b9cd0077
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 03:09:23 2025 +0100
Simplify length calculation code in EncodeTextBase64()
Also improve the comments.
No real changes.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 151f734c..46fddd47 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -583,23 +583,18 @@ EncodeTextBase64(const char* in, const String& csName)
if ( !out.empty() )
out += "\r\n ";
- // how many characters may we put in this encoded word?
- size_t len = 0;
-
- // take into account the length of "=?charset?...?="
- int lenRemaining = RFC2047_MAXWORD_LEN - overhead;
-
// rfc822_binary() splits lines after 60 characters so don't make
// chunks longer than this as the base64-encoded headers can't have
// EOLs in them
static const int CCLIENT_MAX_BASE64_LEN = 60;
- if ( lenRemaining > CCLIENT_MAX_BASE64_LEN )
- lenRemaining = CCLIENT_MAX_BASE64_LEN;
+ // but if the charset name is sufficiently long, we may need to make them
+ // shorter than this
+ size_t lenRemaining = wxMin(CCLIENT_MAX_BASE64_LEN,
+ RFC2047_MAXWORD_LEN - overhead);
- // we can calculate how many characters we may put into lenRemaining
- // directly
- len = (lenRemaining / 4) * 3;
+ // we can calculate how many characters we may put on one line directly
+ size_t len = (lenRemaining / 4) * 3;
// but not more than what we have
size_t lenMax = strlen(reinterpret_cast<const char*>(s));
@@ -613,9 +608,8 @@ EncodeTextBase64(const char* in, const String& csName)
// length of the encoded text and the text itself
unsigned long lenEnc;
- unsigned char *textEnc;
+ unsigned char *textEnc = rfc822_binary(text, len, &lenEnc);
- textEnc = rfc822_binary(text, len, &lenEnc);
while ( textEnc[lenEnc - 2] == '\r' && textEnc[lenEnc - 1] == '\n' )
{
// discard eol which we don't need in the header
commit ba821e338687c1602fc536c3db591c10ca281a8a
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 03:00:24 2025 +0100
Use constants in text encoding code instead of bare numbers
Also fix an apparent bug when we used 5, instead of 7, when computing
the remaining available space in the line.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 62bc6865..151f734c 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -457,14 +457,20 @@ static bool NeedsEncoding(const String& in)
return false;
}
+// Some constants used by the encoding functions below.
+static constexpr size_t RFC2047_MAXWORD_LEN = 75;
+static constexpr size_t MIME_WORD_OVERHEAD = 7; // =?...?X?...?=
+
// encode the text in the charset with the given name in QP
static String
EncodeTextQP(const char* in, const String& csName)
{
// encode the word splitting it in the chunks such that they will be no
- // longer than 75 characters each
+ // longer than maximum length each
+ const size_t overhead = MIME_WORD_OVERHEAD + csName.length();
+
String out;
- out.reserve(csName.length() + strlen(in) + 7 /* for =?...?X?...?= */);
+ out.reserve(strlen(in) + overhead);
auto *s = reinterpret_cast<const unsigned char*>(in);
while ( *s )
@@ -473,13 +479,11 @@ EncodeTextQP(const char* in, const String& csName)
if ( !out.empty() )
out += "\r\n ";
- static const size_t RFC2047_MAXWORD_LEN = 75;
-
// how many characters may we put in this encoded word?
size_t len = 0;
// take into account the length of "=?charset?...?="
- int lenRemaining = RFC2047_MAXWORD_LEN - (5 + csName.length());
+ int lenRemaining = RFC2047_MAXWORD_LEN - overhead;
// for QP we need to examine all characters
for ( ; s[len]; len++ )
@@ -565,10 +569,12 @@ EncodeTextQP(const char* in, const String& csName)
static String
EncodeTextBase64(const char* in, const String& csName)
{
+ const size_t overhead = MIME_WORD_OVERHEAD + csName.length();
+
// encode the word splitting it in the chunks such that they will be no
- // longer than 75 characters each
+ // longer than maximum length each
String out;
- out.reserve(csName.length() + strlen(in) + 7 /* for =?...?X?...?= */);
+ out.reserve(strlen(in) + overhead);
auto *s = reinterpret_cast<const unsigned char*>(in);
while ( *s )
@@ -577,13 +583,11 @@ EncodeTextBase64(const char* in, const String& csName)
if ( !out.empty() )
out += "\r\n ";
- static const size_t RFC2047_MAXWORD_LEN = 75;
-
// how many characters may we put in this encoded word?
size_t len = 0;
// take into account the length of "=?charset?...?="
- int lenRemaining = RFC2047_MAXWORD_LEN - (5 + csName.length());
+ int lenRemaining = RFC2047_MAXWORD_LEN - overhead;
// rfc822_binary() splits lines after 60 characters so don't make
// chunks longer than this as the base64-encoded headers can't have
commit f14cf32b94dd6d98b4ccf4bd52f1e787bceab2a3
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 02:51:56 2025 +0100
Split EncodeText() into 2 functions for QP and Base64
There are already a few differences in how the different encodings are
handled and there will be even more of them soon, so don't try to handle
both encodings in a single function, this is too complicated.
No changes yet.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 1e98b81c..62bc6865 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -457,13 +457,9 @@ static bool NeedsEncoding(const String& in)
return false;
}
-// encode the given text unconditionally, i.e. without checking if it must be
-// encoded (this is supposed to be done in the caller) and using the specified
-// encodings and charset (which are supposed to be detected by the caller too)
+// encode the text in the charset with the given name in QP
static String
-EncodeText(const char* in,
- MIME::Encoding enc2047,
- const String& csName)
+EncodeTextQP(const char* in, const String& csName)
{
// encode the word splitting it in the chunks such that they will be no
// longer than 75 characters each
@@ -486,43 +482,19 @@ EncodeText(const char* in,
int lenRemaining = RFC2047_MAXWORD_LEN - (5 + csName.length());
// for QP we need to examine all characters
- if ( enc2047 == MIME::Encoding_QuotedPrintable )
+ for ( ; s[len]; len++ )
{
- for ( ; s[len]; len++ )
- {
- const unsigned char c = s[len];
-
- // normal characters stand for themselves in QP, the encoded ones
- // take 3 positions (=XX)
- lenRemaining -= (NeedsEncodingInHeader(c) || strchr("=?", c))
- ? 3 : 1;
-
- if ( lenRemaining <= 0 )
- {
- // can't put any more chars into this word
- break;
- }
- }
- }
- else // Base64
- {
- // rfc822_binary() splits lines after 60 characters so don't make
- // chunks longer than this as the base64-encoded headers can't have
- // EOLs in them
- static const int CCLIENT_MAX_BASE64_LEN = 60;
+ const unsigned char c = s[len];
- if ( lenRemaining > CCLIENT_MAX_BASE64_LEN )
- lenRemaining = CCLIENT_MAX_BASE64_LEN;
+ // normal characters stand for themselves in QP, the encoded ones
+ // take 3 positions (=XX)
+ lenRemaining -= (NeedsEncodingInHeader(c) || strchr("=?", c))
+ ? 3 : 1;
- // we can calculate how many characters we may put into lenRemaining
- // directly
- len = (lenRemaining / 4) * 3;
-
- // but not more than what we have
- size_t lenMax = strlen(reinterpret_cast<const char*>(s));
- if ( len > lenMax )
+ if ( lenRemaining <= 0 )
{
- len = lenMax;
+ // can't put any more chars into this word
+ break;
}
}
@@ -533,19 +505,7 @@ EncodeText(const char* in,
unsigned long lenEnc;
unsigned char *textEnc;
- if ( enc2047 == MIME::Encoding_QuotedPrintable )
- {
- textEnc = rfc822_8bit(text, len, &lenEnc);
- }
- else // Encoding_Base64
- {
- textEnc = rfc822_binary(text, len, &lenEnc);
- while ( textEnc[lenEnc - 2] == '\r' && textEnc[lenEnc - 1] == '\n' )
- {
- // discard eol which we don't need in the header
- lenEnc -= 2;
- }
- }
+ textEnc = rfc822_8bit(text, len, &lenEnc);
// put into string as we might want to do some more replacements...
String encword(wxString::FromAscii(CHAR_CAST(textEnc), lenEnc));
@@ -554,48 +514,115 @@ EncodeText(const char* in,
// do it inside the headers
//
// we also have to encode '?'s in the headers which are not encoded by it
- if ( enc2047 == MIME::Encoding_QuotedPrintable )
- {
- String encword2;
- encword2.reserve(encword.length());
+ String encword2;
+ encword2.reserve(encword.length());
- bool replaced = false;
- for ( const wxChar *p = encword.c_str(); *p; p++ )
+ bool replaced = false;
+ for ( const wxChar *p = encword.c_str(); *p; p++ )
+ {
+ switch ( *p )
{
- switch ( *p )
- {
- case ' ':
- encword2 += '_'; // More readable than =20
- break;
-
- case '\t':
- encword2 += _T("=09");
- break;
+ case ' ':
+ encword2 += '_'; // More readable than =20
+ break;
- case '?':
- encword2 += _T("=3F");
- break;
+ case '\t':
+ encword2 += _T("=09");
+ break;
- default:
- encword2 += *p;
+ case '?':
+ encword2 += _T("=3F");
+ break;
- // skip assignment to replaced below
- continue;
- }
+ default:
+ encword2 += *p;
- replaced = true;
+ // skip assignment to replaced below
+ continue;
}
- if ( replaced )
- {
- encword = encword2;
- }
+ replaced = true;
+ }
+
+ if ( replaced )
+ {
+ encword = encword2;
}
// append this word to the header
- out << _T("=?") << csName << _T('?') << (char)enc2047 << _T('?')
- << encword
- << _T("?=");
+ out << _T("=?") << csName << _T("?Q?") << encword << _T("?=");
+
+ fs_give((void **)&textEnc);
+
+ // skip the already encoded part
+ s += len;
+ }
+
+ return out;
+}
+
+// same as the function above but use Base64 encoding
+static String
+EncodeTextBase64(const char* in, const String& csName)
+{
+ // encode the word splitting it in the chunks such that they will be no
+ // longer than 75 characters each
+ String out;
+ out.reserve(csName.length() + strlen(in) + 7 /* for =?...?X?...?= */);
+
+ auto *s = reinterpret_cast<const unsigned char*>(in);
+ while ( *s )
+ {
+ // if we wrapped, insert a line break
+ if ( !out.empty() )
+ out += "\r\n ";
+
+ static const size_t RFC2047_MAXWORD_LEN = 75;
+
+ // how many characters may we put in this encoded word?
+ size_t len = 0;
+
+ // take into account the length of "=?charset?...?="
+ int lenRemaining = RFC2047_MAXWORD_LEN - (5 + csName.length());
+
+ // rfc822_binary() splits lines after 60 characters so don't make
+ // chunks longer than this as the base64-encoded headers can't have
+ // EOLs in them
+ static const int CCLIENT_MAX_BASE64_LEN = 60;
+
+ if ( lenRemaining > CCLIENT_MAX_BASE64_LEN )
+ lenRemaining = CCLIENT_MAX_BASE64_LEN;
+
+ // we can calculate how many characters we may put into lenRemaining
+ // directly
+ len = (lenRemaining / 4) * 3;
+
+ // but not more than what we have
+ size_t lenMax = strlen(reinterpret_cast<const char*>(s));
+ if ( len > lenMax )
+ {
+ len = lenMax;
+ }
+
+ // do encode this word
+ unsigned char *text = const_cast<unsigned char*>(s); // cast for cclient
+
+ // length of the encoded text and the text itself
+ unsigned long lenEnc;
+ unsigned char *textEnc;
+
+ textEnc = rfc822_binary(text, len, &lenEnc);
+ while ( textEnc[lenEnc - 2] == '\r' && textEnc[lenEnc - 1] == '\n' )
+ {
+ // discard eol which we don't need in the header
+ lenEnc -= 2;
+ }
+
+ // put into string as we might want to do some more replacements...
+ String encword(wxString::FromAscii(CHAR_CAST(textEnc), lenEnc));
+
+ // append this word to the header
+ out << _T("=?") << csName << _T("?B?") << encword << _T("?=");
fs_give((void **)&textEnc);
@@ -620,16 +647,6 @@ wxCharBuffer MIME::EncodeHeader(const String& in, wxFontEncoding enc)
enc = wxFONTENCODING_UTF8;
}
- // get the encoding in RFC 2047 sense
- MIME::Encoding enc2047 = MIME::GetEncodingForFontEncoding(enc);
-
- if ( enc2047 == MIME::Encoding_Unknown )
- {
- FAIL_MSG( _T("should have valid MIME encoding") );
-
- enc2047 = MIME::Encoding_QuotedPrintable;
- }
-
// get the name of the charset to use
String csName = MIME::GetCharsetForFontEncoding(enc);
if ( csName.empty() )
@@ -650,7 +667,23 @@ wxCharBuffer MIME::EncodeHeader(const String& in, wxFontEncoding enc)
inbuf = in.utf8_str();
}
- return EncodeText(inbuf.data(), enc2047, csName).ToAscii();
+ String out;
+ switch ( MIME::GetEncodingForFontEncoding(enc) )
+ {
+ case MIME::Encoding_Unknown:
+ FAIL_MSG( "using unknown MIME encoding?" );
+ wxFALLTHROUGH;
+
+ case MIME::Encoding_QuotedPrintable:
+ out = EncodeTextQP(inbuf.data(), csName);
+ break;
+
+ case MIME::Encoding_Base64:
+ out = EncodeTextBase64(inbuf.data(), csName);
+ break;
+ }
+
+ return out.ToAscii();
}
String MIME::DecodeText(const char *p, size_t len, wxFontEncoding enc)
commit 9f4b95a7555bf07860a2286f1f04b66885e0b71a
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 02:45:10 2025 +0100
Remove unused wxFontEncoding parameter of EncodeText()
Simplify the function a bit.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 8b6b11bd..1e98b81c 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -462,7 +462,6 @@ static bool NeedsEncoding(const String& in)
// encodings and charset (which are supposed to be detected by the caller too)
static String
EncodeText(const char* in,
- wxFontEncoding enc,
MIME::Encoding enc2047,
const String& csName)
{
@@ -651,7 +650,7 @@ wxCharBuffer MIME::EncodeHeader(const String& in, wxFontEncoding enc)
inbuf = in.utf8_str();
}
- return EncodeText(inbuf.data(), enc, enc2047, csName).ToAscii();
+ return EncodeText(inbuf.data(), enc2047, csName).ToAscii();
}
String MIME::DecodeText(const char *p, size_t len, wxFontEncoding enc)
commit ba1921ea80e18ca17d4978c5a57da36625c7233f
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 02:43:13 2025 +0100
Pass C string, not wxString, to EncodeText()
Also avoid constructing wxCSConv() when using UTF-8, which is the most
common use case.
No real changes, just prepare for the upcoming refactoring.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 7faeca1d..8b6b11bd 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -461,25 +461,17 @@ static bool NeedsEncoding(const String& in)
// encoded (this is supposed to be done in the caller) and using the specified
// encodings and charset (which are supposed to be detected by the caller too)
static String
-EncodeText(const String& in,
+EncodeText(const char* in,
wxFontEncoding enc,
MIME::Encoding enc2047,
const String& csName)
{
// encode the word splitting it in the chunks such that they will be no
// longer than 75 characters each
- wxCharBuffer buf(in.mb_str(wxCSConv(enc)));
- if ( !buf )
- {
- // if the header can't be encoded using the given encoding, use UTF-8
- // which always works
- buf = in.utf8_str();
- }
-
String out;
- out.reserve(csName.length() + strlen(buf) + 7 /* for =?...?X?...?= */);
+ out.reserve(csName.length() + strlen(in) + 7 /* for =?...?X?...?= */);
- auto *s = reinterpret_cast<const unsigned char*>(buf.data());
+ auto *s = reinterpret_cast<const unsigned char*>(in);
while ( *s )
{
// if we wrapped, insert a line break
@@ -648,7 +640,18 @@ wxCharBuffer MIME::EncodeHeader(const String& in, wxFontEncoding enc)
csName = _T("UNKNOWN");
}
- return EncodeText(in, enc, enc2047, csName).ToAscii();
+ wxCharBuffer inbuf;
+ if ( enc != wxFONTENCODING_UTF8 )
+ inbuf = in.mb_str(wxCSConv(enc));
+
+ if ( !inbuf )
+ {
+ // if the header can't be encoded using the given encoding, use UTF-8
+ // which always works
+ inbuf = in.utf8_str();
+ }
+
+ return EncodeText(inbuf.data(), enc, enc2047, csName).ToAscii();
}
String MIME::DecodeText(const char *p, size_t len, wxFontEncoding enc)
commit 3d1f4cf9b4ac17f17b49f49145d51e3c0c131d4a
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 01:27:05 2025 +0100
Allow up to 6 characters when encoding headers using Base64
The maximum length of the line shouldn't account for "\r\n", otherwise
we only put 58 characters in each line instead of 60 as intended.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 2dd19197..7faeca1d 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -525,7 +525,7 @@ EncodeText(const String& in,
// we can calculate how many characters we may put into lenRemaining
// directly
- len = (lenRemaining / 4) * 3 - 2;
+ len = (lenRemaining / 4) * 3;
// but not more than what we have
size_t lenMax = strlen(reinterpret_cast<const char*>(s));
commit 1ac798f306170815921c6d482d668cf27ede5e88
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 01:17:18 2025 +0100
Fix infinite loop in EncodeText() when using Base64
We need to get the number of remaining bytes in the string, so use
strlen() instead of using wxStrlen() which compiles without the cast but
involves a conversion to wxString, which may fail, returning an empty
string and hence encoding a "word" of 0 length.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index 9134fb4c..2dd19197 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -528,7 +528,7 @@ EncodeText(const String& in,
len = (lenRemaining / 4) * 3 - 2;
// but not more than what we have
- size_t lenMax = wxStrlen(s);
+ size_t lenMax = strlen(reinterpret_cast<const char*>(s));
if ( len > lenMax )
{
len = lenMax;
commit 868edf0e0f3facab75414106cbc04f2b27ed05b9
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 01:16:51 2025 +0100
Stop using wxFONTENCODING_DEFAULT in MIME decoding test
This doesn't make much sense and doesn't work.
diff --git a/tests/mime/decode.cpp b/tests/mime/decode.cpp
index 08f8245d..8473f719 100644
--- a/tests/mime/decode.cpp
+++ b/tests/mime/decode.cpp
@@ -387,12 +387,6 @@ int main()
"\xD0\x92 \xD0\xA6 2007",
wxFONTENCODING_UTF8
},
-
- {
- "=?us-ascii?Q?Foo=20bar?=",
- "Foo bar",
- wxFONTENCODING_DEFAULT
- },
};
int rc = EXIT_SUCCESS;
commit 409d6974435db410434831eed0ef2d561fcb6569
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 01:16:00 2025 +0100
Suppress harmless warnings in code copied from c-client
Fixing them would involve modifying the code which really shouldn't even
be here at all.
diff --git a/tests/mime/decode.cpp b/tests/mime/decode.cpp
index 289f97dc..08f8245d 100644
--- a/tests/mime/decode.cpp
+++ b/tests/mime/decode.cpp
@@ -5,6 +5,8 @@ typedef wxString String;
#include "mail/MimeDecode.h"
+wxGCC_WARNING_SUPPRESS(write-strings)
+
extern "C" {
void *fs_get (size_t size) { return malloc(size); }
@@ -325,6 +327,8 @@ unsigned char *rfc822_8bit (unsigned char *src,unsigned long srcl,
}
}
+wxGCC_WARNING_RESTORE(write-strings)
+
int main()
{
wxInitializer init;
commit 6a5486de8057dc3e64036d61c67e769ccae2f8a6
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 01:08:02 2025 +0100
Remove hard coded paths from MIME tests makefile
diff --git a/tests/mime/Makefile b/tests/mime/Makefile
index a7fb3635..81d952ad 100644
--- a/tests/mime/Makefile
+++ b/tests/mime/Makefile
@@ -1,6 +1,9 @@
-WX_CONFIG := /usr/local/src/build/wx-gtkud/wx-config
+WX_CONFIG := wx-config
+
+ifndef top_builddir
+$(error Define top_builddir to point to build directory on make command line)
+endif
-top_builddir := /home/zeitlin/build/M-gtkud
top_srcdir := ../..
CXXFLAGS := -I$(top_srcdir)/include `$(WX_CONFIG) --cxxflags` -g
commit 06d5b206e24809152471268a618bd0283722e4ee
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 00:54:44 2025 +0100
Don't soft wrap "References" header value
This is done when constructing the final message and there is no need to
do it twice.
diff --git a/src/gui/wxComposeView.cpp b/src/gui/wxComposeView.cpp
index e04e6f18..603d96f1 100644
--- a/src/gui/wxComposeView.cpp
+++ b/src/gui/wxComposeView.cpp
@@ -5519,10 +5519,7 @@ bool wxComposeView::ConfigureInReplyTo()
// if replacement failed (or if we had nothing to replace),
// just add new message id
if ( !ref.empty() )
- {
- // continue "References" header on the next line
- ref += _T("\015\012 ");
- }
+ ref += ' ';
ref += messageIdNew;
}
diff --git a/src/mail/MailFolder.cpp b/src/mail/MailFolder.cpp
index e2a2f36b..4a597b6d 100644
--- a/src/mail/MailFolder.cpp
+++ b/src/mail/MailFolder.cpp
@@ -1117,10 +1117,7 @@ MailFolder::ReplyMessage(Message *msg,
{
String references = headersOrig[1].Trim(TRUE).Trim(FALSE);
if ( !references.empty() )
- {
- // continue "References" header on the next line
- references += _T("\015\012 ");
- }
+ references += ' ';
references += messageid;
cv->AddHeaderEntry(_T("References"), references);
commit 64372212fc20adc244123679f96a2f5612b147d0
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 00:40:58 2025 +0100
Compare header names case-insensitively
Header names are not case-sensitive, so don't allow adding 2 headers
differing in case only.
diff --git a/src/gui/wxComposeView.cpp b/src/gui/wxComposeView.cpp
index 60fc33d6..e04e6f18 100644
--- a/src/gui/wxComposeView.cpp
+++ b/src/gui/wxComposeView.cpp
@@ -5384,7 +5384,7 @@ wxComposeView::AddHeaderEntry(const String& name, const String& value)
i != end;
++i, ++j )
{
- if ( *i == name )
+ if ( wxStricmp(*i, name) == 0 )
{
if ( value.empty() )
{
@@ -5421,7 +5421,7 @@ bool wxComposeView::IsInReplyTo() const
end = m_extraHeadersNames.end();
for ( i = m_extraHeadersNames.begin(); i != end; ++i )
{
- if ( *i == "In-Reply-To" )
+ if ( wxStricmp(*i, "In-Reply-To") == 0 )
return true;
}
@@ -5435,7 +5435,7 @@ bool wxComposeView::ConfigureInReplyTo()
for ( i = m_extraHeadersNames.begin(),
j = m_extraHeadersValues.begin(); i != end; ++i, ++j )
{
- if ( *i == "In-Reply-To" )
+ if ( wxStricmp(*i, "In-Reply-To") == 0 )
break;
}
@@ -5458,7 +5458,7 @@ bool wxComposeView::ConfigureInReplyTo()
end = m_extraHeadersNames.end(),
j = m_extraHeadersValues.begin() ; i != end; ++i, ++j )
{
- if ( *i == "References" )
+ if ( wxStricmp(*i, "References") == 0 )
{
String ref = *j;
ref.Trim(true).Trim(false);
@@ -5508,7 +5508,7 @@ bool wxComposeView::ConfigureInReplyTo()
end = m_extraHeadersNames.begin(),
j = m_extraHeadersValues.begin(); i != end; ++i, ++j )
{
- if ( *i == "References" )
+ if ( wxStricmp(*i, "References") == 0 )
{
String ref = *j;
commit 610297bac03abfb00321bd71289c82067f51a858
Author: Vadim Zeitlin <[email protected]>
Date: Wed Mar 12 00:39:45 2025 +0100
Let NeedsEncodingInHeader() check for ASCII too
We don't need to check whether a (Unicode) code point is an ASCII
character before calling this function if we avoid the truncating
conversion of its argument.
diff --git a/src/mail/MimeDecode.cpp b/src/mail/MimeDecode.cpp
index e2e8c799..9134fb4c 100644
--- a/src/mail/MimeDecode.cpp
+++ b/src/mail/MimeDecode.cpp
@@ -432,7 +432,7 @@ String MIME::DecodeHeader(const String& in, wxFontEncoding *pEncoding)
// returns true if the character must be encoded in a MIME header
//
// NB: we suppose that any special characters had been already escaped
-static inline bool NeedsEncodingInHeader(unsigned char c)
+static inline bool NeedsEncodingInHeader(unsigned c)
{
return c < 20 || c >= 127;
}
@@ -449,7 +449,7 @@ static bool NeedsEncoding(const String& in)
// 822 headers
for ( auto c : in )
{
- if ( !c.IsAscii() || NeedsEncodingInHeader(c.GetValue()) )
+ if ( NeedsEncodingInHeader(c.GetValue()) )
return true;
}
commit 43f8634ada42e8e998e9962c7f1fdea7adb4a07e
Author: Vadim Zeitlin <[email protected]>
Date: Tue Mar 11 23:22:21 2025 +0100
Don't MIME-encode header names
This was added in the apparently unrelated 5ca32298 (Replace all uses of
obsolete kbList stuff with std::list., 2010-06-29) and doesn't make any
sense.
diff --git a/src/gui/wxComposeView.cpp b/src/gui/wxComposeView.cpp
index 6a34407b..60fc33d6 100644
--- a/src/gui/wxComposeView.cpp
+++ b/src/gui/wxComposeView.cpp
@@ -5401,7 +5401,7 @@ wxComposeView::AddHeaderEntry(const String& name, const String& value)
}
// if we didn't find it, add a new one
- m_extraHeadersNames.push_back(MIME::EncodeHeader(name).data());
+ m_extraHeadersNames.push_back(name.utf8_string());
m_extraHeadersValues.push_back(MIME::EncodeHeader(value).data());
}
commit a1e6cff79899ea701e8e6e033618a622d501a674
Author: Vadim Zeitlin <[email protected]>
Date: Tue Mar 11 18:46:58 2025 +0100
Reopen previously opened mailboxes on resume under Linux too
Create a power resource blocker to be notified about suspend and resume
under Linux and so be able to reopen (even remote) mailboxes.
diff --git a/include/gui/wxMainFrame.h b/include/gui/wxMainFrame.h
index 477599db..54e1d98d 100644
--- a/include/gui/wxMainFrame.h
+++ b/include/gui/wxMainFrame.h
@@ -128,6 +128,10 @@ protected:
#ifdef wxHAS_POWER_EVENTS
+#if wxCHECK_VERSION(3, 3, 0)
+ wxPowerResourceBlocker m_powerDelaySleep;
+#endif // wx 3.3.0+
+
// the list of folders which were opened when we were suspended
typedef std::vector<MailFolder*> MailFolders;
MailFolders m_foldersToResume;
diff --git a/src/gui/wxMainFrame.cpp b/src/gui/wxMainFrame.cpp
index 8f39b421..d55f1434 100644
--- a/src/gui/wxMainFrame.cpp
+++ b/src/gui/wxMainFrame.cpp
@@ -628,6 +628,14 @@ END_EVENT_TABLE()
wxMainFrame::wxMainFrame(const String &iname, wxFrame *parent)
: wxMFrame(iname,parent)
+#if wxCHECK_VERSION(3, 3, 0)
+ // We could wait until we open any network connections before
+ // doing this, but it does no real harm to initialize it
+ // immediately.
+ , m_powerDelaySleep(wxPOWER_RESOURCE_SYSTEM,
+ _("Close network connections"),
+ wxPOWER_DELAY)
+#endif // wx 3.3.0+
{
// init members
m_searchData = NULL;
commit 5bc4dbcf83c197a1ede8eac399b55d6a1ecb50dc
Author: Vadim Zeitlin <[email protected]>
Date: Tue Mar 11 18:45:56 2025 +0100
Use CallAfter() instead of disconnecting event handler
Simplify the code a bit by using CallAfter() instead of defining and
connecting a handler which is only called once and then disconnects
itself.
No real changes.
diff --git a/src/gui/wxComposeView.cpp b/src/gui/wxComposeView.cpp
index 27beb3da..6a34407b 100644
--- a/src/gui/wxComposeView.cpp
+++ b/src/gui/wxComposeView.cpp
@@ -800,21 +800,13 @@ public:
// AddHeaderEntry("In-Reply-To") is called after composer creation, so we
// want to update our state a bit later
- Connect(wxEVT_IDLE, wxIdleEventHandler(IsReplyButton::OnIdle));
+ CallAfter(&ToggleIconButton::Update);
}
private:
virtual void DoHandleClick() { m_composer->ConfigureInReplyTo(); }
virtual bool DoGetValue() const { return m_composer->IsInReplyTo(); }
- void OnIdle(wxIdleEvent& /* event */)
- {
- Disconnect(wxID_ANY, wxEVT_IDLE,
- wxIdleEventHandler(IsReplyButton::OnIdle));
-
- Update();
- }
-
DECLARE_NO_COPY_CLASS(IsReplyButton)
};
-----------------------------------------------------------------------
Summary of changes:
include/gui/wxMainFrame.h | 4 +
include/mail/MimeDecode.h | 2 +-
src/gui/wxComposeView.cpp | 49 ++++---
src/gui/wxMainFrame.cpp | 8 ++
src/mail/AddressCC.cpp | 2 +-
src/mail/MailFolder.cpp | 5 +-
src/mail/MimeDecode.cpp | 333 ++++++++++++++++++++++++---------------------
src/mail/SendMessageCC.cpp | 14 +-
tests/mime/Makefile | 7 +-
tests/mime/decode.cpp | 45 +++---
10 files changed, 252 insertions(+), 217 deletions(-)
hooks/post-receive
--
Mahogany sources repository.