(fix) properly support big characters in EAS and fix encoding QP EAS error for Outlook (#3082)
parent
b1453e1d7e
commit
6bc471ad9a
|
@ -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
|
||||||
|
|
|
@ -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
1
NEWS
|
@ -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)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
Loading…
Reference in New Issue