From 1c5e6affb99c04ce24df5ebc95baa3ddb59bd7f6 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 15 Jun 2009 22:19:26 +0000 Subject: [PATCH 1/4] Monotone-Parent: 075df52db5284515c4b7994dd7a105a4399e3e3d Monotone-Revision: a8c0400b04fbc2c00e24cc29fcf280e2ec140c4b Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-15T22:19:26 Monotone-Branch: ca.inverse.sogo --- UI/WebServerResources/dtree.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/UI/WebServerResources/dtree.js b/UI/WebServerResources/dtree.js index 5ad0d944e..b2c3143b2 100644 --- a/UI/WebServerResources/dtree.js +++ b/UI/WebServerResources/dtree.js @@ -9,9 +9,10 @@ | Updated: 17.04.2003 | |--------------------------------------------------*/ +/* The content of attribute values should be quoted properly by using the + equivalent entities. */ function dTreeQuote(str) { return (str - .replace(/\\/g, "\\\\") .replace(/\"/g, """) .replace(/\'/g, "'")); } @@ -109,7 +110,6 @@ dTree.prototype = { // Outputs the tree to the page toString: function() { - log("toString invoked"); var str = '
\n'; if (document.getElementById) { if (this.config.useCookies) @@ -122,7 +122,6 @@ dTree.prototype = { return str; }, valueOf: function() { - log("valueOf invoked"); return this.toString(); }, From b73a34e13dee989bb93663020bcb95b627ba662e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Mon, 15 Jun 2009 22:20:01 +0000 Subject: [PATCH 2/4] Monotone-Parent: a8c0400b04fbc2c00e24cc29fcf280e2ec140c4b Monotone-Revision: 283ae5b7ff599697f5fd5e45e27d320ddeaad825 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-15T22:20:01 Monotone-Branch: ca.inverse.sogo --- UI/WebServerResources/MailerUI.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index 1c57f0481..a51382848 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -39,6 +39,17 @@ var deleteMessageRequestCount = 0; var messageCheckTimer; +/* We need to override this method since it is adapted to GCS-based folder + references, which we do not use here */ +function URLForFolderID(folderID) { + var url = ApplicationBaseURL + encodeURI(folderID); + + if (url[url.length-1] == '/') + url = url.substr(0, url.length-1); + + return url; +} + /* mail list */ function openMessageWindow(msguid, url) { From 286f48179af02cdc6b36442af8a0e7b7ba7c51c1 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 16 Jun 2009 01:14:44 +0000 Subject: [PATCH 3/4] Monotone-Parent: 283ae5b7ff599697f5fd5e45e27d320ddeaad825 Monotone-Revision: 1daf3ae5efb711acef15f3e1e04d4dd21f8484a8 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-16T01:14:44 Monotone-Branch: ca.inverse.sogo --- UI/WebServerResources/dtree.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/UI/WebServerResources/dtree.js b/UI/WebServerResources/dtree.js index b2c3143b2..56ce5c194 100644 --- a/UI/WebServerResources/dtree.js +++ b/UI/WebServerResources/dtree.js @@ -13,10 +13,14 @@ equivalent entities. */ function dTreeQuote(str) { return (str + .replace(/&/g, "&") + .replace(/ Date: Tue, 16 Jun 2009 01:15:39 +0000 Subject: [PATCH 4/4] Monotone-Parent: 1daf3ae5efb711acef15f3e1e04d4dd21f8484a8 Monotone-Revision: 914b4e262396efbb440644e500c6fa43e8d23a61 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-16T01:15:39 Monotone-Branch: ca.inverse.sogo --- NEWS | 1 + SOPE/sope-patchset-r1657.diff | 1230 ++++++++++++++++++++------------- 2 files changed, 763 insertions(+), 468 deletions(-) diff --git a/NEWS b/NEWS index 40ad6d452..fc969c205 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,7 @@ UID) - fixed week view alignment problem in IE7 - fixed LDAP and SQL injection bugs +- fixed many bugs related to the encoding and decoding of IMAP folder names 1.0-20090407 (1.0.1) -------------------- diff --git a/SOPE/sope-patchset-r1657.diff b/SOPE/sope-patchset-r1657.diff index c216e5748..b2c638086 100644 --- a/SOPE/sope-patchset-r1657.diff +++ b/SOPE/sope-patchset-r1657.diff @@ -1,3 +1,24 @@ +Index: sope-mime/NGImap4/NGImap4Functions.m +=================================================================== +--- sope-mime/NGImap4/NGImap4Functions.m (revision 1657) ++++ sope-mime/NGImap4/NGImap4Functions.m (working copy) +@@ -367,3 +367,16 @@ + } + + @end /* NGImap4FolderHandler */ ++ ++NSString * ++SaneFolderName(NSString *folderName) ++{ ++ NSString *saneFName; ++ ++ saneFName = [[folderName stringByReplacingString: @"\\" ++ withString: @"\\\\"] ++ stringByReplacingString: @"\"" ++ withString: @"\\\""]; ++ ++ return saneFName; ++} Index: sope-mime/NGImap4/NGImap4Client.h =================================================================== --- sope-mime/NGImap4/NGImap4Client.h (revision 1657) @@ -133,6 +154,24 @@ Index: sope-mime/NGImap4/NGImap4Client.m return [self->normer normalizeResponse:map]; } +@@ -547,7 +561,7 @@ + if (!(_pattern = [self _folder2ImapFolder:_pattern])) + return nil; + +- s = [NSString stringWithFormat:@"list \"%@\" \"%@\"", _folder, _pattern]; ++ s = [NSString stringWithFormat:@"list \"%@\" \"%@\"", SaneFolderName(_folder), _pattern]; + map = [self processCommand:s]; + + if (self->delimiter == nil) { +@@ -591,7 +605,7 @@ + return nil; + } + +- s = [NSString stringWithFormat:@"lsub \"%@\" \"%@\"", _folder, _pattern]; ++ s = [NSString stringWithFormat:@"lsub \"%@\" \"%@\"", SaneFolderName(_folder), _pattern]; + map = [self processCommand:s]; + + if (self->delimiter == nil) { @@ -617,24 +631,25 @@ 'flags' - array of strings (eg (answered,flagged,draft,seen); 'RawResponse' - the raw IMAP4 response @@ -155,7 +194,8 @@ Index: sope-mime/NGImap4/NGImap4Client.m + newFolder = [NSString stringWithString: _folder]; + ASSIGN (self->selectedFolder, newFolder); - s = [NSString stringWithFormat:@"select \"%@\"", self->selectedFolder]; +- s = [NSString stringWithFormat:@"select \"%@\"", self->selectedFolder]; ++ s = [NSString stringWithFormat:@"select \"%@\"", SaneFolderName(self->selectedFolder)]; return [self->normer normalizeSelectResponse:[self processCommand:s]]; } @@ -167,7 +207,43 @@ Index: sope-mime/NGImap4/NGImap4Client.m - (NSDictionary *)status:(NSString *)_folder flags:(NSArray *)_flags { NSString *cmd; -@@ -820,23 +835,23 @@ +@@ -646,7 +661,7 @@ + return nil; + + cmd = [NSString stringWithFormat:@"status \"%@\" (%@)", +- _folder, [_flags componentsJoinedByString:@" "]]; ++ SaneFolderName(_folder), [_flags componentsJoinedByString:@" "]]; + return [self->normer normalizeStatusResponse:[self processCommand:cmd]]; + } + +@@ -663,20 +678,21 @@ + if ((_newName = [self _folder2ImapFolder:_newName]) == nil) + return nil; + +- cmd = [NSString stringWithFormat:@"rename \"%@\" \"%@\"", _folder, _newName]; ++ cmd = [NSString stringWithFormat:@"rename \"%@\" \"%@\"", ++ SaneFolderName(_folder), SaneFolderName(_newName)]; + + return [self->normer normalizeResponse:[self processCommand:cmd]]; + } + + - (NSDictionary *)_performCommand:(NSString *)_op onFolder:(NSString *)_fname { + NSString *command; +- ++ + if ((_fname = [self _folder2ImapFolder:_fname]) == nil) + return nil; +- ++ + // eg: 'delete "blah"' +- command = [NSString stringWithFormat:@"%@ \"%@\"", _op, _fname]; +- ++ command = [NSString stringWithFormat:@"%@ \"%@\"", _op, SaneFolderName(_fname)]; ++ + return [self->normer normalizeResponse:[self processCommand:command]]; + } + +@@ -820,23 +836,23 @@ return [self->normer normalizeResponse:[self processCommand:cmd]]; } @@ -197,7 +273,7 @@ Index: sope-mime/NGImap4/NGImap4Client.m seqstr, _flag ? '+' : '-', flagstr]; return [self->normer normalizeResponse:[self processCommand:cmd]]; -@@ -967,11 +982,12 @@ +@@ -967,11 +983,12 @@ descr = @"Could not process qualifier for imap search "; descr = [descr stringByAppendingString:reason]; @@ -213,7 +289,7 @@ Index: sope-mime/NGImap4/NGImap4Client.m } - (NSString *)_searchExprForQual:(EOQualifier *)_qualifier { -@@ -1093,7 +1109,18 @@ +@@ -1093,7 +1110,18 @@ Eg: UID SORT ( DATE REVERSE SUBJECT ) UTF-8 TODO */ NSString *tmp; @@ -232,7 +308,7 @@ Index: sope-mime/NGImap4/NGImap4Client.m if ([_sortSpec isKindOfClass:[NSArray class]]) tmp = [self _generateIMAP4SortOrderings:_sortSpec]; else if ([_sortSpec isKindOfClass:[EOSortOrdering class]]) -@@ -1107,9 +1134,10 @@ +@@ -1107,9 +1135,10 @@ tmp = @"DATE"; } @@ -245,7 +321,7 @@ Index: sope-mime/NGImap4/NGImap4Client.m } - (NSDictionary *)sort:(NSArray *)_sortOrderings qualifier:(EOQualifier *)_qual -@@ -1130,7 +1158,7 @@ +@@ -1130,7 +1159,7 @@ return nil; } @@ -254,7 +330,50 @@ Index: sope-mime/NGImap4/NGImap4Client.m return [self->normer normalizeSearchResponse:[self processCommand:s]]; } -@@ -1193,6 +1221,82 @@ +@@ -1142,7 +1171,7 @@ + if ((_folder = [self _folder2ImapFolder:_folder]) == nil) + return nil; + +- cmd = [NSString stringWithFormat:@"getacl \"%@\"", _folder]; ++ cmd = [NSString stringWithFormat:@"getacl \"%@\"", SaneFolderName(_folder)]; + return [self->normer normalizeGetACLResponse:[self processCommand:cmd]]; + } + +@@ -1155,7 +1184,7 @@ + return nil; + + cmd = [NSString stringWithFormat:@"setacl \"%@\" \"%@\" \"%@\"", +- _folder, _uid, _r]; ++ SaneFolderName(_folder), _uid, _r]; + return [self->normer normalizeResponse:[self processCommand:cmd]]; + } + +@@ -1166,7 +1195,7 @@ + return nil; + + cmd = [NSString stringWithFormat:@"deleteacl \"%@\" \"%@\"", +- _folder, _uid]; ++ SaneFolderName(_folder), _uid]; + return [self->normer normalizeResponse:[self processCommand:cmd]]; + } + +@@ -1177,7 +1206,7 @@ + return nil; + + cmd = [NSString stringWithFormat:@"listrights \"%@\" \"%@\"", +- _folder, _uid]; ++ SaneFolderName(_folder), _uid]; + return [self->normer normalizeListRightsResponse:[self processCommand:cmd]]; + } + +@@ -1187,12 +1216,88 @@ + if ((_folder = [self _folder2ImapFolder:_folder]) == nil) + return nil; + +- cmd = [NSString stringWithFormat:@"myrights \"%@\"", _folder]; ++ cmd = [NSString stringWithFormat:@"myrights \"%@\"", SaneFolderName(_folder)]; + return [self->normer normalizeMyRightsResponse:[self processCommand:cmd]]; + } /* Private Methods */ @@ -337,6 +456,26 @@ Index: sope-mime/NGImap4/NGImap4Client.m - (NSException *)_processCommandParserException:(NSException *)_exception { [self logWithFormat:@"ERROR(%s): catched IMAP4 parser exception %@: %@", __PRETTY_FUNCTION__, [_exception name], [_exception reason]]; +@@ -1412,7 +1517,8 @@ + return nil; + } + +- array = [_folder pathComponents]; ++// array = [_folder pathComponents]; ++ array = [_folder componentsSeparatedByString:self->delimiter]; + + if ([array isNotEmpty]) { + NSString *o; +@@ -1445,7 +1551,8 @@ + array = [array arrayByAddingObjectsFromArray: + [_folder componentsSeparatedByString:[self delimiter]]]; + +- return [[NSString pathWithComponents:array] stringByDecodingImap4FolderName]; ++ return [[array componentsJoinedByString: self->delimiter] ++ stringByDecodingImap4FolderName]; + } + + - (void)setContext:(NGImap4Context *)_ctx { Index: sope-mime/NGImap4/NGSieveClient.m =================================================================== --- sope-mime/NGImap4/NGSieveClient.m (revision 1657) @@ -389,23 +528,26 @@ Index: sope-mime/NGImap4/NGImap4Connection.m =================================================================== --- sope-mime/NGImap4/NGImap4Connection.m (revision 1657) +++ sope-mime/NGImap4/NGImap4Connection.m (working copy) -@@ -373,7 +373,14 @@ +@@ -22,6 +22,7 @@ + #include "NGImap4Connection.h" + #include "NGImap4MailboxInfo.h" + #include "NGImap4Client.h" ++#include "NGImap4Functions.h" + #include "imCommon.h" + + @implementation NGImap4Connection +@@ -373,7 +374,9 @@ /* folder operations */ -- (NSDictionary *)primaryFetchMailboxHierarchyForURL:(NSURL *)_url { +- (NSDictionary *)primaryFetchMailboxHierarchyForURL:(NSURL *)_url -+{ -+ return [self primaryFetchMailboxHierarchyForURL: _url onlySubscribedFolders: NO]; -+} -+ -+- (NSDictionary *)primaryFetchMailboxHierarchyForURL:(NSURL *)_url + onlySubscribedFolders: (BOOL) subscribedFoldersOnly +{ NSDictionary *result; if ((result = [self cachedHierarchyResults]) != nil) -@@ -381,8 +388,12 @@ +@@ -381,8 +384,12 @@ if (debugCache) [self logWithFormat:@" no folders cached yet .."]; @@ -420,17 +562,24 @@ Index: sope-mime/NGImap4/NGImap4Connection.m if (![[result valueForKey:@"result"] boolValue]) { [self errorWithFormat:@"Could not list mailbox hierarchy!"]; return nil; -@@ -413,10 +424,18 @@ +@@ -400,6 +407,11 @@ + return result; + } + ++- (NSDictionary *)primaryFetchMailboxHierarchyForURL:(NSURL *)_url ++{ ++ return [self primaryFetchMailboxHierarchyForURL: _url onlySubscribedFolders: NO]; ++} ++ + - (NSArray *)subfoldersForURL:(NSURL *)_url { + NSDictionary *result; + +@@ -413,10 +425,13 @@ return [self extractSubfoldersForURL:_url fromResultSet:result]; } -- (NSArray *)allFoldersForURL:(NSURL *)_url { +- (NSArray *)allFoldersForURL:(NSURL *)_url -+{ -+ return [self allFoldersForURL: _url onlySubscribedFolders: NO]; -+} -+ -+- (NSArray *)allFoldersForURL:(NSURL *)_url + onlySubscribedFolders: (BOOL) subscribedFoldersOnly +{ NSDictionary *result; @@ -441,7 +590,19 @@ Index: sope-mime/NGImap4/NGImap4Connection.m return nil; if ([result isKindOfClass:[NSException class]]) { [self errorWithFormat:@"failed to retrieve hierarchy: %@", result]; -@@ -646,7 +665,7 @@ +@@ -426,6 +441,11 @@ + return [self extractFoldersFromResultSet:result]; + } + ++- (NSArray *)allFoldersForURL:(NSURL *)_url ++{ ++ return [self allFoldersForURL: _url onlySubscribedFolders: NO]; ++} ++ + /* message operations */ + + - (NSArray *)fetchUIDsInURL:(NSURL *)_url qualifier:(id)_qualifier +@@ -646,7 +666,7 @@ /* store flags */ @@ -450,16 +611,7 @@ Index: sope-mime/NGImap4/NGImap4Connection.m if (![[result valueForKey:@"result"] boolValue]) { return [self errorForResult:result text:@"Failed to change flags of IMAP4 message"]; -@@ -736,7 +755,7 @@ - /* managing folders */ - - - (BOOL)doesMailboxExistAtURL:(NSURL *)_url { -- NSString *folderName; -+ NSString *folderName, *previousFolderName; - id result; - - /* check in hierarchy cache */ -@@ -760,11 +779,11 @@ +@@ -760,11 +780,11 @@ // TODO: we should probably just fetch the whole hierarchy? folderName = [self imap4FolderNameForURL:_url]; @@ -480,7 +632,39 @@ Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.m =================================================================== --- sope-mime/NGImap4/NGImap4ResponseNormalizer.m (revision 1657) +++ sope-mime/NGImap4/NGImap4ResponseNormalizer.m (working copy) -@@ -292,7 +292,7 @@ +@@ -76,22 +76,6 @@ + return self; + } + +-/* client callbacks */ +- +-- (void)closeConnection { +- [(id)self->client closeConnection]; +-} +- +-- (NSString *)delimiter { +- return [self->client delimiter]; +-} +- +-/* folder handling */ +- +-- (NSString *)_imapFolder2Folder:(NSString *)_folder { +- return [self->client _imapFolder2Folder:_folder]; +-} +- + /* primary */ + + - (NSMutableDictionary *)normalizeResponse:(NGHashMap *)_map { +@@ -117,7 +101,7 @@ + if ((obj = [_map objectForKey:@"bye"])) { + [result setObject:NoNumber forKey:@"result"]; + [result setObject:obj forKey:@"reason"]; +- [self closeConnection]; ++ [self->client closeConnection]; + return result; + } + +@@ -292,7 +276,7 @@ /* filter for fetch response fetch : NSArray (fetch responses) @@ -489,7 +673,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.m 'text' - RFC822.TEXT 'size' - SIZE 'flags' - FLAGS -@@ -336,7 +336,12 @@ +@@ -336,7 +320,12 @@ switch (c) { case 'b': /* Note: we check for _prefix_! eg body[1] is valid too */ @@ -503,7 +687,25 @@ Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.m keys[count] = @"body"; values[count] = objForKey(obj, @selector(objectForKey:), key); count++; -@@ -648,14 +653,13 @@ +@@ -516,7 +505,7 @@ + } + continue; + } +- [tmp setObject:qDesc forKey:[self _imapFolder2Folder:obj]]; ++ [tmp setObject:qDesc forKey:[self->client _imapFolder2Folder:obj]]; + } + [result setObject:tmp forKey:@"quotas"]; + return [[result copy] autorelease]; +@@ -615,7 +604,7 @@ + + while ((o = [enumerator nextObject])) { + [folder setObject:_imapFlags2Flags(self, [o objectForKey:@"flags"]) +- forKey:[self _imapFolder2Folder:[o objectForKey:@"folderName"]]]; ++ forKey:[self->client _imapFolder2Folder:[o objectForKey:@"folderName"]]]; + } + + { +@@ -648,14 +637,13 @@ enumerator = [_flags objectEnumerator]; cnt = 0; while ((obj = [enumerator nextObject])) { @@ -732,7 +934,36 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m } - (void)_consumeOptionalSpace { if (_la(self, 0) == ' ') _consume(self, 1); -@@ -1090,6 +1249,8 @@ +@@ -685,6 +844,10 @@ + name = [self _parseQuotedString]; + _parseUntil(self, '\n'); + } ++ else if (_la(self, 0) == '{') { ++ name = [self _parseQuotedStringOrNIL]; ++ _parseUntil(self, '\n'); ++ } + else + name = _parseUntil(self, '\n'); + +@@ -1030,10 +1193,15 @@ + _consume(self, 7); + + if (_la(self, 0) == '"') { +- _consume(self, 1); +- name = _parseUntil(self, '"'); ++ name = [self _parseQuotedString]; ++// _consume(self, 1); ++// name = _parseUntil(self, '"'); + _consumeIfMatch(self, ' '); + } ++ else if (_la(self, 0) == '{') { ++ name = [self _parseQuotedStringOrNIL]; ++ _consumeIfMatch(self, ' '); ++ } + else { + name = _parseUntil(self, ' '); + } +@@ -1090,6 +1258,8 @@ return @""; s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; @@ -741,7 +972,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m if (s == nil) { [self logWithFormat: @"ERROR(%s): could not convert data (%d bytes) into string.", -@@ -1185,7 +1346,7 @@ +@@ -1185,7 +1355,7 @@ route = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace]; mailbox = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace]; host = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace]; @@ -750,7 +981,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m if (_la(self, 0) != ')') { [self logWithFormat:@"WARNING: IMAP4 envelope " @"address not properly closed (c0=%c,c1=%c): %@", -@@ -1197,6 +1358,7 @@ +@@ -1197,6 +1367,7 @@ address = [[NGImap4EnvelopeAddress alloc] initWithPersonalName:pname sourceRoute:route mailbox:mailbox host:host]; @@ -758,7 +989,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m return address; } -@@ -1382,7 +1544,15 @@ +@@ -1382,7 +1553,15 @@ #if 0 [self logWithFormat:@"PARSE KEY: %@", key]; #endif @@ -775,7 +1006,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m NSDictionary *content; if ((content = [self _parseBodyContent]) != nil) -@@ -1594,8 +1764,11 @@ +@@ -1594,8 +1773,11 @@ if (_decode) data = [data decodeQuotedPrintableValueOfMIMEHeaderField:nil]; @@ -789,7 +1020,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m } else { str = _parseUntil2(self, ' ', ')'); -@@ -1620,13 +1793,35 @@ +@@ -1620,13 +1802,35 @@ return str; } @@ -826,7 +1057,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m static NSDictionary *_parseBodyParameterList(NGImap4ResponseParser *self) { NSMutableDictionary *list; -@@ -1646,7 +1841,7 @@ +@@ -1646,7 +1850,7 @@ _consumeIfMatch(self, ' '); value = _parseBodyDecodeString(self, YES, YES); @@ -835,7 +1066,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m } _consumeIfMatch(self, ')'); } -@@ -1731,13 +1926,14 @@ +@@ -1731,13 +1935,14 @@ static NSDictionary *_parseSingleBody(NGImap4ResponseParser *self, BOOL isBodyStructure) { NSString *type, *subtype, *bodyId, *description, @@ -852,7 +1083,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m _consumeIfMatch(self, ' '); parameterList = _parseBodyParameterList(self); _consumeIfMatch(self, ' '); -@@ -1762,13 +1958,18 @@ +@@ -1762,13 +1967,18 @@ _consumeIfMatch(self, ' '); [dict setObject:_parseBodyString(self, YES) forKey:@"lines"]; } @@ -874,7 +1105,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m _consumeIfMatch(self, ' '); [dict setObject:_parseParenthesizedAddressList(self) forKey:@"from"]; _consumeIfMatch(self, ' '); -@@ -1783,14 +1984,20 @@ +@@ -1783,14 +1993,20 @@ _consumeIfMatch(self, ' '); [dict setObject:_parseParenthesizedAddressList(self) forKey:@"bcc"]; _consumeIfMatch(self, ' '); @@ -898,7 +1129,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m } } -@@ -1805,14 +2012,9 @@ +@@ -1805,14 +2021,9 @@ forKey: @"disposition"]; if (_la(self, 0) != ')') { _consume(self,1); @@ -916,7 +1147,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m if (_la(self, 0) != ')') { _consume(self,1); [dict setObject: _parseBodyString(self, YES) -@@ -1829,6 +2031,7 @@ +@@ -1829,6 +2040,7 @@ static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self, BOOL isBodyStructure) { NSMutableArray *parts; @@ -924,7 +1155,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m NSString *kind; NSMutableDictionary *dict; -@@ -1854,14 +2057,9 @@ +@@ -1854,14 +2066,9 @@ forKey: @"disposition"]; if (_la(self, 0) != ')') { _consume(self,1); @@ -942,7 +1173,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m if (_la(self, 0) != ')') { _consume(self,1); [dict setObject: _parseBodyString(self, YES) -@@ -2170,6 +2368,21 @@ +@@ -2170,6 +2377,21 @@ } } @@ -964,7 +1195,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m - (NSException *)exceptionForFailedMatch:(unsigned char)_match got:(unsigned char)_avail { -@@ -2225,9 +2438,9 @@ +@@ -2225,9 +2447,9 @@ [s release]; if (c == '\n') { @@ -980,7 +1211,17 @@ Index: sope-mime/NGImap4/ChangeLog =================================================================== --- sope-mime/NGImap4/ChangeLog (revision 1657) +++ sope-mime/NGImap4/ChangeLog (working copy) -@@ -1,3 +1,29 @@ +@@ -1,3 +1,39 @@ ++2009-06-15 Wolfgang Sourdeau ++ ++ * NSString+Imap4.m (-stringByEncodingImap4FolderName, ++ -stringByDecodingImap4FolderName): reimplemented the original ++ methods in a unicode-safe way, thereby simplifying the code at the ++ same time. ++ ++ * NGImap4Functions.m (SaneFolderName): new function designed to ++ sanitize folder names prior to using them in IMAP commands. ++ +2008-10-23 Wolfgang Sourdeau + + * NGImap4Client.m ([NGImap -sort:qualifier:encoding:]): message @@ -1141,7 +1382,7 @@ Index: sope-mime/NGImap4/NSString+Imap4.m =================================================================== --- sope-mime/NGImap4/NSString+Imap4.m (revision 1657) +++ sope-mime/NGImap4/NSString+Imap4.m (working copy) -@@ -20,11 +20,56 @@ +@@ -20,117 +20,86 @@ 02111-1307, USA. */ @@ -1150,66 +1391,34 @@ Index: sope-mime/NGImap4/NSString+Imap4.m #include #include "imCommon.h" - /* TODO: NOT UNICODE SAFE (uses cString) */ - -+#ifndef __APPLE__ -+ -+@interface NSMutableData (PantomimeExtensions) -+ -+- (void) appendCFormat: (NSString *) theFormat, ...; -+- (void) appendCString: (const char *) theCString; -+ -+@end -+ -+@implementation NSMutableData (PantomimeExtensions) -+ -+- (void) appendCFormat: (NSString *) theFormat, ... -+{ -+ NSString *aString; -+ va_list args; -+ -+ va_start(args, theFormat); -+ aString = [[NSString alloc] initWithFormat: theFormat arguments: args]; -+ va_end(args); -+ -+ // We allow lossy conversion to not lose any information / raise an exception -+ [self appendData: [aString dataUsingEncoding: NSASCIIStringEncoding allowLossyConversion: YES]]; -+ -+ RELEASE(aString); -+} -+ -+ -+// -+// -+// -+- (void) appendCString: (const char *) theCString -+{ -+ [self appendBytes: theCString length: strlen(theCString)]; -+} -+ -+@end -+ -+#endif -+ -+@implementation NSString(Imap4) -+ -+#if __APPLE__ -+ - static void _encodeToModifiedUTF7(unsigned char *_buf, int encLen, - unsigned char **result_, - unsigned int *cntRes_); -@@ -33,8 +78,6 @@ - unsigned char **buffer_, - int *bufLen_, int maxBuf); - --@implementation NSString(Imap4) +-/* TODO: NOT UNICODE SAFE (uses cString) */ - +-static void _encodeToModifiedUTF7(unsigned char *_buf, int encLen, +- unsigned char **result_, +- unsigned int *cntRes_); +-static int _decodeOfModifiedUTF7(unsigned char *_target, unsigned _targetLen, +- unsigned *usedBytes_ , +- unsigned char **buffer_, +- int *bufLen_, int maxBuf); +- + @implementation NSString(Imap4) + ++static unsigned int _encodeToModifiedUTF7(unichar *_char, unsigned char *result_, ++ unsigned int *cntRes_); ++static unsigned int _decodeOfModifiedUTF7(unsigned char *_source, unichar *result_, ++ unsigned int *cntRes_ ); ++ - (NSString *)stringByEncodingImap4FolderName { - // TBD: this is restricted to Latin1, should be fixed to UTF-8 - /* dude.d& --> dude.d&- */ -@@ -46,12 +89,15 @@ +- // TBD: this is restricted to Latin1, should be fixed to UTF-8 +- /* dude.d& --> dude.d&- */ +- unsigned char *buf = NULL; ++ unichar *buf = NULL; + unsigned char *res = NULL; + unsigned int len = 0; + unsigned int cnt = 0; + unsigned int cntRes = 0; NSString *result = nil; - NSData *data; +- NSData *data; - len = [self cStringLength]; - buf = calloc(len + 3, sizeof(char)); @@ -1217,69 +1426,324 @@ Index: sope-mime/NGImap4/NSString+Imap4.m - buf[len] = '\0'; - res[len * 6] = '\0'; - [self getCString:(char *)buf]; -+ len = [self lengthOfBytesUsingEncoding: NSISOLatin1StringEncoding] + 1; -+ buf = calloc(len + 3, sizeof(char)); -+ res = calloc((len * 6) + 3, sizeof(char)); -+ [self getCString:(char *)buf maxLength: len -+ encoding: NSISOLatin1StringEncoding]; -+ buf[len-1] = 0; ++ len = [self length]; ++ buf = NSZoneMalloc(NULL, (len + 1) * sizeof(unichar)); ++ [self getCharacters: buf]; + buf[len] = 0; -+ buf[len+1] = 0; -+ buf[len+2] = 0; ++ /* 1 * '&', 3 for the max bytes / char, 1 * '-' */ ++ res = NSZoneMalloc(NULL, ((len * 5) + 1) * sizeof(char)); ++ while (cnt < len) { - int c = buf[cnt]; -@@ -185,70 +231,6 @@ - return [result autorelease]; +- int c = buf[cnt]; ++ unichar c = buf[cnt]; + if (((c > 31) && (c < 38)) || + ((c > 38) && (c < 127))) { + res[cntRes++] = c; +- cnt++; + } + else { + if (c == '&') { + res[cntRes++] = '&'; + res[cntRes++] = '-'; +- cnt++; + } + else { +- int start; +- +- start = cnt; +- +- while (cnt < (len - 1)) { +- int c = buf[cnt + 1]; +- if (((c > 31) && (c < 38)) || +- ((c > 38) && (c < 127)) || +- (c == '&')) { +- break; +- } +- else { +- cnt++; +- } +- } +- { +- unsigned length; +- +- res[cntRes++] = '&'; +- +- length = cnt - start + 1; +- +- _encodeToModifiedUTF7(buf + start, length, &res, &cntRes); +- +- res[cntRes] = '-'; +- cntRes++; +- cnt++; +- } ++ res[cntRes++] = '&'; ++ cnt += _encodeToModifiedUTF7(buf + cnt, res + cntRes, &cntRes); ++ res[cntRes++] = '-'; + } + } ++ cnt++; + } +- if (buf != NULL) free(buf); buf = NULL; ++ if (buf != NULL) NSZoneFree(NULL, buf); + +- data = [[NSData alloc] initWithBytesNoCopy:res length:cntRes +- freeWhenDone:YES]; +- result = [[NSString alloc] initWithData:data +- encoding:NSISOLatin1StringEncoding]; +- [data release]; data = nil; +- +- return [result autorelease]; ++ res[cntRes] = 0; ++ result = [NSString stringWithCString: (char *) res ++ encoding: NSISOLatin1StringEncoding]; ++ ++ return result; } --- (NSString *)stringByEscapingImap4Password { -- // TODO: perf -- unichar *buffer; -- unichar *chars; -- unsigned len, i, j; -- NSString *s; + - (NSString *)stringByDecodingImap4FolderName { +- // TBD: this is restricted to Latin1, should be fixed to UTF-8 +- /* dude/d&- --> dude/d& */ + unsigned char *buf; +- unsigned char *res; ++ unichar *res; + unsigned int len; + unsigned int cnt = 0; + unsigned int cntRes = 0; + NSString *result = nil; +- NSData *data; ++// NSData *data; + +- if ((len = [self cStringLength]) == 0) ++ if ((len = [self lengthOfBytesUsingEncoding: NSISOLatin1StringEncoding]) == 0) + return @""; +- +- buf = calloc(len + 3, sizeof(unsigned char)); +- res = calloc(len + 3, sizeof(unsigned char)); ++ ++ buf = NSZoneMalloc(NULL, (len + 1) * sizeof(unsigned char)); ++ ++ if ([self getCString:(char *)buf maxLength: len + 1 ++ encoding: NSISOLatin1StringEncoding] == NO) { ++ NSZoneFree(NULL, buf); ++ return @""; ++ } + buf[len] = '\0'; +- res[len] = '\0'; +- +- [self getCString:(char *)buf]; +- +- while (cnt < (len - 1)) { /* &- */ ++ ++ res = NSZoneMalloc(NULL, (len + 1) * sizeof(unichar)); ++ ++ while (cnt < len) { /* &- */ + unsigned char c; + + c = buf[cnt]; +@@ -141,29 +110,7 @@ + cnt += 2; + } + else { +- unsigned usedBytes = 0; +- unsigned char *buffer; +- int maxBuf, bufLen; - -- len = [self length]; +- cnt++; +- maxBuf = 511; +- bufLen = 0; +- buffer = calloc(maxBuf + 3, sizeof(char)); +- +- if (_decodeOfModifiedUTF7(buf + cnt, len - cnt, &usedBytes , &buffer, +- &bufLen, maxBuf) == 0) { +- int cnt1; +- +- cnt1 = 0; +- while (cnt1 < bufLen) { +- res[cntRes++] = buffer[cnt1++]; +- } +- cnt += usedBytes; +- } +- else { +- NSCAssert(NO, @"couldn't decode UTF-7 .."); +- } +- free(buffer); buffer = NULL; ++ cnt += _decodeOfModifiedUTF7(buf + cnt + 1, res + cntRes, &cntRes) + 1; + } + } + else { +@@ -171,20 +118,129 @@ + cnt++; + } + } +- if (cnt < len) +- res[cntRes++] = buf[cnt++]; +- +- if (buf != NULL) free(buf); buf = NULL; + +- data = [[NSData alloc] initWithBytesNoCopy:res length:cntRes +- freeWhenDone:YES]; +- result = [[NSString alloc] initWithData:data +- encoding:NSISOLatin1StringEncoding]; +- [data release]; data = nil; +- +- return [result autorelease]; ++ if (buf != NULL) NSZoneFree(NULL, buf); ++ ++ res[cntRes] = 0; ++ result = [NSString stringWithCharacters: res length: cntRes]; ++ ++ return result; + } + ++/* check metamail output for correctness */ ++ ++static unsigned char basis_64[] = ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; ++ ++static char index_64[128] = { ++ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, ++ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, ++ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, ++ 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, ++ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, ++ 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, ++ -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, ++ 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 ++}; ++ ++#define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) ++ ++static unsigned int _encodeToModifiedUTF7(unichar *_char, unsigned char *result_, ++ unsigned int *cntRes_) ++{ ++ unsigned int processedSrc, processedDest, cycle; ++ unichar c; ++ char leftover; ++ ++ processedSrc = 0; ++ processedDest = 0; ++ cycle = 0; ++ leftover = 0; ++ ++ c = *_char; ++ while (c > 126 || (c > 0 && c < 32)) { ++ if (cycle == 0) { ++ *(result_ + processedDest) = basis_64[(c >> 10) & 0x3f]; ++ *(result_ + processedDest + 1) = basis_64[(c >> 4) & 0x3f]; ++ leftover = (c << 2); ++ processedDest += 2; ++ cycle = 1; ++ } ++ else if (cycle == 1) { ++ *(result_ + processedDest) = basis_64[(leftover | (c >> 14)) & 0x3f]; ++ *(result_ + processedDest + 1) = basis_64[(c >> 8) & 0x3f]; ++ *(result_ + processedDest + 2) = basis_64[(c >> 2) & 0x3f]; ++ leftover = (c << 4); ++ processedDest += 3; ++ cycle = 2; ++ } ++ else if (cycle == 2) { ++ *(result_ + processedDest) = basis_64[(leftover | (c >> 12)) & 0x3f]; ++ *(result_ + processedDest + 1) = basis_64[(c >> 6) & 0x3f]; ++ *(result_ + processedDest + 2) = basis_64[c & 0x3f]; ++ leftover = 0; ++ processedDest += 3; ++ cycle = 0; ++ } ++ processedSrc++; ++ c = *(_char + processedSrc); ++ } ++ if (leftover) { ++ *(result_ + processedDest) = basis_64[leftover & 0x3f]; ++ processedDest++; ++ } ++ processedSrc--; ++ *cntRes_ += processedDest; ++ ++ return processedSrc; ++} ++ ++static unsigned int _decodeOfModifiedUTF7(unsigned char *_source, unichar *result_, ++ unsigned int *cntRes_) ++{ ++ unsigned int processedSrc, processedDest; ++ unsigned char c, decoded; ++ unichar currentRes; ++ int shift; ++ ++ processedSrc = 0; ++ processedDest = 0; ++ shift = 10; ++ currentRes = 0; ++ ++ c = *_source; ++ while (c != 0 && c != '-') { ++ decoded = index_64[c]; ++ if (shift < 0) { ++ currentRes |= (decoded >> (shift * -1)); ++ *(result_ + processedDest) = currentRes; ++ processedDest++; ++ shift += 16; ++ currentRes = (decoded << shift); ++ } else { ++ currentRes |= (decoded << shift); ++ if (shift == 0) { ++ *(result_ + processedDest) = currentRes; ++ processedDest++; ++ currentRes = 0; ++ shift = 16; ++ } ++ } ++ shift -= 6; ++ processedSrc++; ++ c = *(_source + processedSrc); ++ } ++ if (shift != 10) { ++ *(result_ + processedDest) = currentRes; ++ } ++ if (c == '-') ++ processedSrc++; ++ ++ *cntRes_ += processedDest; ++ ++ return processedSrc; ++} ++ + - (NSString *)stringByEscapingImap4Password { + // TODO: perf + unichar *buffer; +@@ -193,12 +249,12 @@ + NSString *s; + + len = [self length]; - chars = calloc(len + 2, sizeof(unichar)); -- [self getCharacters:chars]; ++ chars = NSZoneCalloc(NULL, len + 2, sizeof(unichar)); + [self getCharacters:chars]; - - buffer = calloc(len * 2 + 2, sizeof(unichar)); -- buffer[len * 2] = '\0'; ++ ++ buffer = NSZoneCalloc(NULL, len * 2 + 2, sizeof(unichar)); + buffer[len * 2] = '\0'; - -- for (i = 0, j = 0; i < len; i++, j++) { -- BOOL conv = NO; -- -- if (chars[i] <= 0x1F || chars[i] > 0x7F) { -- conv = YES; -- } -- else switch (chars[i]) { -- case '(': -- case ')': -- case '{': -- case ' ': -- case '%': -- case '*': -- case '"': -- case '\\': -- conv = YES; -- break; -- } -- -- if (conv) { -- buffer[j] = '\\'; -- j++; -- } -- buffer[j] = chars[i]; -- } ++ + for (i = 0, j = 0; i < len; i++, j++) { + BOOL conv = NO; + +@@ -224,209 +280,11 @@ + } + buffer[j] = chars[i]; + } - if (chars != NULL) free(chars); chars = NULL; -- -- s = [NSString stringWithCharacters:buffer length:j]; ++ if (chars != NULL) NSZoneFree(NULL, chars); + + s = [NSString stringWithCharacters:buffer length:j]; - if (buffer != NULL) free(buffer); buffer = NULL; -- return s; --} -- --@end /* NSString(Imap4) */ ++ + return s; + } + + @end /* NSString(Imap4) */ - -static void writeChunk(int _c1, int _c2, int _c3, int _pads, - unsigned char **result_, @@ -1297,13 +1761,33 @@ Index: sope-mime/NGImap4/NSString+Imap4.m - } - return result; -} - static void _encodeToModifiedUTF7(unsigned char *_buf, int encLen, - unsigned char **result_, unsigned int *cntRes_) - { -@@ -276,58 +258,6 @@ - } - } - +-static void _encodeToModifiedUTF7(unsigned char *_buf, int encLen, +- unsigned char **result_, unsigned int *cntRes_) +-{ +- int c1, c2, c3; +- int cnt, cntAll; +- +- cnt = 0; +- cntAll = 0; +- +- while (cnt < encLen) { +- c1 = getChar(cntAll++, &cnt, _buf); +- if (cnt == encLen) { +- writeChunk(c1, 0, 0, 2, result_, cntRes_); +- } +- else { +- c2 = getChar(cntAll++, &cnt, _buf); +- if (cnt == encLen) { +- writeChunk(c1, c2, 0, 1, result_, cntRes_); +- } +- else { +- c3 = getChar(cntAll++, &cnt, _buf); +- writeChunk(c1, c2, c3, 0, result_, cntRes_); +- } +- } +- } +-} +- -/* check metamail output for correctness */ - -static unsigned char basis_64[] = @@ -1356,309 +1840,119 @@ Index: sope-mime/NGImap4/NSString+Imap4.m - -#define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) - - static int _decodeOfModifiedUTF7(unsigned char *_target, unsigned _targetLen, - unsigned *usedBytes_ , unsigned char **buffer_, - int *bufLen_, int maxBuf) -@@ -430,3 +360,299 @@ - } - return 0; - } +-static int _decodeOfModifiedUTF7(unsigned char *_target, unsigned _targetLen, +- unsigned *usedBytes_ , unsigned char **buffer_, +- int *bufLen_, int maxBuf) +-{ +- int c1, c2, c3, c4; +- unsigned int cnt; +- +- for (cnt = 0; cnt < _targetLen; ) { +- c1 = '='; +- c2 = '='; +- c3 = '='; +- c4 = '='; +- +- c1 = _target[cnt++]; +- +- if (c1 == '-') { +- (*usedBytes_)++; +- return 0; +- } +- if (cnt < _targetLen) +- c2 = _target[cnt++]; +- +- if (c2 == '-') { +- (*usedBytes_)+=2; +- return 0; +- } +- +- (*usedBytes_) += 2; +- +- if (cnt < _targetLen) { +- c3 = _target[cnt++]; +- (*usedBytes_)++; +- } +- +- if (cnt < _targetLen) { +- c4 = _target[cnt++]; +- if (c3 != '-') +- (*usedBytes_)++; +- } +- +- if (c2 == -1 || c3 == -1 || c4 == -1) { +- fprintf(stderr, "Warning: base64 decoder saw premature EOF!\n"); +- return 0; +- } +- +- if (c1 == '=' || c2 == '=') { +- continue; +- } +- +- c1 = char64(c1); +- c2 = char64(c2); +- +- if (*bufLen_ < maxBuf) { +- unsigned char c; +- +- c = ((c1<<2) | ((c2&0x30)>>4)); +- +- if (c) { +- (*buffer_)[*bufLen_] = c; +- *bufLen_ = *bufLen_ + 1; +- } +- } +- if (c3 == '-') { +- return 0; +- } +- else if (c3 == '=') { +- continue; +- } else { +- +- c3 = char64(c3); +- +- if (*bufLen_ < maxBuf) { +- unsigned char c; +- c = (((c2&0XF) << 4) | ((c3&0x3C) >> 2)); +- if (c) { +- (*buffer_)[*bufLen_] = c; +- *bufLen_ = *bufLen_ + 1; +- } +- } +- +- if (c4 == '-') { +- return 0; +- } +- else if (c4 == '=') { +- continue; +- } else { +- c4 = char64(c4); +- +- if (*bufLen_ < maxBuf) { +- unsigned char c; +- +- c = (((c3&0x03) <<6) | c4); +- if (c) { +- (*buffer_)[*bufLen_] = c; +- (*bufLen_) = (*bufLen_) + 1; +- } +- } +- } +- } +- } +- return 0; +-} +Index: sope-mime/NGImap4/NGImap4Functions.h +=================================================================== +--- sope-mime/NGImap4/NGImap4Functions.h (revision 1657) ++++ sope-mime/NGImap4/NGImap4Functions.h (working copy) +@@ -58,4 +58,6 @@ + id_folder); + BOOL _createSubFolderWithName(id self, NSString *_name, BOOL _app); + ++NSString *SaneFolderName(NSString *folderName); + -+static void writeChunk(int _c1, int _c2, int _c3, int _pads, -+ unsigned char **result_, -+ unsigned int *cntRes_); -+ -+static int getChar(int _cnt, int *cnt_, unsigned char *_buf) { -+ int result; -+ -+ if ((_cnt % 2)) { -+ result = _buf[*cnt_]; -+ (*cnt_)++; -+ } -+ else { -+ result = 0; -+ } -+ return result; -+} -+ -+/* check metamail output for correctness */ -+ -+static unsigned char basis_64[] = -+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -+ -+static void writeChunk(int c1, int c2, int c3, int pads, unsigned char **result_, -+ unsigned int *cntRes_) { -+ unsigned char c; -+ -+ c = basis_64[c1>>2]; -+ (*result_)[*cntRes_] = c; -+ (*cntRes_)++; -+ -+ c = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)]; -+ -+ (*result_)[*cntRes_] = c; -+ (*cntRes_)++; -+ -+ -+ if (pads == 2) { -+ ; -+ } -+ else if (pads) { -+ c = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)]; -+ (*result_)[*cntRes_] = c; -+ (*cntRes_)++; -+ } -+ else { -+ c = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)]; -+ -+ (*result_)[*cntRes_] = c; -+ (*cntRes_)++; -+ -+ c = basis_64[c3 & 0x3F]; -+ (*result_)[*cntRes_] = c; -+ (*cntRes_)++; -+ } -+} -+ -+static char index_64[128] = { -+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, -+ 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, -+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, -+ 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, -+ -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, -+ 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 -+}; -+ -+#define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) -+ -+#else // __APPLE__ -+ -+#define IS_PRINTABLE(c) (isascii(c) && isprint(c)) -+ -+- (NSString *)stringByEncodingImap4FolderName { -+ NSMutableData *aMutableData, *modifiedData; -+ NSString *aString; -+ -+ const char *b; -+ BOOL escaped; -+ unichar ch; -+ int i, len; -+ -+ // -+ // We UTF-7 encode _only_ the non-ASCII parts. -+ // -+ aMutableData = [[NSMutableData alloc] init]; -+ AUTORELEASE(aMutableData); -+ len = [self length]; -+ -+ for (i = 0; i < len; i++) -+ { -+ ch = [self characterAtIndex: i]; -+ -+ if (IS_PRINTABLE(ch)) -+ { -+ [aMutableData appendCFormat: @"%c", ch]; -+ } -+ else -+ { -+ int j; -+ -+ j = i+1; -+ // We got a non-ASCII character, let's get the substring and encode it using UTF-7. -+ while (j < len && !IS_PRINTABLE([self characterAtIndex: j])) -+ { -+ j++; -+ } -+ -+ // Get the substring. -+ [aMutableData appendData: [[self substringWithRange: NSMakeRange(i,j-i)] dataUsingEncoding: NSUTF7StringEncoding]]; -+ i = j-1; -+ } -+ } -+ -+ b = [aMutableData bytes]; -+ len = [aMutableData length]; -+ escaped = NO; -+ -+ // -+ // We replace: -+ // -+ // & -> &- -+ // + -> & -+ // +- -> + -+ // / -> , -+ // -+ // in order to produce our modified UTF-7 string. -+ // -+ modifiedData = [[NSMutableData alloc] init]; -+ AUTORELEASE(modifiedData); -+ -+ for (i = 0; i < len; i++, b++) -+ { -+ if (!escaped && *b == '&') -+ { -+ [modifiedData appendCString: "&-"]; -+ } -+ else if (!escaped && *b == '+') -+ { -+ if (*(b+1) == '-') -+ { -+ [modifiedData appendCString: "+"]; -+ } -+ else -+ { -+ [modifiedData appendCString: "&"]; -+ -+ // We enter the escaped mode. -+ escaped = YES; -+ } -+ } -+ else if (escaped && *b == '/') -+ { -+ [modifiedData appendCString: ","]; -+ } -+ else if (escaped && *b == '-') -+ { -+ [modifiedData appendCString: "-"]; -+ -+ // We leave the escaped mode. -+ escaped = NO; -+ } -+ else -+ { -+ [modifiedData appendCFormat: @"%c", *b]; -+ } -+ } -+ -+ // If we're still in the escaped mode we haven't added our trailing -, -+ // let's add it right now. -+ if (escaped) -+ { -+ [modifiedData appendCString: "-"]; -+ } -+ -+ aString = AUTORELEASE([[NSString alloc] initWithData: modifiedData encoding: NSASCIIStringEncoding]); -+ -+ return (aString != nil ? aString : self); -+} -+ -+// -+// -+// -+- (NSString *)stringByDecodingImap4FolderName { -+ NSMutableData *aMutableData; -+ -+ BOOL escaped; -+ unichar ch; -+ int i, len; -+ -+ aMutableData = [[NSMutableData alloc] init]; -+ AUTORELEASE(aMutableData); -+ -+ len = [self length]; -+ escaped = NO; -+ -+ // -+ // We replace: -+ // -+ // & -> + -+ // &- -> & -+ // , -> / -+ // -+ // If we are in escaped mode. That is, between a &....- -+ // -+ for (i = 0; i < len; i++) -+ { -+ ch = [self characterAtIndex: i]; -+ -+ if (!escaped && ch == '&') -+ { -+ if ( (i+1) < len && [self characterAtIndex: (i+1)] != '-' ) -+ { -+ [aMutableData appendCString: "+"]; -+ -+ // We enter the escaped mode. -+ escaped = YES; -+ } -+ else -+ { -+ // We replace &- by & -+ [aMutableData appendCString: "&"]; -+ i++; -+ } -+ } -+ else if (escaped && ch == ',') -+ { -+ [aMutableData appendCString: "/"]; -+ } -+ else if (escaped && ch == '-') -+ { -+ [aMutableData appendCString: "-"]; -+ -+ // We leave the escaped mode. -+ escaped = NO; -+ } -+ else -+ { -+ [aMutableData appendCFormat: @"%c", ch]; -+ } -+ } -+ -+ return AUTORELEASE([[NSString alloc] initWithData: aMutableData encoding: NSUTF7StringEncoding]); -+} -+ -+ -+#endif // __APPLE__ -+ -+- (NSString *)stringByEscapingImap4Password { -+ // TODO: perf -+ unichar *buffer; -+ unichar *chars; -+ unsigned len, i, j; -+ NSString *s; -+ -+ len = [self length]; -+ chars = calloc(len + 2, sizeof(unichar)); -+ [self getCharacters:chars]; -+ -+ buffer = calloc(len * 2 + 2, sizeof(unichar)); -+ buffer[len * 2] = '\0'; -+ -+ for (i = 0, j = 0; i < len; i++, j++) { -+ BOOL conv = NO; -+ -+ if (chars[i] <= 0x1F || chars[i] > 0x7F) { -+ conv = YES; -+ } -+ else switch (chars[i]) { -+ case '(': -+ case ')': -+ case '{': -+ case ' ': -+ case '%': -+ case '*': -+ case '"': -+ case '\\': -+ conv = YES; -+ break; -+ } -+ -+ if (conv) { -+ buffer[j] = '\\'; -+ j++; -+ } -+ buffer[j] = chars[i]; -+ } -+ if (chars != NULL) free(chars); chars = NULL; -+ -+ s = [NSString stringWithCharacters:buffer length:j]; -+ if (buffer != NULL) free(buffer); buffer = NULL; -+ return s; -+} -+ -+@end /* NSString(Imap4) */ + #endif /* __NGMime_NGImap4_NGImap4Functions_H__ */ Index: sope-mime/NGMail/NGMailAddressParser.h =================================================================== --- sope-mime/NGMail/NGMailAddressParser.h (revision 1657)