isspace() breaks encoding in rfc2047.c on some systems
Dennis Preiser <[email protected]> Tue, 16 Mar 2010 20:40:33 +0100
| Newsgroups | gmane.network.tin.devel |
|---|---|
| Message-ID | <[email protected]> |
I encountered the following issue:
On my system (MacOSX 10.4, powerpc-apple-darwin8.11.0) isspace()
returns TRUE for '0xa0' (I use an UTF-8 locale). 0xa0 can be the second
byte of a two byte UTF-8 character, for instance:
Š 0xc5 0xa0
This causes the isbetween() macro in rfc2047.c to return TRUE and the
various encoding functions fail. For quoted-printable and the character
above in the subject it looks like this:
Subject: =?UTF-8?Q?=C5?=
followed by 0xA0. (The internal inews complains about unencoded 8-bit
chars, which is correct.)
Here some code to check the behaviour of isspace() (returns TRUE with an
UTF-8 locale on my system):
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
int
main(
void)
{
unsigned char ch = 0xa0;
setlocale(LC_ALL, "");
printf("isspace(0xa0) = %s\n", isspace(ch) ? "TRUE" : "FALSE");
return 0;
}
According to google (quick check with 'isspace(0xa0)'), there seems to
be some systems whith such a behaviour. MacOSX, (older?) BSD and linux
with an older glibc version.
I think we have to decide whether it is worse to be fixed and if so, how.
One solution might be the use of iswspace() when dealing with those data
(depending on the locale?). In addition, there might be other functions
that behave uncommon whith utf-8 input (isalpha(), isalnum()...).
As a preliminary fix, I use the patch below. It replaces the isspace()
inside isbetween() whith a check for the common white-space characters.
Btw.: We use the encoding functions to write the overview, thus the
cached overview is badly encoded too.
Dennis
--- tin-1.9.6_r1/src/rfc2047.c 2009-12-01 15:15:30.000000000 +0100
+++ tin-1.9.6_r2/src/rfc2047.c 2010-03-16 19:30:36.000000000 +0100
@@ -49,7 +49,17 @@
* in unstructured headers like Subject, Keyword and Summary
* c.f. RFC 2047
*/
-#define isbetween(c, s) (isspace((unsigned char) c) || ((s) && ((c) == '(' || (c) == ')' || (c) == '"')))
+/*
+ * On some systems isspace(0xa0) returns TRUE (UTF-8 locale).
+ * 0xa0 can be the second byte of a UTF-8 character and must not be
+ * treated as whitespace, otherwise Q and B encoding fails.
+ */
+#if 0
+ #define isbetween(c, s) (isspace((unsigned char) c) || ((s) && ((c) == '(' || (c) == ')' || (c) == '"')))
+#else
+ #define my_isspace(c) ((c) == '\t' || (c) == '\n' || (c) == '\v' || (c) == '\f' || (c) == '\r' || (c) == ' ')
+ #define isbetween(c, s) (my_isspace(c) || ((s) && ((c) == '(' || (c) == ')' || (c) == '"')))
+#endif /* 0 */
#define NOT_RANKED 255