(fix) properly support big characters in EAS and fix encoding QP EAS error for Outlook (#3082)

pull/89/head
Ludovic Marcotte 2015-06-10 10:58:59 -04:00
parent b1453e1d7e
commit 6bc471ad9a
3 changed files with 126 additions and 15 deletions

View File

@ -46,6 +46,94 @@ static NSArray *easCommandParameters = nil;
@implementation NSString (ActiveSync) @implementation NSString (ActiveSync)
//
// This is a copy from NSString+XMLEscaping.m from SOPE.
// The difference here is that we use wchar_t instead of unichar.
// This is needed to get the rigth numeric character reference.
// e.g. SMILING FACE WITH OPEN MOUTH
// ok: wchar_t -> 😃 wrong: unichar -> � �
//
- (NSString *)stringByEscapingXMLStringUsingCharacters {
register unsigned i, len, j;
register wchar_t *buf;
const wchar_t *chars;
unsigned escapeCount;
if ([self length] == 0) return @"";
NSData *data = [self dataUsingEncoding:NSUTF32StringEncoding];
chars = [data bytes];
len = [data length]/4;
/* check for characters to escape ... */
for (i = 0, escapeCount = 0; i < len; i++) {
switch (chars[i]) {
case '&': case '"': case '<': case '>': case '\r':
escapeCount++;
break;
default:
if (chars[i] > 127)
escapeCount++;
break;
}
}
if (escapeCount == 0 ) {
/* nothing to escape ... */
return [[self copy] autorelease];
}
buf = calloc((len + 5) + (escapeCount * 16), sizeof(wchar_t));
for (i = 0, j = 0; i < len; i++) {
switch (chars[i]) {
/* escape special chars */
case '\r':
buf[j] = '&'; j++; buf[j] = '#'; j++; buf[j] = '1'; j++;
buf[j] = '3'; j++; buf[j] = ';'; j++;
break;
case '&':
buf[j] = '&'; j++; buf[j] = 'a'; j++; buf[j] = 'm'; j++;
buf[j] = 'p'; j++; buf[j] = ';'; j++;
break;
case '"':
buf[j] = '&'; j++; buf[j] = 'q'; j++; buf[j] = 'u'; j++;
buf[j] = 'o'; j++; buf[j] = 't'; j++; buf[j] = ';'; j++;
break;
case '<':
buf[j] = '&'; j++; buf[j] = 'l'; j++; buf[j] = 't'; j++;
buf[j] = ';'; j++;
break;
case '>':
buf[j] = '&'; j++; buf[j] = 'g'; j++; buf[j] = 't'; j++;
buf[j] = ';'; j++;
break;
default:
/* escape big chars */
if (chars[i] > 127) {
unsigned char nbuf[32];
unsigned int k;
sprintf((char *)nbuf, "&#%i;", (int)chars[i]);
for (k = 0; nbuf[k] != '\0'; k++) {
buf[j] = nbuf[k];
j++;
}
}
else if (chars[i] == 0x9 || chars[i] == 0xA || chars[i] == 0xD || chars[i] >= 0x20) { // ignore any unsupported control character
/* nothing to escape */
buf[j] = chars[i];
j++;
}
break;
}
}
self = [[[NSString alloc] initWithBytes:buf length:(j) * sizeof(wchar_t) encoding:NSUTF32StringEncoding] autorelease];
if (buf) free(buf);
return self;
}
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType - (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType
{ {
if (folderType == ActiveSyncEventFolder) if (folderType == ActiveSyncEventFolder)
@ -65,11 +153,7 @@ static NSArray *easCommandParameters = nil;
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context - (NSString *) activeSyncRepresentationInContext: (WOContext *) context
{ {
NSString *s; return [self stringByEscapingXMLStringUsingCharacters];
s = [self safeString];
return [s stringByEscapingHTMLString];
} }
- (int) activeSyncFolderType - (int) activeSyncFolderType

View File

@ -381,11 +381,6 @@ struct GlobalObjectId {
if (s) if (s)
{ {
// We sanitize the content immediately, in case we have non-UNICODE safe
// characters that would be re-encoded later in HTML entities and thus,
// ignore afterwards.
s = [s safeString];
body = [s dataUsingEncoding: NSUTF8StringEncoding]; body = [s dataUsingEncoding: NSUTF8StringEncoding];
} }
@ -866,10 +861,41 @@ struct GlobalObjectId {
if (d) if (d)
{ {
NSMutableData *sanitizedData;
NSString *content; NSString *content;
int len, truncated; int len, truncated;
content = [[NSString alloc] initWithData: d encoding: NSUTF8StringEncoding]; // Outlook fails to decode quoted-printable (see #3082) if lines are not termined by CRLF.
const char *bytes;
char *mbytes;
int mlen;
len = [d length];
mlen = 0;
sanitizedData = [NSMutableData dataWithLength: len*2];
bytes = [d bytes];
mbytes = [sanitizedData mutableBytes];
while (len > 0)
{
if (*bytes == '\n' && *(bytes-1) != '\r' && mlen > 0)
{
*mbytes = '\r';
mbytes++;
mlen++;
}
*mbytes = *bytes;
mbytes++; bytes++;
len--;
mlen++;
}
[sanitizedData setLength: mlen];
content = [[NSString alloc] initWithData: sanitizedData encoding: NSUTF8StringEncoding];
// FIXME: This is a hack. We should normally avoid doing this as we might get // FIXME: This is a hack. We should normally avoid doing this as we might get
// broken encodings. We should rather tell that the data was truncated and expect // broken encodings. We should rather tell that the data was truncated and expect
@ -879,15 +905,15 @@ struct GlobalObjectId {
// for an "interesting" discussion around this. // for an "interesting" discussion around this.
// //
if (!content) if (!content)
content = [[NSString alloc] initWithData: d encoding: NSISOLatin1StringEncoding]; content = [[NSString alloc] initWithData: sanitizedData encoding: NSISOLatin1StringEncoding];
AUTORELEASE(content); AUTORELEASE(content);
content = [content activeSyncRepresentationInContext: context]; content = [content activeSyncRepresentationInContext: context];
truncated = 0; truncated = 0;
len = [content length]; len = [content length];
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"]) if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
{ {
[s appendFormat: @"<Body xmlns=\"Email:\">%@</Body>", content]; [s appendFormat: @"<Body xmlns=\"Email:\">%@</Body>", content];

1
NEWS
View File

@ -11,6 +11,7 @@ Bug fixes
- fixed some rare cornercases in multidomain configurations - fixed some rare cornercases in multidomain configurations
- properly escape folder after creation using EAS (#3237) - properly escape folder after creation using EAS (#3237)
- fixed potential organizer highjacking when using EAS (#3131) - fixed potential organizer highjacking when using EAS (#3131)
- properly support big characters in EAS and fix encoding QP EAS error for Outlook (#3082)
2.3.0 (2015-06-01) 2.3.0 (2015-06-01)
------------------- -------------------