diff --git a/SOPE/sope-patchset-r1632.diff b/SOPE/sope-patchset-r1632.diff deleted file mode 100644 index 7afb9dc5b..000000000 --- a/SOPE/sope-patchset-r1632.diff +++ /dev/null @@ -1,4712 +0,0 @@ -Index: sope-ldap/NGLdap/NGLdapConnection.m -=================================================================== ---- sope-ldap/NGLdap/NGLdapConnection.m (revision 1632) -+++ sope-ldap/NGLdap/NGLdapConnection.m (working copy) -@@ -219,6 +219,29 @@ - return e; - } - -+/* encryption */ -+ -+- (BOOL)useSSL -+{ -+ BOOL rc; -+ int option; -+ -+ if (self->handle != NULL) { -+ option = LDAP_OPT_X_TLS_HARD; -+ rc = (ldap_set_option(self->handle, LDAP_OPT_X_TLS, &option) == LDAP_SUCCESS); -+ } -+ else -+ rc = NO; -+ -+ return rc; -+} -+ -+- (BOOL)startTLS -+{ -+ return (self->handle != NULL -+ && ldap_start_tls_s(self->handle, NULL, NULL) == LDAP_SUCCESS); -+} -+ - /* binding */ - - - (BOOL)isBound { -Index: sope-ldap/NGLdap/ChangeLog -=================================================================== ---- sope-ldap/NGLdap/ChangeLog (revision 1632) -+++ sope-ldap/NGLdap/ChangeLog (working copy) -@@ -1,3 +1,8 @@ -+2009-04-02 Wolfgang Sourdeau -+ -+ * NGLdapConnection.m (useSSL,startTLS): new method enabling -+ encryption on the LDAP connection. -+ - 2007-11-21 Helge Hess - - * NGLdapConnection.m: replaced some -cString calls with -UTF8String -Index: sope-ldap/NGLdap/NGLdapConnection.h -=================================================================== ---- sope-ldap/NGLdap/NGLdapConnection.h (revision 1632) -+++ sope-ldap/NGLdap/NGLdapConnection.h (working copy) -@@ -53,6 +53,10 @@ - - (NSString *)hostName; - - (int)port; - -+/* encryption */ -+- (BOOL)useSSL; -+- (BOOL)startTLS; -+ - /* binding */ - - - (BOOL)isBound; -Index: sope-mime/NGImap4/NGImap4Client.h -=================================================================== ---- sope-mime/NGImap4/NGImap4Client.h (revision 1632) -+++ sope-mime/NGImap4/NGImap4Client.h (working copy) -@@ -62,6 +62,8 @@ - NGImap4ResponseNormalizer *normer; - NSMutableArray *responseReceiver; - -+ BOOL loggedIn; -+ - BOOL isLogin; - unsigned tagId; - -@@ -120,6 +122,7 @@ - - (NSDictionary *)list:(NSString *)_folder pattern:(NSString *)_pattern; - - (NSDictionary *)lsub:(NSString *)_folder pattern:(NSString *)_pattern; - - (NSDictionary *)select:(NSString *)_folder; -+- (NSDictionary *)unselect; - - (NSDictionary *)status:(NSString *)_folder flags:(NSArray *)_flags; - - (NSDictionary *)rename:(NSString *)_folder to:(NSString *)_newName; - - (NSDictionary *)delete:(NSString *)_folder; -@@ -138,7 +141,7 @@ - flags:(NSArray *)_flags; - - (NSDictionary *)storeFrom:(unsigned)_from to:(unsigned)_to - add:(NSNumber *)_add flags:(NSArray *)_flags; --- (NSDictionary *)storeFlags:(NSArray *)_flags forMSNs:(id)_msns -+- (NSDictionary *)storeFlags:(NSArray *)_flags forUIDs:(id)_uids - addOrRemove:(BOOL)_flag; - - - (NSDictionary *)copyUid:(unsigned)_uid toFolder:(NSString *)_folder; -Index: sope-mime/NGImap4/NGImap4Client.m -=================================================================== ---- sope-mime/NGImap4/NGImap4Client.m (revision 1632) -+++ sope-mime/NGImap4/NGImap4Client.m (working copy) -@@ -24,6 +24,8 @@ - #include "NGImap4Client.h" - #include "NGImap4Context.h" - #include "NGImap4Support.h" -+#include "NGImap4Envelope.h" -+#include "NGImap4EnvelopeAddress.h" - #include "NGImap4Functions.h" - #include "NGImap4ResponseParser.h" - #include "NGImap4ResponseNormalizer.h" -@@ -53,17 +55,17 @@ - - @end /* NGImap4Client(ConnectionRegistration); */ - --#if GNUSTEP_BASE_LIBRARY --/* FIXME: TODO: move someplace better (hh: NGExtensions...) */ --@implementation NSException(setUserInfo) -+// #if GNUSTEP_BASE_LIBRARY -+// /* FIXME: TODO: move someplace better (hh: NGExtensions...) */ -+// @implementation NSException(setUserInfo) - --- (id)setUserInfo:(NSDictionary *)_userInfo { -- ASSIGN(self->_e_info, _userInfo); -- return self; --} -+// - (id)setUserInfo:(NSDictionary *)_userInfo { -+// ASSIGN(self->_e_info, _userInfo); -+// return self; -+// } - --@end /* NSException(setUserInfo) */ --#endif -+// @end /* NSException(setUserInfo) */ -+// #endif - - @interface NGImap4Client(Private) - -@@ -84,6 +86,8 @@ - - - (NSDictionary *)login; - -+- (NSDictionary *) _sopeSORT: (id)_sortSpec qualifier:(EOQualifier *)_qual encoding:(NSString *)_encoding; -+ - @end - - /* -@@ -195,11 +199,14 @@ - self->debug = ImapDebugEnabled; - self->responseReceiver = [[NSMutableArray alloc] initWithCapacity:128]; - self->normer = [[NGImap4ResponseNormalizer alloc] initWithClient:self]; -+ self->loggedIn = NO; -+ self->context = nil; - } - return self; - } - - - (void)dealloc { -+ if (self->loggedIn) [self logout]; - [self removeFromConnectionRegister]; - [self->normer release]; - [self->text release]; -@@ -457,8 +464,8 @@ - - (void)reconnect { - if ([self->context lastException] != nil) - return; -- -- [self closeConnection]; -+ -+ [self closeConnection]; - self->tagId = 0; - [self openConnection]; - -@@ -481,6 +488,7 @@ - */ - NGHashMap *map; - NSString *s, *log; -+ NSDictionary *response; - - if (self->isLogin ) - return nil; -@@ -499,7 +507,11 @@ - - self->isLogin = NO; - -- return [self->normer normalizeResponse:map]; -+ response = [self->normer normalizeResponse:map]; -+ -+ self->loggedIn = [[response valueForKey:@"result"] boolValue]; -+ -+ return response; - } - - - (NSDictionary *)logout { -@@ -508,6 +520,8 @@ - - map = [self processCommand:@"logout"]; - [self closeConnection]; -+ [self->selectedFolder release]; self->selectedFolder = nil; -+ self->loggedIn = NO; - - return [self->normer normalizeResponse:map]; - } -@@ -617,24 +631,25 @@ - 'flags' - array of strings (eg (answered,flagged,draft,seen); - 'RawResponse' - the raw IMAP4 response - */ -- NSString *s; -- id tmp; -- -- tmp = self->selectedFolder; // remember ptr to old folder name -- -+ NSString *s, *newFolder; -+ - if (![_folder isNotEmpty]) - return nil; - if ((_folder = [self _folder2ImapFolder:_folder]) == nil) - return nil; - -- self->selectedFolder = [_folder copy]; -- -- [tmp release]; tmp = nil; // release old folder name -+ newFolder = [NSString stringWithString: _folder]; -+ ASSIGN (self->selectedFolder, newFolder); - - s = [NSString stringWithFormat:@"select \"%@\"", self->selectedFolder]; - return [self->normer normalizeSelectResponse:[self processCommand:s]]; - } - -+- (NSDictionary *)unselect { -+ [self->selectedFolder release]; self->selectedFolder = nil; -+ return [self->normer normalizeResponse:[self processCommand:@"unselect"]]; -+} -+ - - (NSDictionary *)status:(NSString *)_folder flags:(NSArray *)_flags { - NSString *cmd; - -@@ -820,23 +835,23 @@ - return [self->normer normalizeResponse:[self processCommand:cmd]]; - } - --- (NSDictionary *)storeFlags:(NSArray *)_flags forMSNs:(id)_msns -+- (NSDictionary *)storeFlags:(NSArray *)_flags forUIDs:(id)_uids - addOrRemove:(BOOL)_flag - { - NSString *cmd; - NSString *flagstr; - NSString *seqstr; - -- if ([_msns isKindOfClass:[NSArray class]]) { -+ if ([_uids isKindOfClass:[NSArray class]]) { - // TODO: improve by using ranges, eg 1:5 instead of 1,2,3,4,5 -- _msns = [_msns valueForKey:@"stringValue"]; -- seqstr = [_msns componentsJoinedByString:@","]; -+ _uids = [_uids valueForKey:@"stringValue"]; -+ seqstr = [_uids componentsJoinedByString:@","]; - } - else -- seqstr = [_msns stringValue]; -+ seqstr = [_uids stringValue]; - - flagstr = [_flags2ImapFlags(self, _flags) componentsJoinedByString:@" "]; -- cmd = [NSString stringWithFormat:@"store %@ %cFLAGS (%@)", -+ cmd = [NSString stringWithFormat:@"UID STORE %@ %cFLAGS (%@)", - seqstr, _flag ? '+' : '-', flagstr]; - - return [self->normer normalizeResponse:[self processCommand:cmd]]; -@@ -967,11 +982,12 @@ - descr = @"Could not process qualifier for imap search "; - descr = [descr stringByAppendingString:reason]; - -- exception = [[NGImap4SearchException alloc] initWithFormat:@"%@", descr]; - ui = [NSDictionary dictionaryWithObject:_q forKey:@"qualifier"]; -- [exception setUserInfo:ui]; -+ exception -+ = [NGImap4SearchException exceptionWithName: @"NGImap4SearchException" -+ reason: descr -+ userInfo: ui]; - [self->context setLastException:exception]; -- [exception release]; - } - - - (NSString *)_searchExprForQual:(EOQualifier *)_qualifier { -@@ -1093,7 +1109,18 @@ - Eg: UID SORT ( DATE REVERSE SUBJECT ) UTF-8 TODO - */ - NSString *tmp; -+ NSArray *capa; - -+ // We first check to see if our server supports IMAP SORT. If not -+ // we'll sort ourself the results. -+ capa = [[self capability] objectForKey: @"capability"]; -+ -+ if ([capa indexOfObject: @"sort"] == NSNotFound) -+ { -+ return [self _sopeSORT: _sortSpec qualifier: _qual encoding: _encoding]; -+ } -+ -+ - if ([_sortSpec isKindOfClass:[NSArray class]]) - tmp = [self _generateIMAP4SortOrderings:_sortSpec]; - else if ([_sortSpec isKindOfClass:[EOSortOrdering class]]) -@@ -1107,9 +1134,10 @@ - tmp = @"DATE"; - } - -+ - return [self primarySort:tmp -- qualifierString:[self _searchExprForQual:_qual] -- encoding:_encoding]; -+ qualifierString:[self _searchExprForQual:_qual] -+ encoding:_encoding]; - } - - (NSDictionary *)sort:(NSArray *)_sortOrderings - qualifier:(EOQualifier *)_qual -@@ -1130,7 +1158,7 @@ - return nil; - } - -- s = [@"search" stringByAppendingString:s]; -+ s = [@"UID SEARCH" stringByAppendingString:s]; - return [self->normer normalizeSearchResponse:[self processCommand:s]]; - } - -@@ -1193,6 +1221,82 @@ - - /* Private Methods */ - -+- (NSDictionary *) _sopeSORT: (id)_sortSpec qualifier:(EOQualifier *)_qual encoding:(NSString *)_encoding { -+ NSMutableDictionary *result; -+ NSDictionary *d; -+ NSCalendarDate *envDate; -+ -+ result = [[[NSMutableDictionary alloc] init] autorelease]; -+ [result setObject: [NSNumber numberWithBool: NO] forKey: @"result"]; -+ -+ // _sortSpec: [REVERSE] {DATE,FROM,SUBJECT} -+ d = [self searchWithQualifier: _qual]; -+ -+ if ((d = [d objectForKey: @"RawResponse"])) -+ { -+ NSMutableDictionary *dict; -+ NSArray *a, *s_a; -+ BOOL b; -+ int i; -+ -+ a = [d objectForKey: @"search"]; -+ d = [self fetchUids: a parts: [NSArray arrayWithObject: @"ENVELOPE"]]; -+ a = [d objectForKey: @"fetch"]; -+ -+ -+ dict = [[[NSMutableDictionary alloc] init] autorelease]; -+ b = YES; -+ -+ for (i = 0; i < [a count]; i++) -+ { -+ NGImap4Envelope *env; -+ id o, uid, s; -+ -+ o = [a objectAtIndex: i]; -+ env = [o objectForKey: @"envelope"]; -+ uid = [o objectForKey: @"uid"]; -+ -+ if ([_sortSpec rangeOfString: @"SUBJECT"].length) -+ { -+ s = [env subject]; -+ if ([s isKindOfClass: [NSData class]]) -+ s = [[[NSString alloc] initWithData: s encoding: NSUTF8StringEncoding] autorelease]; -+ -+ [dict setObject: (s != nil ? s : (id)@"") forKey: uid]; -+ } -+ else if ([_sortSpec rangeOfString: @"FROM"].length) -+ { -+ s = [[[env from] lastObject] email]; -+ [dict setObject: (s != nil ? s : (id)@"") forKey: uid]; -+ } -+ else -+ { -+ envDate = [env date]; -+ if (!envDate) -+ envDate = [NSCalendarDate date]; -+ [dict setObject: envDate forKey: uid]; -+ b = NO; -+ } -+ } -+ -+ if (b) -+ s_a = [dict keysSortedByValueUsingSelector: @selector(caseInsensitiveCompare:)]; -+ else -+ s_a = [dict keysSortedByValueUsingSelector: @selector(compare:)]; -+ -+ if ([_sortSpec rangeOfString: @"REVERSE"].length) -+ { -+ s_a = [[s_a reverseObjectEnumerator] allObjects]; -+ } -+ -+ [result setObject: [NSNumber numberWithBool: YES] forKey: @"result"]; -+ [result setObject: s_a forKey: @"sort"]; -+ } -+ -+ return result; -+} -+ -+ - - (NSException *)_processCommandParserException:(NSException *)_exception { - [self logWithFormat:@"ERROR(%s): catched IMAP4 parser exception %@: %@", - __PRETTY_FUNCTION__, [_exception name], [_exception reason]]; -Index: sope-mime/NGImap4/NGSieveClient.m -=================================================================== ---- sope-mime/NGImap4/NGSieveClient.m (revision 1632) -+++ sope-mime/NGImap4/NGSieveClient.m (working copy) -@@ -294,8 +294,8 @@ - return con; - } - -- logLen = [self->login cStringLength]; -- bufLen = (logLen * 2) + [self->password cStringLength] +2; -+ logLen = [self->login lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; -+ bufLen = (logLen * 2) + [self->password lengthOfBytesUsingEncoding: NSUTF8StringEncoding] +2; - - buf = calloc(bufLen + 2, sizeof(char)); - -@@ -306,8 +306,9 @@ - password - */ - sprintf(buf, "%s %s %s", -- [self->login cString], [self->login cString], -- [self->password cString]); -+ [self->login cStringUsingEncoding:NSUTF8StringEncoding], -+ [self->login cStringUsingEncoding:NSUTF8StringEncoding], -+ [self->password cStringUsingEncoding:NSUTF8StringEncoding]); - - buf[logLen] = '\0'; - buf[logLen * 2 + 1] = '\0'; -@@ -656,7 +657,7 @@ - fputc('\n', stderr); - } - else -- fprintf(stderr, "C: %s\n", [_txt cString]); -+ fprintf(stderr, "C: %s\n", [_txt cStringUsingEncoding:NSUTF8StringEncoding]); - } - - /* write */ -Index: sope-mime/NGImap4/NGImap4Connection.h -=================================================================== ---- sope-mime/NGImap4/NGImap4Connection.h (revision 1632) -+++ sope-mime/NGImap4/NGImap4Connection.h (working copy) -@@ -89,6 +89,7 @@ - - - (NSArray *)subfoldersForURL:(NSURL *)_url; - - (NSArray *)allFoldersForURL:(NSURL *)_url; -+- (BOOL)selectFolder:(id)_url; - - /* message operations */ - -Index: sope-mime/NGImap4/NGImap4Connection.m -=================================================================== ---- sope-mime/NGImap4/NGImap4Connection.m (revision 1632) -+++ sope-mime/NGImap4/NGImap4Connection.m (working copy) -@@ -373,7 +373,14 @@ - - /* 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 @@ - - if (debugCache) [self logWithFormat:@" no folders cached yet .."]; - -- result = [[self client] list:(onlyFetchInbox ? @"INBOX" : @"*") -- pattern:@"*"]; -+ if (subscribedFoldersOnly) -+ result = [[self client] lsub:(onlyFetchInbox ? @"INBOX" : @"") -+ pattern:@"*"]; -+ else -+ result = [[self client] list:(onlyFetchInbox ? @"INBOX" : @"") -+ pattern:@"*"]; - if (![[result valueForKey:@"result"] boolValue]) { - [self errorWithFormat:@"Could not list mailbox hierarchy!"]; - return nil; -@@ -413,10 +424,18 @@ - 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; - -- if ((result = [self primaryFetchMailboxHierarchyForURL:_url]) == nil) -+ if ((result = [self primaryFetchMailboxHierarchyForURL:_url -+ onlySubscribedFolders: subscribedFoldersOnly]) == nil) - return nil; - if ([result isKindOfClass:[NSException class]]) { - [self errorWithFormat:@"failed to retrieve hierarchy: %@", result]; -@@ -646,7 +665,7 @@ - - /* store flags */ - -- result = [[self client] storeFlags:_f forMSNs:result addOrRemove:YES]; -+ result = [[self client] storeFlags:_f forUIDs:result addOrRemove:YES]; - 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 @@ - // TODO: we should probably just fetch the whole hierarchy? - - folderName = [self imap4FolderNameForURL:_url]; -- result = [[self client] select:folderName]; -- if (![[result valueForKey:@"result"] boolValue]) -- return NO; -- -- return YES; -+ -+ result = [self->client status: folderName -+ flags: [NSArray arrayWithObject: @"UIDVALIDITY"]]; -+ -+ return ([[result valueForKey: @"result"] boolValue]); - } - - - (id)infoForMailboxAtURL:(NSURL *)_url { -Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.m -=================================================================== ---- sope-mime/NGImap4/NGImap4ResponseNormalizer.m (revision 1632) -+++ sope-mime/NGImap4/NGImap4ResponseNormalizer.m (working copy) -@@ -292,7 +292,7 @@ - /* - filter for fetch response - fetch : NSArray (fetch responses) -- 'header' - RFC822.HEADER -+ 'header' - RFC822.HEADER and BODY[HEADER.FIELDS (...)] - 'text' - RFC822.TEXT - 'size' - SIZE - 'flags' - FLAGS -@@ -336,7 +336,12 @@ - switch (c) { - case 'b': - /* Note: we check for _prefix_! eg body[1] is valid too */ -- if (klen > 3 && [key hasPrefix:@"body"]) { -+ if (klen > 17 && [key hasPrefix:@"body[header.fields"]) { -+ keys[count] = @"header"; -+ values[count] = objForKey(obj, @selector(objectForKey:), key); -+ count++; -+ } -+ else if (klen > 3 && [key hasPrefix:@"body"]) { - keys[count] = @"body"; - values[count] = objForKey(obj, @selector(objectForKey:), key); - count++; -@@ -648,14 +653,13 @@ - enumerator = [_flags objectEnumerator]; - cnt = 0; - while ((obj = [enumerator nextObject])) { -- if (![obj isNotEmpty]) -- continue; -- -- if (![[obj substringToIndex:1] isEqualToString:@"\\"]) -- continue; -- -- objs[cnt] = [obj substringFromIndex:1]; -- cnt++; -+ if ([obj isNotEmpty]) { -+ if ([obj hasPrefix:@"\\"]) -+ objs[cnt] = [obj substringFromIndex:1]; -+ else -+ objs[cnt] = obj; -+ cnt++; -+ } - } - result = [NSArray arrayWithObjects:objs count:cnt]; - if (objs) free(objs); -Index: sope-mime/NGImap4/NGImap4ResponseParser.m -=================================================================== ---- sope-mime/NGImap4/NGImap4ResponseParser.m (revision 1632) -+++ sope-mime/NGImap4/NGImap4ResponseParser.m (working copy) -@@ -31,6 +31,7 @@ - @interface NGImap4ResponseParser(ParsingPrivates) - - (BOOL)_parseNumberUntaggedResponse:(NGMutableHashMap *)result_; - - (NSDictionary *)_parseBodyContent; -+- (NSData *) _parseBodyHeaderFields; - - - (NSData *)_parseData; - -@@ -84,6 +85,8 @@ - static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self, - BOOL isBodyStructure); - -+static NSArray *_parseLanguages(); -+ - static NSString *_parseBodyString(NGImap4ResponseParser *self, - BOOL _convertString); - static NSString *_parseBodyDecodeString(NGImap4ResponseParser *self, -@@ -111,6 +114,7 @@ - static NSNumber *_parseUnsigned(NGImap4ResponseParser *self); - static NSString *_parseUntil(NGImap4ResponseParser *self, char _c); - static NSString *_parseUntil2(NGImap4ResponseParser *self, char _c1, char _c2); -+static BOOL _endsWithCQuote(NSString *_string); - - static __inline__ NSException *_consumeIfMatch - (NGImap4ResponseParser *self, unsigned char _m); -@@ -488,6 +492,50 @@ - return [self _parseDataIntoRAM:size]; - } - -+/* -+ Similair to _parseData but used to parse something like this : -+ -+ BODY[HEADER.FIELDS (X-PRIORITY)] {17} -+ X-Priority: 1 -+ -+ ) -+ -+ Headers are returned as data, as is. -+*/ -+- (NSData *) _parseBodyHeaderFields -+{ -+ NSData *result; -+ unsigned size; -+ NSNumber *sizeNum; -+ -+ /* we skip until we're ready to parse {length} */ -+ _parseUntil(self, '{'); -+ -+ result = nil; -+ -+ if ((sizeNum = _parseUnsigned(self)) == nil) { -+ NSException *e; -+ -+ e = [[NGImap4ParserException alloc] -+ initWithFormat:@"expect a number between {}"]; -+ [self setLastException:[e autorelease]]; -+ return nil; -+ } -+ _consumeIfMatch(self, '}'); -+ _consumeIfMatch(self, '\n'); -+ -+ if ((size = [sizeNum intValue]) == 0) { -+ [self logWithFormat:@"ERROR(%s): got content size '0'!", -+ __PRETTY_FUNCTION__]; -+ return nil; -+ } -+ -+ if (UseMemoryMappedData && (size > Imap4MMDataBoundary)) -+ return [self _parseDataToFile:size]; -+ -+ return [self _parseDataIntoRAM:size]; -+} -+ - static int _parseTaggedResponse(NGImap4ResponseParser *self, - NGMutableHashMap *result_) - { -@@ -648,13 +696,124 @@ - [result_ addObject:_parseUntil(self, '\n') forKey:@"description"]; - } - -+static inline void -+_purifyQuotedString(NSMutableString *quotedString) { -+ unichar *currentChar, *qString, *maxC, *startC; -+ unsigned int max, questionMarks; -+ BOOL possiblyQuoted, skipSpaces; -+ NSMutableString *newString; -+ -+ newString = [NSMutableString string]; -+ -+ max = [quotedString length]; -+ qString = malloc (sizeof (unichar) * max); -+ [quotedString getCharacters: qString]; -+ currentChar = qString; -+ startC = qString; -+ maxC = qString + max; -+ -+ possiblyQuoted = NO; -+ skipSpaces = NO; -+ -+ questionMarks = 0; -+ -+ while (currentChar < maxC) { -+ if (possiblyQuoted) { -+ if (questionMarks == 2) { -+ if ((*currentChar == 'Q' || *currentChar == 'q' -+ || *currentChar == 'B' || *currentChar == 'b') -+ && ((currentChar + 1) < maxC -+ && (*(currentChar + 1) == '?'))) { -+ currentChar++; -+ questionMarks = 3; -+ } -+ else { -+ possiblyQuoted = NO; -+ } -+ } -+ else if (questionMarks == 4) { -+ if (*currentChar == '=') { -+ skipSpaces = YES; -+ possiblyQuoted = NO; -+ currentChar++; -+ [newString appendString: [NSString stringWithCharacters: startC -+ length: (currentChar - startC)]]; -+ startC = currentChar; -+ } -+ else { -+ possiblyQuoted = NO; -+ } -+ } -+ else { -+ if (*currentChar == '?') { -+ questionMarks++; -+ } -+ else if (*currentChar == ' ' && questionMarks != 3) { -+ possiblyQuoted = NO; -+ } -+ } -+ } -+ else if (*currentChar == '=' -+ && ((currentChar + 1) < maxC -+ && (*(currentChar + 1) == '?'))) { -+ [newString appendString: [NSString stringWithCharacters: startC -+ length: (currentChar - startC)]]; -+ startC = currentChar; -+ possiblyQuoted = YES; -+ skipSpaces = NO; -+ currentChar++; -+ questionMarks = 1; -+ } -+ -+ currentChar++; -+ -+ if (skipSpaces) { -+ while (currentChar < maxC -+ && (*currentChar == ' ' -+ || *currentChar == '\t')) -+ currentChar++; -+ skipSpaces = NO; -+ startC = currentChar; -+ } -+ } -+ -+ if (startC < maxC) -+ [newString appendString: [NSString stringWithCharacters: startC -+ length: (currentChar - startC)]]; -+ -+ [quotedString setString: newString]; -+ free (qString); -+} -+ - - (NSString *)_parseQuotedString { -+ NSMutableString *quotedString; -+ NSString *tmpString; -+ BOOL stop; -+ - /* parse a quoted string, eg '"' */ - if (_la(self, 0) == '"') { - _consume(self, 1); -- return _parseUntil(self, '"'); -+ quotedString = [NSMutableString string]; -+ stop = NO; -+ while (!stop) { -+ tmpString = _parseUntil(self, '"'); -+ [quotedString appendString: tmpString]; -+ if(_endsWithCQuote(tmpString)) { -+ [quotedString deleteSuffix: @"\\"]; -+ [quotedString appendString: @"\""]; -+ } -+ else { -+ stop = YES; -+ } -+ } - } -- return nil; -+ else { -+ quotedString = nil; -+ } -+ -+ _purifyQuotedString(quotedString); -+ -+ return quotedString; - } - - (void)_consumeOptionalSpace { - if (_la(self, 0) == ' ') _consume(self, 1); -@@ -1090,6 +1249,8 @@ - return @""; - - s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; -+ if (s == nil) -+ s = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding]; - if (s == nil) { - [self logWithFormat: - @"ERROR(%s): could not convert data (%d bytes) into string.", -@@ -1185,7 +1346,7 @@ - route = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace]; - mailbox = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace]; - host = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace]; -- -+ - if (_la(self, 0) != ')') { - [self logWithFormat:@"WARNING: IMAP4 envelope " - @"address not properly closed (c0=%c,c1=%c): %@", -@@ -1197,6 +1358,7 @@ - address = [[NGImap4EnvelopeAddress alloc] initWithPersonalName:pname - sourceRoute:route mailbox:mailbox - host:host]; -+ - return address; - } - -@@ -1382,7 +1544,15 @@ - #if 0 - [self logWithFormat:@"PARSE KEY: %@", key]; - #endif -- if ([key hasPrefix:@"body["]) { -+ if ([key hasPrefix:@"body[header.fields"]) { -+ NSData *content; -+ -+ if ((content = [self _parseBodyHeaderFields]) != nil) -+ [fetch setObject:content forKey:key]; -+ else -+ [self logWithFormat:@"ERROR: got no body content for key: '%@'",key]; -+ } -+ else if ([key hasPrefix:@"body["]) { - NSDictionary *content; - - if ((content = [self _parseBodyContent]) != nil) -@@ -1594,8 +1764,11 @@ - if (_decode) - data = [data decodeQuotedPrintableValueOfMIMEHeaderField:nil]; - -- return [[[StrClass alloc] initWithData:data encoding:encoding] -- autorelease]; -+ if ([data isKindOfClass: [NSString class]]) -+ return (NSString *) data; -+ else -+ return [[[StrClass alloc] initWithData:data encoding:encoding] -+ autorelease]; - } - else { - str = _parseUntil2(self, ' ', ')'); -@@ -1620,13 +1793,35 @@ - return str; - } - -- - static NSString *_parseBodyString(NGImap4ResponseParser *self, - BOOL _convertString) - { - return _parseBodyDecodeString(self, _convertString, NO /* no decode */); - } - -+static NSArray *_parseLanguages(NGImap4ResponseParser *self) { -+ NSMutableArray *languages; -+ NSString *language; -+ -+ languages = [NSMutableArray array]; -+ if (_la(self, 0) == '(') { -+ while (_la(self, 0) != ')') { -+ _consume(self,1); -+ language = _parseBodyString(self, YES); -+ if ([language length]) -+ [languages addObject: language]; -+ } -+ _consume(self,1); -+ } -+ else { -+ language = _parseBodyString(self, YES); -+ if ([language length]) -+ [languages addObject: language]; -+ } -+ -+ return languages; -+} -+ - static NSDictionary *_parseBodyParameterList(NGImap4ResponseParser *self) - { - NSMutableDictionary *list; -@@ -1646,7 +1841,7 @@ - _consumeIfMatch(self, ' '); - value = _parseBodyDecodeString(self, YES, YES); - -- [list setObject:value forKey:[key lowercaseString]]; -+ if (value) [list setObject:value forKey:[key lowercaseString]]; - } - _consumeIfMatch(self, ')'); - } -@@ -1731,13 +1926,14 @@ - static NSDictionary *_parseSingleBody(NGImap4ResponseParser *self, - BOOL isBodyStructure) { - NSString *type, *subtype, *bodyId, *description, -- *encoding, *bodysize; -+ *result, *encoding, *bodysize; - NSDictionary *parameterList; - NSMutableDictionary *dict; -+ NSArray *languages; - - type = [_parseBodyString(self, YES) lowercaseString]; - _consumeIfMatch(self, ' '); -- subtype = _parseBodyString(self, YES); -+ subtype = [_parseBodyString(self, YES) lowercaseString]; - _consumeIfMatch(self, ' '); - parameterList = _parseBodyParameterList(self); - _consumeIfMatch(self, ' '); -@@ -1762,13 +1958,18 @@ - _consumeIfMatch(self, ' '); - [dict setObject:_parseBodyString(self, YES) forKey:@"lines"]; - } -- else if ([type isEqualToString:@"message"]) { -+ else if ([type isEqualToString:@"message"] -+ && [subtype isEqualToString:@"rfc822"]) { - if (_la(self, 0) != ')') { - _consumeIfMatch(self, ' '); - _consumeIfMatch(self, '('); -- [dict setObject:_parseBodyString(self, YES) forKey:@"date"]; -+ result = _parseBodyString(self, YES); -+ if (result == nil) result = @""; -+ [dict setObject:result forKey:@"date"]; - _consumeIfMatch(self, ' '); -- [dict setObject:_parseBodyString(self, YES) forKey:@"subject"]; -+ result = _parseBodyString(self, YES); -+ if (result == nil) result = @""; -+ [dict setObject:result forKey:@"subject"]; - _consumeIfMatch(self, ' '); - [dict setObject:_parseParenthesizedAddressList(self) forKey:@"from"]; - _consumeIfMatch(self, ' '); -@@ -1783,14 +1984,20 @@ - _consumeIfMatch(self, ' '); - [dict setObject:_parseParenthesizedAddressList(self) forKey:@"bcc"]; - _consumeIfMatch(self, ' '); -- [dict setObject:_parseBodyString(self, YES) forKey:@"in-reply-to"]; -+ result = _parseBodyString(self, YES); -+ if (result == nil) result = @""; -+ [dict setObject:result forKey:@"in-reply-to"]; - _consumeIfMatch(self, ' '); -- [dict setObject:_parseBodyString(self, YES) forKey:@"messageId"]; -+ result = _parseBodyString(self, YES); -+ if (result == nil) result = @""; -+ [dict setObject:result forKey:@"messageId"]; - _consumeIfMatch(self, ')'); - _consumeIfMatch(self, ' '); - [dict setObject:_parseBody(self, isBodyStructure) forKey:@"body"]; - _consumeIfMatch(self, ' '); -- [dict setObject:_parseBodyString(self, YES) forKey:@"bodyLines"]; -+ result = _parseBodyString(self, YES); -+ if (result == nil) result = @""; -+ [dict setObject:result forKey:@"bodyLines"]; - } - } - -@@ -1805,14 +2012,9 @@ - forKey: @"disposition"]; - if (_la(self, 0) != ')') { - _consume(self,1); -- if (_la(self, 0) == '(') { -- [dict setObject: _parseBodyParameterList(self) -- forKey: @"language"]; -- } -- else { -- [dict setObject: _parseBodyString(self, YES) -- forKey: @"language"]; -- } -+ languages = _parseLanguages(self); -+ if ([languages count]) -+ [dict setObject: languages forKey: @"languages"]; - if (_la(self, 0) != ')') { - _consume(self,1); - [dict setObject: _parseBodyString(self, YES) -@@ -1829,6 +2031,7 @@ - static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self, - BOOL isBodyStructure) { - NSMutableArray *parts; -+ NSArray *languages; - NSString *kind; - NSMutableDictionary *dict; - -@@ -1854,14 +2057,9 @@ - forKey: @"disposition"]; - if (_la(self, 0) != ')') { - _consume(self,1); -- if (_la(self, 0) == '(') { -- [dict setObject: _parseBodyParameterList(self) -- forKey: @"language"]; -- } -- else { -- [dict setObject: _parseBodyString(self, YES) -- forKey: @"language"]; -- } -+ languages = _parseLanguages(self); -+ if ([languages count]) -+ [dict setObject: languages forKey: @"languages"]; - if (_la(self, 0) != ')') { - _consume(self,1); - [dict setObject: _parseBodyString(self, YES) -@@ -2170,6 +2368,21 @@ - } - } - -+static BOOL _endsWithCQuote(NSString *_string){ -+ unsigned int quoteSlashes; -+ int pos; -+ -+ quoteSlashes = 0; -+ pos = [_string length] - 1; -+ while (pos > -1 -+ && [_string characterAtIndex: pos] == '\\') { -+ quoteSlashes++; -+ pos--; -+ } -+ -+ return ((quoteSlashes % 2) == 1); -+} -+ - - (NSException *)exceptionForFailedMatch:(unsigned char)_match - got:(unsigned char)_avail - { -@@ -2225,9 +2438,9 @@ - [s release]; - - if (c == '\n') { -- if ([self->serverResponseDebug cStringLength] > 2) { -+ if ([self->serverResponseDebug lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding] > 2) { - fprintf(stderr, "S[%p]: %s", self, -- [self->serverResponseDebug cString]); -+ [self->serverResponseDebug cStringUsingEncoding:NSISOLatin1StringEncoding]); - } - [self->serverResponseDebug release]; - self->serverResponseDebug = -Index: sope-mime/NGImap4/ChangeLog -=================================================================== ---- sope-mime/NGImap4/ChangeLog (revision 1632) -+++ sope-mime/NGImap4/ChangeLog (working copy) -@@ -1,3 +1,29 @@ -+2008-10-23 Wolfgang Sourdeau -+ -+ * NGImap4Client.m ([NGImap -sort:qualifier:encoding:]): message -+ without date that are sorted on servers which do not have the SORT -+ capability are now given the current date as a work-around. -+ -+2008-09-22 Wolfgang Sourdeau -+ -+ * NGImap4Connection.m ([NGImap -doesMailboxExistAtURL:]): restore -+ the previously selected folder state. -+ -+2008-09-19 Wolfgang Sourdeau -+ -+ * NGImap4Client.m ([NGImap -select:]): simplified method by -+ removing the need for storing the previous folder before releasing -+ it. This strangely seems to fix a crash with gnustep 1.14. -+ -+2008-09-01 Ludovic Marcotte -+ -+ * NGImap4ConnectionManager.m: implemented _garbageCollect. -+ -+2008-08-28 Wolfgang Sourdeau -+ -+ * NGImap4Client.m ([NGImap -unselect]): new method to send -+ "UNSELECT" to the imap server. -+ - 2007-08-24 Wolfgang Sourdeau - - * NGImap4Connection.m: some fix for folders ending with a slash (OGo -Index: sope-mime/NGImap4/NGImap4ConnectionManager.m -=================================================================== ---- sope-mime/NGImap4/NGImap4ConnectionManager.m (revision 1632) -+++ sope-mime/NGImap4/NGImap4ConnectionManager.m (working copy) -@@ -38,6 +38,9 @@ - debugCache = [ud boolForKey:@"NGImap4EnableIMAP4CacheDebug"]; - poolingOff = [ud boolForKey:@"NGImap4DisableIMAP4Pooling"]; - -+ if ([ud objectForKey:@"NGImap4PoolingCleanupInterval"]) -+ PoolScanInterval = [[ud objectForKey:@"NGImap4PoolingCleanupInterval"] doubleValue]; -+ - if (debugOn) NSLog(@"Note: NGImap4EnableIMAP4Debug is enabled!"); - if (poolingOff) NSLog(@"WARNING: IMAP4 connection pooling is disabled!"); - } -@@ -53,18 +56,17 @@ - if ((self = [super init])) { - if (!poolingOff) { - self->urlToEntry = [[NSMutableDictionary alloc] initWithCapacity:256]; -+ self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval: -+ PoolScanInterval -+ target:self selector:@selector(_garbageCollect:) -+ userInfo:nil repeats:YES] retain]; - } -- -- self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval: -- PoolScanInterval -- target:self selector:@selector(_garbageCollect:) -- userInfo:nil repeats:YES] retain]; - } - return self; - } - - - (void)dealloc { -- if (self->gcTimer) [self->gcTimer invalidate]; -+ [self->gcTimer invalidate]; - [self->urlToEntry release]; - [self->gcTimer release]; - [super dealloc]; -@@ -91,6 +93,25 @@ - - - (void)_garbageCollect:(NSTimer *)_timer { - // TODO: scan for old IMAP4 channels -+ NGImap4Connection *entry; -+ NSDate *now; -+ NSArray *a; -+ int i; -+ -+ a = [self->urlToEntry allKeys]; -+ now = [NSDate date]; -+ -+ for (i = 0; i < [a count]; i++) -+ { -+ entry = [self->urlToEntry objectForKey: [a objectAtIndex: i]]; -+ -+ if ([now timeIntervalSinceDate: [entry creationTime]] > PoolScanInterval) -+ { -+ [[entry client] logout]; -+ [self->urlToEntry removeObjectForKey: [a objectAtIndex: i]]; -+ } -+ } -+ - [self debugWithFormat:@"should collect IMAP4 channels (%d active)", - [self->urlToEntry count]]; - } -@@ -105,34 +126,42 @@ - NGImap4Connection *entry; - NGImap4Client *client; - -+ if (poolingOff) { -+ client = [self imap4ClientForURL:_url password:_p]; -+ entry = [[NGImap4Connection alloc] initWithClient:client -+ password:_p]; -+ return [entry autorelease]; -+ } -+ else { - /* check cache */ - -- if ((entry = [self entryForURL:_url]) != nil) { -- if ([entry isValidPassword:_p]) { -+ if ((entry = [self entryForURL:_url]) != nil) { -+ if ([entry isValidPassword:_p]) { -+ if (debugCache) -+ [self logWithFormat:@"valid password, reusing cache entry ..."]; -+ return entry; -+ } -+ -+ /* different password, password could have changed! */ - if (debugCache) -- [self logWithFormat:@"valid password, reusing cache entry ..."]; -- return entry; -+ [self logWithFormat:@"different password than cached entry: %@", _url]; -+ entry = nil; - } -- -- /* different password, password could have changed! */ -- if (debugCache) -- [self logWithFormat:@"different password than cached entry: %@", _url]; -- entry = nil; -- } -- else -- [self debugWithFormat:@"no connection cached yet for url: %@", _url]; -+ else -+ [self debugWithFormat:@"no connection cached yet for url: %@", _url]; - -- /* try to login */ -+ /* try to login */ - -- client = [entry isValidPassword:_p] -- ? [entry client] -- : [self imap4ClientForURL:_url password:_p]; -+ client = [entry isValidPassword:_p] -+ ? [entry client] -+ : [self imap4ClientForURL:_url password:_p]; -+ -+ if (client == nil) -+ return nil; - -- if (client == nil) -- return nil; -- - /* sideeffect of -imap4ClientForURL:password: is to create a cache entry */ -- return [self entryForURL:_url]; -+ return [self entryForURL:_url]; -+ } - } - - /* client object */ -Index: sope-mime/NGImap4/NSString+Imap4.m -=================================================================== ---- sope-mime/NGImap4/NSString+Imap4.m (revision 1632) -+++ sope-mime/NGImap4/NSString+Imap4.m (working copy) -@@ -20,11 +20,56 @@ - 02111-1307, USA. - */ - -+#import -+ - #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) -- - - (NSString *)stringByEncodingImap4FolderName { - // TBD: this is restricted to Latin1, should be fixed to UTF-8 - /* dude.d& --> dude.d&- */ -@@ -46,12 +89,15 @@ - NSString *result = nil; - NSData *data; - -- len = [self cStringLength]; -- buf = calloc(len + 3, sizeof(char)); -- res = calloc((len * 6) + 3, sizeof(char)); -- 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; -+ buf[len] = 0; -+ buf[len+1] = 0; -+ buf[len+2] = 0; - - while (cnt < len) { - int c = buf[cnt]; -@@ -185,70 +231,6 @@ - return [result autorelease]; - } - --- (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) */ -- --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; --} - static void _encodeToModifiedUTF7(unsigned char *_buf, int encLen, - unsigned char **result_, unsigned int *cntRes_) - { -@@ -276,58 +258,6 @@ - } - } - --/* 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)]) -- - static int _decodeOfModifiedUTF7(unsigned char *_target, unsigned _targetLen, - unsigned *usedBytes_ , unsigned char **buffer_, - int *bufLen_, int maxBuf) -@@ -430,3 +360,299 @@ - } - return 0; - } -+ -+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) */ -Index: sope-mime/NGMail/NGSmtpClient.m -=================================================================== ---- sope-mime/NGMail/NGSmtpClient.m (revision 1632) -+++ sope-mime/NGMail/NGSmtpClient.m (working copy) -@@ -24,6 +24,82 @@ - #include "NGSmtpReplyCodes.h" - #include "common.h" - -+// -+// Useful extension that comes from Pantomime which is also -+// released under the LGPL. -+// -+@interface NSMutableData (DataCleanupExtension) -+ -+- (NSRange) rangeOfCString: (const char *) theCString; -+- (NSRange) rangeOfCString: (const char *) theCString -+ options: (unsigned int) theOptions -+ range: (NSRange) theRange; -+@end -+ -+@implementation NSMutableData (DataCleanupExtension) -+ -+- (NSRange) rangeOfCString: (const char *) theCString -+{ -+ return [self rangeOfCString: theCString -+ options: 0 -+ range: NSMakeRange(0,[self length])]; -+} -+ -+-(NSRange) rangeOfCString: (const char *) theCString -+ options: (unsigned int) theOptions -+ range: (NSRange) theRange -+{ -+ const char *b, *bytes; -+ int i, len, slen; -+ -+ if (!theCString) -+ { -+ return NSMakeRange(NSNotFound,0); -+ } -+ -+ bytes = [self bytes]; -+ len = [self length]; -+ slen = strlen(theCString); -+ -+ b = bytes; -+ -+ if (len > theRange.location + theRange.length) -+ { -+ len = theRange.location + theRange.length; -+ } -+ -+ if (theOptions == NSCaseInsensitiveSearch) -+ { -+ i = theRange.location; -+ b += i; -+ -+ for (; i <= len-slen; i++, b++) -+ { -+ if (!strncasecmp(theCString,b,slen)) -+ { -+ return NSMakeRange(i,slen); -+ } -+ } -+ } -+ else -+ { -+ i = theRange.location; -+ b += i; -+ -+ for (; i <= len-slen; i++, b++) -+ { -+ if (!memcmp(theCString,b,slen)) -+ { -+ return NSMakeRange(i,slen); -+ } -+ } -+ } -+ -+ return NSMakeRange(NSNotFound,0); -+} -+ -+@end -+ - @interface NGSmtpClient(PrivateMethods) - - (void)_fetchExtensionInfo; - @end -@@ -429,7 +505,9 @@ - - - (BOOL)sendData:(NSData *)_data { - NGSmtpResponse *reply = nil; -- -+ NSMutableData *cleaned_data; -+ NSRange r1, r2; -+ - [self requireState:NGSmtpState_TRANSACTION]; - - reply = [self sendCommand:@"DATA"]; -@@ -441,11 +519,54 @@ - } - [self->text flush]; - -+ cleaned_data = [NSMutableData dataWithData: _data]; -+ -+ // -+ // According to RFC 2821 section 4.5.2, we must check for the character -+ // sequence "."; any occurrence have its period duplicated -+ // to avoid data transparency. -+ // -+ // The following code was copied from Pantomime (and also the one -+ // that strips Bcc: headers from the mail's content) -+ // -+ r1 = [cleaned_data rangeOfCString: "\r\n."]; -+ -+ while (r1.location != NSNotFound) -+ { -+ [cleaned_data replaceBytesInRange: r1 withBytes: "\r\n.." length: 4]; -+ -+ r1 = [cleaned_data rangeOfCString: "\r\n." -+ options: 0 -+ range: NSMakeRange(NSMaxRange(r1)+1, [cleaned_data length]-NSMaxRange(r1)-1)]; -+ } -+ -+ // -+ // We now look for the Bcc: header. If it is present, we remove it. -+ // Some servers, like qmail, do not remove it automatically. -+ // -+ r1 = [cleaned_data rangeOfCString: "\r\n\r\n"]; -+ r1 = [cleaned_data rangeOfCString: "\r\nBcc: " -+ options: 0 -+ range: NSMakeRange(0,r1.location-1)]; -+ -+ if (r1.location != NSNotFound) -+ { -+ // We search for the first \r\n AFTER the Bcc: header and -+ // replace the whole thing with \r\n. -+ r2 = [cleaned_data rangeOfCString: "\r\n" -+ options: 0 -+ range: NSMakeRange(NSMaxRange(r1)+1,[cleaned_data length]-NSMaxRange(r1)-1)]; -+ [cleaned_data replaceBytesInRange: NSMakeRange(r1.location, NSMaxRange(r2)-r1.location) -+ withBytes: "\r\n" -+ length: 2]; -+ } -+ -+ - if (self->isDebuggingEnabled) -- [NGTextErr writeFormat:@"C: data(%i bytes) ..\n", [_data bytes]]; -+ [NGTextErr writeFormat:@"C: data(%i bytes) ..\n", [cleaned_data length]]; - -- [self->connection safeWriteBytes:[_data bytes] count:[_data length]]; -- [self->connection safeWriteBytes:".\r\n" count:3]; -+ [self->connection safeWriteBytes:[cleaned_data bytes] count:[cleaned_data length]]; -+ [self->connection safeWriteBytes:"\r\n.\r\n" count:5]; - [self->connection flush]; - - reply = [self receiveReply]; -Index: sope-mime/NGMail/NGMailAddressParser.h -=================================================================== ---- sope-mime/NGMail/NGMailAddressParser.h (revision 1632) -+++ sope-mime/NGMail/NGMailAddressParser.h (working copy) -@@ -24,7 +24,9 @@ - - #import - --@class NSData, NSString, NSArray; -+#import -+ -+@class NSData, NSArray; - @class NGMailAddressList; - - /* -@@ -34,16 +36,16 @@ - @interface NGMailAddressParser : NSObject - { - @private -- unsigned char *data; -- int dataPos; -- int errorPos; -- int maxLength; -+ unichar *data; -+ int dataPos; -+ int errorPos; -+ int maxLength; - } - - + (id)mailAddressParserWithString:(NSString *)_string; - + (id)mailAddressParserWithData:(NSData *)_data; --+ (id)mailAddressParserWithCString:(char *)_cString; --- (id)initWithCString:(const unsigned char *)_cstr length:(int unsigned)_len; -++ (id)mailAddressParserWithCString:(const char *)_cString; -+- (id)initWithString:(NSString *)_str; - - /* parsing */ - -Index: sope-mime/NGMail/NGMimeMessageGenerator.m -=================================================================== ---- sope-mime/NGMail/NGMimeMessageGenerator.m (revision 1632) -+++ sope-mime/NGMail/NGMimeMessageGenerator.m (working copy) -@@ -86,37 +86,40 @@ - char *des = NULL; - unsigned int cnt; - BOOL doEnc; -- NSString *str; -+// NSString *str; - - // TODO: this s***s big time! -+// NSLog (@"class: '%@'", NSStringFromClass ([_data class])); -+// #if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY -+// str = [[NSString alloc] initWithData:_data -+// encoding:NSISOLatin1StringEncoding]; -+// str = [str autorelease]; -+ -+// #else -+// str = [[NSString alloc] initWithData:_data -+// encoding:NSISOLatin9StringEncoding]; -+// #endif -+// bytes = [str cString]; -+// length = [str cStringLength]; - --#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY -- str = [[NSString alloc] initWithData:_data -- encoding:NSISOLatin1StringEncoding]; --#else -- str = [[NSString alloc] initWithData:_data -- encoding:NSISOLatin9StringEncoding]; --#endif -- str = [str autorelease]; -- -- bytes = [str cString]; -- length = [str cStringLength]; -- -+ bytes = [_data bytes]; -+ length = [_data length]; -+ - /* check whether we need to encode */ -- -- for (cnt = 0, doEnc = NO; cnt < length; cnt++) { -- if ((unsigned char)bytes[cnt] > 127) { -+ cnt = 0; -+ doEnc = NO; -+ while (!doEnc && cnt < length) -+ if ((unsigned char)bytes[cnt] > 127) - doEnc = YES; -- break; -- } -- } -- -+ else -+ cnt++; -+ - if (!doEnc) - return _data; - - /* encode quoted printable */ - { -- char iso[] = "=?iso-8859-15?q?"; -+ char iso[] = "=?utf-8?q?"; - unsigned isoLen = 16; - char isoEnd[] = "?="; - unsigned isoEndLen = 2; -Index: sope-mime/NGMail/NGMailAddressParser.m -=================================================================== ---- sope-mime/NGMail/NGMailAddressParser.m (revision 1632) -+++ sope-mime/NGMail/NGMailAddressParser.m (working copy) -@@ -52,9 +52,9 @@ - StrClass = [NSString class]; - } - --static inline NSString *mkStrObj(const unsigned char *s, unsigned int l) { -+static inline NSString *mkStrObj(const unichar *s, unsigned int l) { - // TODO: unicode -- return [(NSString *)[StrClass alloc] initWithCString:(char *)s length:l]; -+ return [(NSString *)[StrClass alloc] initWithCharacters:s length:l]; - } - - static inline id parseWhiteSpaces(NGMailAddressParser *self, BOOL _guessMode) { -@@ -84,7 +84,7 @@ - int keepPos = self->dataPos; // keep reference for backtracking - id returnValue = nil; - BOOL isAtom = YES; -- unsigned char text[self->maxLength + 2]; // token text -+ unichar text[self->maxLength + 2]; // token text - int length = 0; // token text length - BOOL done = NO; - -@@ -94,7 +94,7 @@ - done = YES; - } - else { -- register unsigned char c = self->data[self->dataPos]; -+ register unichar c = self->data[self->dataPos]; - - switch (c) { - case '(' : case ')': case '<': case '>': -@@ -162,7 +162,7 @@ - int keepPos = self->dataPos; // keep reference for backtracking - id returnValue = nil; - BOOL isQText = YES; -- unsigned char text[self->maxLength + 4]; // token text -+ unichar text[self->maxLength + 4]; // token text - int length = 0; // token text length - BOOL done = YES; - -@@ -172,9 +172,9 @@ - done = YES; - } - else { -- register char c = self->data[self->dataPos]; -+ register unichar c = self->data[self->dataPos]; - -- switch ((int)c) { -+ switch (c) { - case '"' : - case '\\': - case 13 : -@@ -215,7 +215,7 @@ - int keepPos = self->dataPos; // keep reference for backtracking - id returnValue = nil; - BOOL isDText = YES; -- unsigned char text[self->maxLength]; // token text -+ unichar text[self->maxLength]; // token text - int length = 0; // token text length - BOOL done = YES; - -@@ -225,9 +225,9 @@ - done = YES; - } - else { -- register char c = self->data[self->dataPos]; -+ register unichar c = self->data[self->dataPos]; - -- switch ((int)c) { -+ switch (c) { - case '[': case ']': - case '\\': case 13: - isDText = (length > 0); -@@ -320,42 +320,47 @@ - /* constructors */ - - + (id)mailAddressParserWithData:(NSData *)_data { -- return [[(NGMailAddressParser *)[self alloc] -- initWithCString:[_data bytes] -- length:[_data length]] autorelease]; -+ NSString *uniString; -+ -+ uniString = [NSString stringWithCharacters:(unichar *)[_data bytes] -+ length:([_data length] / sizeof(unichar))]; -+ -+ return [(NGMailAddressParser *)self mailAddressParserWithString:uniString]; - } -+ - + (id)mailAddressParserWithCString:(char *)_cString { -- return [[(NGMailAddressParser *)[self alloc] -- initWithCString:(unsigned char *)_cString -- length:strlen(_cString)] autorelease]; -+ NSString *nsCString; -+ -+ nsCString = [NSString stringWithCString:_cString]; -+ -+ return [(NGMailAddressParser *)self mailAddressParserWithString:nsCString]; - } --- (id)initWithCString:(const unsigned char *)_cstr length:(int unsigned)_len { -+ -++ (id)mailAddressParserWithString:(NSString *)_string { -+ return [[(NGMailAddressParser *)[self alloc] initWithString:_string] -+ autorelease]; -+} -+ -+- (id)initWithString:(NSString *)_str { - if ((self = [super init])) { - // TODO: remember some string encoding? -- self->data = (unsigned char *)_cstr; -- self->maxLength = _len; -+ self->maxLength = [_str length]; -+ self->data = malloc(self->maxLength*sizeof(unichar)); -+ [_str getCharacters:self->data]; - self->dataPos = 0; - self->errorPos = -1; - } - return self; - } - --- (id)initWithString:(NSString *)_str { -- // TODO: unicode -- return [self initWithCString:(unsigned char *)[_str cString] -- length:[_str cStringLength]]; --} -- - - (id)init { -- return [self initWithCString:NULL length:0]; -+ return [self initWithString:nil]; - } - --+ (id)mailAddressParserWithString:(NSString *)_string { -- return [[(NGMailAddressParser *)[self alloc] initWithString:_string] -- autorelease]; --} -- - - (void)dealloc { -+ if (self->data != NULL) { -+ free(self->data); -+ } - self->data = NULL; - self->maxLength = 0; - self->dataPos = 0; -Index: sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m -=================================================================== ---- sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (revision 1632) -+++ sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (working copy) -@@ -19,88 +19,45 @@ - 02111-1307, USA. - */ - -+#ifdef HAVE_STRNDUP -+#define _GNU_SOURCE 1 -+#endif -+ -+#include -+ - #include "NGMimeHeaderFieldParser.h" - #include "NGMimeHeaderFields.h" - #include "NGMimeUtilities.h" - #include "common.h" --#include - -+#ifndef HAVE_STRNDUP -+char *strndup(const char *str, size_t len) -+{ -+ char *dup = (char *)malloc(len+1); -+ if (dup) { -+ strncpy(dup,str,len); -+ dup[len]= '\0'; -+ } -+ return dup; -+} -+#endif -+ - @implementation NGMimeRFC822DateHeaderFieldParser - --static Class CalDateClass = Nil; --static NSTimeZone *gmt = nil; --static NSTimeZone *gmt01 = nil; --static NSTimeZone *gmt02 = nil; --static NSTimeZone *gmt03 = nil; --static NSTimeZone *gmt04 = nil; --static NSTimeZone *gmt05 = nil; --static NSTimeZone *gmt06 = nil; --static NSTimeZone *gmt07 = nil; --static NSTimeZone *gmt08 = nil; --static NSTimeZone *gmt09 = nil; --static NSTimeZone *gmt10 = nil; --static NSTimeZone *gmt11 = nil; --static NSTimeZone *gmt12 = nil; --static NSTimeZone *gmt0530 = nil; --static NSTimeZone *gmtM01 = nil; --static NSTimeZone *gmtM02 = nil; --static NSTimeZone *gmtM03 = nil; --static NSTimeZone *gmtM04 = nil; --static NSTimeZone *gmtM05 = nil; --static NSTimeZone *gmtM06 = nil; --static NSTimeZone *gmtM07 = nil; --static NSTimeZone *gmtM08 = nil; --static NSTimeZone *gmtM09 = nil; --static NSTimeZone *gmtM10 = nil; --static NSTimeZone *gmtM11 = nil; --static NSTimeZone *gmtM12 = nil; --static NSTimeZone *gmtM13 = nil; --static NSTimeZone *gmtM14 = nil; --static NSTimeZone *met = nil; -+static NSTimeZone *gmt = nil; -+static NSTimeZone *met = nil; - - + (int)version { - return 2; - } -+ - + (void)initialize { - static BOOL didInit = NO; -- Class TzClass; - if (didInit) return; - didInit = YES; - -- CalDateClass = [NSCalendarDate class]; -- -- /* timezones which were actually used in a maillist mailbox */ -- TzClass = [NSTimeZone class]; -- gmt = [[TzClass timeZoneWithName:@"GMT"] retain]; -- met = [[TzClass timeZoneWithName:@"MET"] retain]; -- gmt01 = [[TzClass timeZoneForSecondsFromGMT: 1 * (60 * 60)] retain]; -- gmt02 = [[TzClass timeZoneForSecondsFromGMT: 2 * (60 * 60)] retain]; -- gmt03 = [[TzClass timeZoneForSecondsFromGMT: 3 * (60 * 60)] retain]; -- gmt04 = [[TzClass timeZoneForSecondsFromGMT: 4 * (60 * 60)] retain]; -- gmt05 = [[TzClass timeZoneForSecondsFromGMT: 5 * (60 * 60)] retain]; -- gmt06 = [[TzClass timeZoneForSecondsFromGMT: 6 * (60 * 60)] retain]; -- gmt07 = [[TzClass timeZoneForSecondsFromGMT: 7 * (60 * 60)] retain]; -- gmt08 = [[TzClass timeZoneForSecondsFromGMT: 8 * (60 * 60)] retain]; -- gmt09 = [[TzClass timeZoneForSecondsFromGMT: 9 * (60 * 60)] retain]; -- gmt10 = [[TzClass timeZoneForSecondsFromGMT: 10 * (60 * 60)] retain]; -- gmt11 = [[TzClass timeZoneForSecondsFromGMT: 11 * (60 * 60)] retain]; -- gmt12 = [[TzClass timeZoneForSecondsFromGMT: 12 * (60 * 60)] retain]; -- gmtM01 = [[TzClass timeZoneForSecondsFromGMT: -1 * (60 * 60)] retain]; -- gmtM02 = [[TzClass timeZoneForSecondsFromGMT: -2 * (60 * 60)] retain]; -- gmtM03 = [[TzClass timeZoneForSecondsFromGMT: -3 * (60 * 60)] retain]; -- gmtM04 = [[TzClass timeZoneForSecondsFromGMT: -4 * (60 * 60)] retain]; -- gmtM05 = [[TzClass timeZoneForSecondsFromGMT: -5 * (60 * 60)] retain]; -- gmtM06 = [[TzClass timeZoneForSecondsFromGMT: -6 * (60 * 60)] retain]; -- gmtM07 = [[TzClass timeZoneForSecondsFromGMT: -7 * (60 * 60)] retain]; -- gmtM08 = [[TzClass timeZoneForSecondsFromGMT: -8 * (60 * 60)] retain]; -- gmtM09 = [[TzClass timeZoneForSecondsFromGMT: -9 * (60 * 60)] retain]; -- gmtM10 = [[TzClass timeZoneForSecondsFromGMT:-10 * (60 * 60)] retain]; -- gmtM11 = [[TzClass timeZoneForSecondsFromGMT:-11 * (60 * 60)] retain]; -- gmtM12 = [[TzClass timeZoneForSecondsFromGMT:-12 * (60 * 60)] retain]; -- gmtM13 = [[TzClass timeZoneForSecondsFromGMT:-13 * (60 * 60)] retain]; -- gmtM14 = [[TzClass timeZoneForSecondsFromGMT:-14 * (60 * 60)] retain]; -- -- gmt0530 = [[TzClass timeZoneForSecondsFromGMT:5 * (60*60) + (30*60)] retain]; -+ gmt = [[NSTimeZone timeZoneWithName:@"GMT"] retain]; -+ met = [[NSTimeZone timeZoneWithName:@"MET"] retain]; - } - - /* -@@ -111,7 +68,7 @@ - TODO: use an own parser for that. - */ - --static int parseMonthOfYear(unsigned char *s, unsigned int len) { -+static int parseMonthOfYear(char *s, unsigned int len) { - /* - This one is *extremely* forgiving, it only checks what is - necessary for the set below. This should work for both, English -@@ -147,162 +104,110 @@ - } - } - --static NSTimeZone *parseTimeZone(unsigned char *s, unsigned int len) { -+static int offsetFromTZAbbreviation(const char **p) { -+ NSString *abbreviation; -+ NSTimeZone *offsetTZ; -+ unsigned int length; -+ -+ length = 0; -+ while (isalpha(*(*p+length))) -+ length++; -+ abbreviation = [[NSString alloc] initWithBytes: *p -+ length: length - 1 -+ encoding: NSISOLatin1StringEncoding]; -+ offsetTZ = [NSTimeZone timeZoneWithAbbreviation: abbreviation]; -+ [abbreviation release]; -+ *p += length; -+ -+ return [offsetTZ secondsFromGMT]; -+} -+ -+static inline char *digitsString(const char *string) { -+ const char *p; -+ unsigned int len; -+ -+ p = string; -+ while (!isdigit(*p)) -+ p++; -+ len = 0; -+ while (isdigit(*(p + len))) -+ len++; -+ -+ return strndup(p, len); -+} -+ -+static NSTimeZone *parseTimeZone(const char *s, unsigned int len) { - /* - WARNING: failed to parse RFC822 timezone: '+0530' \ - (value='Tue, 13 Jul 2004 21:39:28 +0530') - TODO: this is because libFoundation doesn't accept 'GMT+0530' as input. - */ -- char *p = (char *)s; -+ char *newString, *digits; -+ const char *p; - NSTimeZone *tz; -- NSString *ts; -- -- if (len == 0) -- return nil; -- -- if (*s == '+' || *s == '-') { -- if (len == 3) { -- if (p[1] == '0' && p[2] == '0') // '+00' or '-00' -- return gmt; -- if (*s == '+') { -- if (p[1] == '0' && p[2] == '1') // '+01' -- return gmt01; -- if (p[1] == '0' && p[2] == '2') // '+02' -- return gmt02; -- } -- } -- else if (len == 5) { -- if (p[3] == '0' && p[4] == '0' && p[1] == '0') { // '?0x00' -- if (p[2] == '0') // '+0000' -- return gmt; -- -- if (*s == '+') { -- if (p[2] == '1') return gmt01; // '+0100' -- if (p[2] == '2') return gmt02; // '+0200' -- if (p[2] == '3') return gmt03; // '+0300' -- if (p[2] == '4') return gmt04; // '+0400' -- if (p[2] == '5') return gmt05; // '+0500' -- if (p[2] == '6') return gmt06; // '+0600' -- if (p[2] == '7') return gmt07; // '+0700' -- if (p[2] == '8') return gmt08; // '+0800' -- if (p[2] == '9') return gmt09; // '+0900' -- } -- else if (*s == '-') { -- if (p[2] == '1') return gmtM01; // '-0100' -- if (p[2] == '2') return gmtM02; // '-0200' -- if (p[2] == '3') return gmtM03; // '-0300' -- if (p[2] == '4') return gmtM04; // '-0400' -- if (p[2] == '5') return gmtM05; // '-0500' -- if (p[2] == '6') return gmtM06; // '-0600' -- if (p[2] == '7') return gmtM07; // '-0700' -- if (p[2] == '8') return gmtM08; // '-0800' -- if (p[2] == '9') return gmtM09; // '-0900' -- } -- } -- else if (p[3] == '0' && p[4] == '0' && p[1] == '1') { // "?1x00" -- if (*s == '+') { -- if (p[2] == '0') return gmt10; // '+1000' -- if (p[2] == '1') return gmt11; // '+1100' -- if (p[2] == '2') return gmt12; // '+1200' -- } -- else if (*s == '-') { -- if (p[2] == '0') return gmtM10; // '-1000' -- if (p[2] == '1') return gmtM11; // '-1100' -- if (p[2] == '2') return gmtM12; // '-1200' -- if (p[2] == '3') return gmtM13; // '-1300' -- if (p[2] == '4') return gmtM14; // '-1400' -- } -- } -- -- /* special case for GMT+0530 */ -- if (strncmp((char *)s, "+0530", 5) == 0) -- return gmt0530; -- } -- else if (len == 7) { -- /* -- "MultiMail" submits timezones like this: -- "Tue, 9 Mar 2004 9:43:00 -05-500", -- don't know what the "-500" trailer is supposed to mean? Apparently -- Thunderbird just uses the "-05", so do we. -- */ -- -- if (isdigit(p[1]) && isdigit(p[2]) && (p[3] == '-'||p[3] == '+')) { -- unsigned char tmp[8]; -- -- strncpy((char *)tmp, p, 3); -- tmp[3] = '0'; -- tmp[4] = '0'; -- tmp[5] = '\0'; -- return parseTimeZone(tmp, 5); -- } -- } -+ unsigned int hours, minutes, seconds, remaining; -+ int sign; -+ -+ sign = 1; -+ hours = 0; -+ minutes = 0; -+ seconds = 0; -+ -+ newString = strndup(s, len); -+ p = newString; -+ -+ if (isalpha(*p)) -+ seconds = offsetFromTZAbbreviation(&p); -+ while (isspace(*p)) -+ p++; -+ while (*p == '+' || *p == '-') { -+ if (*p == '-') -+ sign = -sign; -+ p++; - } -- else if (*s == '0') { -- if (len == 2) { // '00' -- if (p[1] == '0') return gmt; -- if (p[1] == '1') return gmt01; -- if (p[1] == '2') return gmt02; -- } -- else if (len == 4) { -- if (p[2] == '0' && p[3] == '0') { // '0x00' -- if (p[1] == '0') return gmt; -- if (p[1] == '1') return gmt01; -- if (p[1] == '2') return gmt02; -- } -- } -+ digits = digitsString(p); -+ p = digits; -+ remaining = strlen(p); -+ switch(remaining) { -+ case 6: /* hhmmss */ -+ seconds += (10 * (*(p + remaining - 2) - 48) -+ + *(p + remaining - 1) - 48); -+ case 4: /* hhmm */ -+ hours += 10 * (*p - 48); -+ p++; -+ case 3: /* hmm */ -+ hours += (*p - 48); -+ p++; -+ minutes += 10 * (*p - 48) + *(p + 1) - 48; -+ break; -+ case 2: /* hh */ -+ hours += 10 * (*p - 48) + *(p + 1) - 48; -+ break; -+ default: -+ NSLog (@"parseTimeZone: cannot parse time notation '%s'", newString); - } -- else if (len == 3) { -- if (strcasecmp((char *)s, "GMT") == 0) return gmt; -- if (strcasecmp((char *)s, "UTC") == 0) return gmt; -- if (strcasecmp((char *)s, "MET") == 0) return met; -- if (strcasecmp((char *)s, "CET") == 0) return met; -- } -- -- if (isalpha(*s)) { -- ts = [[NSString alloc] initWithCString:(char *)s length:len]; -- } -- else { -- char buf[len + 5]; -- -- buf[0] = 'G'; buf[1] = 'M'; buf[2] = 'T'; -- if (*s == '+' || *s == '-') { -- strcpy(&(buf[3]), (char *)s); -- } -- else { -- buf[3] = '+'; -- strcpy(&(buf[4]), (char *)s); -- } -- ts = [[NSString alloc] initWithCString:buf]; -- } --#if 1 -- NSLog(@"%s: RFC822 TZ Parser: expensive: '%@'", __PRETTY_FUNCTION__, ts); --#endif -- tz = [NSTimeZone timeZoneWithAbbreviation:ts]; -- [ts release]; -+ free(digits); -+ -+ seconds += sign * (3600 * hours + 60 * minutes); -+ tz = [NSTimeZone timeZoneForSecondsFromGMT: seconds]; -+ free(newString); -+ - return tz; - } - - - (id)parseValue:(id)_data ofHeaderField:(NSString *)_field { - // TODO: use UNICODE - NSCalendarDate *date = nil; -- unsigned char buf[256]; -- unsigned char *bytes = buf, *pe; -+ char *bytes, *pe; - unsigned length = 0; - NSTimeZone *tz = nil; - char dayOfMonth, monthOfYear, hour, minute, second; - short year; - BOOL flag; -- -- if ((length = [_data cStringLength]) > 254) { -- [self logWithFormat: -- @"header field value to large for date parsing: '%@'(%i)", -- _data, length]; -- length = 254; -- } -- -- [_data getCString:(char *)buf maxLength:length]; -- buf[length] = '\0'; -- -+ -+ length = [_data lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; -+ bytes = [_data cStringUsingEncoding: NSUTF8StringEncoding]; -+ - /* remove leading chars (skip to first digit, the day of the month) */ - while (length > 0 && (!isdigit(*bytes))) { - bytes++; -@@ -312,7 +217,7 @@ - if (length == 0) { - NSLog(@"WARNING(%s): empty value for header field %@ ..", - __PRETTY_FUNCTION__, _field); -- return [CalDateClass date]; -+ return [NSCalendarDate date]; - } - - // TODO: should be a category on NSCalendarDate -@@ -435,7 +340,8 @@ - for (pe = bytes; isalnum(*pe) || *pe == '-' || *pe == '+'; pe++) - ; - *pe = '\0'; -- if ((tz = parseTimeZone(bytes, (pe - bytes))) == nil) { -+ if (pe == bytes -+ || (tz = parseTimeZone((const char *) bytes, (pe - bytes))) == nil) { - [self logWithFormat: - @"WARNING: failed to parse RFC822 timezone: '%s' (value='%@')", - bytes, _data]; -@@ -444,9 +350,9 @@ - - /* construct and return */ - finished: -- date = [CalDateClass dateWithYear:year month:monthOfYear day:dayOfMonth -- hour:hour minute:minute second:second -- timeZone:tz]; -+ date = [NSCalendarDate dateWithYear:year month:monthOfYear day:dayOfMonth -+ hour:hour minute:minute second:second -+ timeZone:tz]; - if (date == nil) goto failed; - - #if 0 -Index: sope-mime/NGMime/NGMimeMultipartBodyParser.m -=================================================================== ---- sope-mime/NGMime/NGMimeMultipartBodyParser.m (revision 1632) -+++ sope-mime/NGMime/NGMimeMultipartBodyParser.m (working copy) -@@ -428,6 +428,7 @@ - NSString *boundary = nil; - NSArray *rawBodyParts = nil; - BOOL foundError = NO; -+ NSData *boundaryBytes; - - contentType = [_part contentType]; - boundary = [contentType valueOfParameter:@"boundary"]; -@@ -437,9 +438,10 @@ - - *(&foundError) = NO; - -+ boundaryBytes = [boundary dataUsingEncoding:NSISOLatin1StringEncoding]; - *(&rawBodyParts) = [self _parseBody:_body part:_part data:_data -- boundary:[boundary cString] -- length:[boundary cStringLength] -+ boundary:[boundaryBytes bytes] -+ length:[boundary length] - delegate:_d]; - - if (rawBodyParts) { -Index: sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m -=================================================================== ---- sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (revision 1632) -+++ sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (working copy) -@@ -77,6 +77,7 @@ - [rfc822Set setGenerator:gen forField:@"bcc"]; - [rfc822Set setGenerator:gen forField:Fields->from]; - [rfc822Set setGenerator:gen forField:@"reply-to"]; -+ [rfc822Set setGenerator:gen forField:@"in-reply-to"]; - [rfc822Set setGenerator:gen forField:@"Disposition-Notification-To"]; - } - -Index: sope-mime/NGMime/NGMimeType.m -=================================================================== ---- sope-mime/NGMime/NGMimeType.m (revision 1632) -+++ sope-mime/NGMime/NGMimeType.m (working copy) -@@ -120,28 +120,23 @@ - - /* some unsupported, but known encoding */ - else if ([charset isEqualToString:@"ks_c_5601-1987"]) { -- encoding = [NSString defaultCStringEncoding]; -+ encoding = NSISOLatin1StringEncoding; - foundUnsupported = YES; - } - else if ([charset isEqualToString:@"euc-kr"]) { -- encoding = [NSString defaultCStringEncoding]; -- foundUnsupported = YES; -+ encoding = NSKoreanEUCStringEncoding; - } - else if ([charset isEqualToString:@"big5"]) { -- encoding = [NSString defaultCStringEncoding]; -- foundUnsupported = YES; -+ encoding = NSBIG5StringEncoding; - } - else if ([charset isEqualToString:@"iso-2022-jp"]) { -- encoding = [NSString defaultCStringEncoding]; -- foundUnsupported = YES; -+ encoding = NSISO2022JPStringEncoding; - } - else if ([charset isEqualToString:@"gb2312"]) { -- encoding = [NSString defaultCStringEncoding]; -- foundUnsupported = YES; -+ encoding = NSGB2312StringEncoding; - } - else if ([charset isEqualToString:@"koi8-r"]) { -- encoding = [NSString defaultCStringEncoding]; -- foundUnsupported = YES; -+ encoding = NSKOI8RStringEncoding; - } - - else if ([charset isEqualToString:@"windows-1252"]) { -@@ -152,7 +147,7 @@ - } - else if ([charset isEqualToString:@"x-unknown"] || - [charset isEqualToString:@"unknown"]) { -- encoding = NSASCIIStringEncoding; -+ encoding = NSISOLatin1StringEncoding; - } - /* ISO Latin 9 */ - #if !(NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY) -@@ -166,7 +161,7 @@ - else { - [self logWithFormat:@"%s: unknown charset '%@'", - __PRETTY_FUNCTION__, _s]; -- encoding = [NSString defaultCStringEncoding]; -+ encoding = NSISOLatin1StringEncoding; - } - return encoding; - } -@@ -385,23 +380,26 @@ - } - - - (BOOL)valueNeedsQuotes:(NSString *)_parameterValue { -- unsigned len = [_parameterValue cStringLength]; -- char buf[len + 15]; -- char *cstr; -+ NSData *stringData; -+ const char *cstr; -+ unsigned int count, max; -+ BOOL needsQuote; - -- cstr = &(buf[0]); -+ needsQuote = NO; - -- [_parameterValue getCString:cstr]; cstr[len] = '\0'; -- while (*cstr) { -- if (isMime_SpecialByte(*cstr)) -- return YES; -- -- if (*cstr == 32) -- return YES; -- -- cstr++; -+ stringData = [_parameterValue dataUsingEncoding:NSUTF8StringEncoding]; -+ cstr = [stringData bytes]; -+ max = [stringData length]; -+ count = 0; -+ while (!needsQuote && count < max) { -+ if (isMime_SpecialByte(*(cstr + count)) -+ || *(cstr + count) == 32) -+ needsQuote = YES; -+ else -+ count++; - } -- return NO; -+ -+ return needsQuote; - } - - - (NSString *)stringValue { -Index: sope-mime/NGMime/NGMimeBodyPart.m -=================================================================== ---- sope-mime/NGMime/NGMimeBodyPart.m (revision 1632) -+++ sope-mime/NGMime/NGMimeBodyPart.m (working copy) -@@ -31,18 +31,6 @@ - return 2; - } - --static NGMimeType *defaultType = nil; -- --+ (void)initialize { -- static BOOL isInitialized = NO; -- if (!isInitialized) { -- isInitialized = YES; -- -- defaultType = -- [[NGMimeType mimeType:@"text/plain; charset=us-ascii"] retain]; -- } --} -- - + (id)bodyPartWithHeader:(NGHashMap *)_header { - return [[[self alloc] initWithHeader:_header] autorelease]; - } -@@ -156,13 +144,12 @@ - if (!Fields) - Fields = (NGMimeHeaderNames *)[NGMimePartParser headerFieldNames]; - -- - type = [self->header objectForKey:Fields->contentType]; - - if (![type isKindOfClass:[NGMimeType class]]) - type = [NGMimeType mimeType:[type stringValue]]; - -- return (type != nil ? type : (id)defaultType); -+ return type; - } - - - (NSString *)contentId { -Index: sope-mime/NGMime/ChangeLog -=================================================================== ---- sope-mime/NGMime/ChangeLog (revision 1632) -+++ sope-mime/NGMime/ChangeLog (working copy) -@@ -1,3 +1,25 @@ -+2008-09-08 Wolfgang Sourdeau -+ -+ * NGMimeRFC822DateHeaderFieldParser.m ([NGMimeRFC -+ -parseValue:ofHeaderField:]): don't parse timezone with a length -+ of 0. -+ -+2008-09-01 Wolfgang Sourdeau -+ -+ * NGMimeRFC822DateHeaderFieldParser.m ([NGMimeRFC -+ -parseValue:ofHeaderField:]): use an 8-bit safe encoding when -+ parsing dates. Since we only consider 7-bits characters, we ensure -+ that bad user-agents can be handled more properly. -+ -+ * NGMimeType.m ([NGMimeType +stringEncodingForCharset:]): -+ x-unknown encoding is now translated to an 8-bit safe encoding -+ (NSISOLatin1StringEncoding). -+ -+ * NGMimeAddressHeaderFieldGenerator.m -+ ([NGMimeAddressHeaderFieldGenerator -+ -generateDataForHeaderFieldNamed:value:]): encode resulting string -+ in an 8-bit safe encoding (NSISOLatin1StringEncoding). -+ - 2008-01-29 Albrecht Dress - - * fixes for OGo bug #789 (reply-to QP encoding) -Index: sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m -=================================================================== ---- sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (revision 1632) -+++ sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (working copy) -@@ -36,8 +36,7 @@ - NGMimeType *type = nil; // only one content-type field - NSString *tmp = nil; - NSMutableData *data = nil; -- unsigned char *ctmp = NULL; -- unsigned len = 0; -+ NSData *valueData; - - type = _value; - -@@ -59,21 +58,15 @@ - - tmp = [type type]; - NSAssert(tmp, @"type should not be nil"); -- len = [tmp length]; -- ctmp = malloc(len + 4); -- [tmp getCString:(char *)ctmp]; ctmp[len] = '\0'; -- [data appendBytes:ctmp length:len]; -- free(ctmp); -+ valueData = [tmp dataUsingEncoding: NSISOLatin1StringEncoding]; -+ [data appendData: valueData]; -+ -+ [data appendBytes:"/" length:1]; - -- [data appendBytes:"//" length:1]; -- - tmp = [type subType]; - if (tmp != nil) { -- len = [tmp length]; -- ctmp = malloc(len + 4); -- [tmp getCString:(char *)ctmp]; ctmp[len] = '\0'; -- [data appendBytes:ctmp length:len]; -- free(ctmp); -+ valueData = [tmp dataUsingEncoding: NSISOLatin1StringEncoding]; -+ [data appendData:valueData]; - } - else - [data appendBytes:"*" length:1]; -@@ -91,12 +84,9 @@ - continue; - } - [data appendBytes:"; " length:2]; -- -- len = [name cStringLength]; -- ctmp = malloc(len + 1); -- [name getCString:(char *)ctmp]; ctmp[len] = '\0'; -- [data appendBytes:ctmp length:len]; -- free(ctmp); -+ -+ valueData = [name dataUsingEncoding: NSUTF8StringEncoding]; -+ [data appendData: valueData]; - - /* - this confuses GroupWise: "= \"" (a space) -@@ -105,66 +95,30 @@ - - /* check for encoding */ - { -- unsigned cnt; -+ unsigned cnt, max; -+ const char *dataBytes; - BOOL doEnc; - -- len = [value cStringLength]; -- ctmp = malloc(len + 4); -- [value getCString:(char *)ctmp]; ctmp[len] = '\0'; -- cnt = 0; -+ valueData = [value dataUsingEncoding:NSUTF8StringEncoding]; -+ dataBytes = [valueData bytes]; -+ max = [valueData length]; -+ - doEnc = NO; -- while (cnt < len) { -- if ((unsigned char)ctmp[cnt] > 127) { -+ cnt = 0; -+ while (!doEnc && cnt < max) { -+ if ((unsigned char)dataBytes[cnt] > 127) - doEnc = YES; -- break; -- } -- cnt++; -+ else -+ cnt++; - } - if (doEnc) { -- unsigned char iso[] = "=?iso-8859-15?q?"; -- unsigned isoLen = 16; -- unsigned char isoEnd[] = "?="; -- unsigned isoEndLen = 2; -- unsigned desLen; -- unsigned char *des; -- -- if (ctmp) free(ctmp); -- { -- NSData *data; -- --#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY -- data = [value dataUsingEncoding:NSISOLatin1StringEncoding]; --#else -- data = [value dataUsingEncoding:NSISOLatin9StringEncoding]; --#endif -- -- len = [data length]; -- ctmp = malloc(len + 10); -- [data getBytes:ctmp]; ctmp[len] = '\0'; -- } -- -- desLen = len * 3 + 20; -- des = calloc(desLen + 10, sizeof(char)); -- -- memcpy(des, ctmp, cnt); -- memcpy(des + cnt, iso, isoLen); -- desLen = -- NGEncodeQuotedPrintableMime(ctmp + cnt, len - cnt, -- des + cnt + isoLen, -- desLen - cnt - isoLen); -- if ((int)desLen != -1) { -- memcpy(des + cnt + isoLen + desLen, isoEnd, isoEndLen); -- [data appendBytes:des length:(cnt + isoLen + desLen + isoEndLen)]; -- } -- else { -- NSLog(@"WARNING: An error occour during quoted-printable decoding"); -- } -- if (des) free(des); -+ [data appendBytes:"=?utf-8?q?" length:10]; -+ [data appendData: [valueData dataByEncodingQuotedPrintable]]; -+ [data appendBytes:"?=" length:2]; - } - else { -- [data appendBytes:ctmp length:len]; -+ [data appendData: valueData]; - } -- free(ctmp); - } - [data appendBytes:"\"" length:1]; - } -Index: sope-mime/NGMime/NGMimePartGenerator.m -=================================================================== ---- sope-mime/NGMime/NGMimePartGenerator.m (revision 1632) -+++ sope-mime/NGMime/NGMimePartGenerator.m (working copy) -@@ -155,8 +155,9 @@ - BOOL isMultiValue, isFirst; - - /* get field name and strip leading spaces */ -- fcname = (const unsigned char *)[_field cString]; -- for (len = [_field cStringLength]; len > 0; fcname++, len--) { -+ fcname = (const unsigned char *)[_field cStringUsingEncoding:NSISOLatin1StringEncoding]; -+ for (len = [_field lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding]; -+ len > 0; fcname++, len--) { - if (*fcname != ' ') - break; - } -@@ -328,7 +329,7 @@ - if ([body isKindOfClass:[NSData class]]) - data = body; - else if ([body isKindOfClass:[NSString class]]) -- data = [body dataUsingEncoding:[NSString defaultCStringEncoding]]; -+ data = [body dataUsingEncoding: NSISOLatin1StringEncoding]; - else - data = nil; - -Index: sope-mime/NGMime/NGMimeBodyParser.m -=================================================================== ---- sope-mime/NGMime/NGMimeBodyParser.m (revision 1632) -+++ sope-mime/NGMime/NGMimeBodyParser.m (working copy) -@@ -67,7 +67,10 @@ - if (_data == nil) return nil; - - ctype = [_part contentType]; -- -+ if (!ctype -+ && [_d respondsToSelector: @selector(parser:contentTypeOfPart:)]) -+ ctype = [_d parser: self contentTypeOfPart: _part]; -+ - if (![ctype isKindOfClass:[NGMimeType class]]) - ctype = [NGMimeType mimeType:[ctype stringValue]]; - -@@ -88,10 +91,20 @@ - NSStringEncoding encoding; - - encoding = [NGMimeType stringEncodingForCharset:charset]; -- -+ -+ // If we nave no encoding here, let's not simply return nil. -+ // We SHOULD try at least UTF-8 and after, Latin1. -+ if (!encoding) -+ encoding = NSUTF8StringEncoding; -+ - body = [[[NSString alloc] -- initWithData:_data -+ initWithData:_data - encoding:encoding] autorelease]; -+ -+ if (!body) -+ body = [[[NSString alloc] initWithData:_data -+ encoding:NSISOLatin1StringEncoding] -+ autorelease]; - } - return body; - } -Index: sope-mime/NGMime/NGMimePartParser.h -=================================================================== ---- sope-mime/NGMime/NGMimePartParser.h (revision 1632) -+++ sope-mime/NGMime/NGMimePartParser.h (working copy) -@@ -117,6 +117,7 @@ - BOOL parserParseRawBodyDataOfPart:1; - BOOL parserBodyParserForPart:1; - BOOL parserDecodeBodyOfPart:1; -+ BOOL parserContentTypeOfPart:1; - } delegateRespondsTo; - - -@@ -275,6 +276,9 @@ - - (id)parser:(NGMimePartParser *)_parser - bodyParserForPart:(id)_part; - -+- (NGMimeType *)parser:(id)_parser -+ contentTypeOfPart:(id)_part; -+ - @end /* NSObject(NGMimePartParserDelegate) */ - - @interface NSObject(NGMimePartParser) -Index: sope-mime/NGMime/NGMimePartParser.m -=================================================================== ---- sope-mime/NGMime/NGMimePartParser.m (revision 1632) -+++ sope-mime/NGMime/NGMimePartParser.m (working copy) -@@ -227,7 +227,7 @@ - } - - + (NSStringEncoding)defaultHeaderFieldEncoding { -- return NSISOLatin1StringEncoding; -+ return NSUTF8StringEncoding; - } - - - (id)valueOfHeaderField:(NSString *)_name data:(id)_data { -@@ -1091,7 +1091,10 @@ - id bodyParser = nil; - - ctype = [_p contentType]; -- -+ if (!ctype -+ && self->delegateRespondsTo.parserContentTypeOfPart) -+ ctype = [self->delegate parser: self contentTypeOfPart: _p]; -+ - contentType = ([ctype isKindOfClass:[NGMimeType class]]) - ? ctype - : [NGMimeType mimeType:[ctype stringValue]]; -Index: sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m -=================================================================== ---- sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (revision 1632) -+++ sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (working copy) -@@ -105,10 +105,10 @@ - } - - tmp = [obj displayName]; -- bufLen = [tmp cStringLength]; -+ bufLen = [tmp lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; - -- buffer = calloc(bufLen + 10, sizeof(char)); -- [tmp getCString:buffer]; -+ buffer = calloc(bufLen, sizeof(char)); -+ [tmp getCString: buffer maxLength: bufLen encoding: NSUTF8StringEncoding]; - - cnt = 0; - doEnc = NO; -@@ -117,11 +117,11 @@ - /* must encode chars outside ASCII 33..60, 62..126 ranges [RFC 2045, Sect. 6.7] - * RFC 2047, Sect. 4.2 also requires chars 63 and 95 to be encoded - * For spaces, quotation is fine */ -- if ((unsigned char)buffer[cnt] < 32 || -- (unsigned char)buffer[cnt] == 61 || -- (unsigned char)buffer[cnt] == 63 || -- (unsigned char)buffer[cnt] == 95 || -- (unsigned char)buffer[cnt] > 126) { -+ if ((unichar)buffer[cnt] < 32 || -+ (unichar)buffer[cnt] == 61 || -+ (unichar)buffer[cnt] == 63 || -+ (unichar)buffer[cnt] == 95 || -+ (unichar)buffer[cnt] > 126) { - doEnc = YES; - break; - } -@@ -130,8 +130,13 @@ - - if (doEnc) { - /* FIXME - better use UTF8 encoding! */ -+#if NeXT_Foundation_LIBRARY - unsigned char iso[] = "=?iso-8859-15?q?"; - unsigned isoLen = 16; -+#else -+ unsigned char iso[] = "=?utf-8?q?"; -+ unsigned isoLen = 10; -+#endif - unsigned char isoEnd[] = "?="; - unsigned isoEndLen = 2; - unsigned desLen; -@@ -141,10 +146,10 @@ - { - NSData *data; - --#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY -+#if NeXT_Foundation_LIBRARY - data = [tmp dataUsingEncoding:NSISOLatin1StringEncoding]; - #else -- data = [tmp dataUsingEncoding:NSISOLatin9StringEncoding]; -+ data = [tmp dataUsingEncoding:NSUTF8StringEncoding]; - #endif - - bufLen = [data length]; -@@ -162,8 +167,9 @@ - des + isoLen, desLen - isoLen); - if ((int)desLen != -1) { - memcpy(des + isoLen + desLen, isoEnd, isoEndLen); -- tmp = [NSString stringWithCString:(char *)des -- length:(isoLen + desLen + isoEndLen)]; -+ tmp = [[NSString alloc] initWithData: [NSData dataWithBytes:(char *)des length:(isoLen + desLen + isoEndLen)] -+ encoding: NSISOLatin1StringEncoding]; -+ [tmp autorelease]; - } - else { - [self warnWithFormat: -@@ -190,11 +196,7 @@ - } - } - --#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY - data = [result dataUsingEncoding:NSISOLatin1StringEncoding]; --#else -- data = [result dataUsingEncoding:NSISOLatin9StringEncoding]; --#endif - [result release]; - - return data; -Index: sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m -=================================================================== ---- sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (revision 1632) -+++ sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (working copy) -@@ -49,80 +49,70 @@ - - // TODO: move the stuff below to some NSString or NSData category? - -- data = [NSMutableData dataWithCapacity:64]; -+ data = [NSMutableData dataWithCapacity: 64]; - tmp = [field type]; - [data appendBytes:[tmp cString] length:[tmp length]]; - tmp = [field filename]; - if (tmp != nil) { - [data appendBytes:"; " length:2]; - [data appendBytes:"filename=\"" length:10]; -- { -- unsigned char *ctmp; -- int cnt, len; -- BOOL doEnc; -- -- // TODO: unicode? -- len = [tmp cStringLength]; -- ctmp = malloc(len + 3); -- [tmp getCString:(char *)ctmp]; ctmp[len] = '\0'; -- cnt = 0; -- doEnc = NO; -- while (cnt < len) { -- if ((unsigned char)ctmp[cnt] > 127) { -- doEnc = YES; -- break; -- } -- cnt++; -+ -+ NSData *d; -+ unsigned char* bytes; -+ unsigned length; -+ int cnt; -+ BOOL doEnc; -+ -+ //d = [tmp dataUsingEncoding: NSUTF8StringEncoding]; -+ //bytes = [d bytes]; -+ //length = [d length]; -+ bytes = [tmp cStringUsingEncoding: NSUTF8StringEncoding]; -+ length = strlen(bytes); -+ -+ cnt = 0; -+ doEnc = NO; -+ while (cnt < length) { -+ if ((unsigned char)bytes[cnt] > 127) { -+ doEnc = YES; -+ break; - } -- if (doEnc) { -- char iso[] = "=?iso-8859-15?q?"; -- unsigned isoLen = 16; -- char isoEnd[] = "?="; -- unsigned isoEndLen = 2; -- unsigned desLen; -- char *des; -- -- if (ctmp) free(ctmp); -- { -- NSData *data; -+ cnt++; -+ } - --#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY -- data = [tmp dataUsingEncoding:NSISOLatin1StringEncoding]; --#else -- data = [tmp dataUsingEncoding:NSISOLatin9StringEncoding]; --#endif -- -- len = [data length]; -- ctmp = malloc(len+1); -- [data getBytes:ctmp]; ctmp[len] = '\0'; -- } -- -- desLen = len * 3 + 20; -- des = calloc(desLen + 10, sizeof(char)); -- -- memcpy(des, ctmp, cnt); -- memcpy(des + cnt, iso, isoLen); -- desLen = -- NGEncodeQuotedPrintableMime((unsigned char *)ctmp + cnt, len - cnt, -- (unsigned char *)des + cnt + isoLen, -- desLen - cnt - isoLen); -- if ((int)desLen != -1) { -- memcpy(des + cnt + isoLen + desLen, isoEnd, isoEndLen); -- [data appendBytes:des length:(cnt + isoLen + desLen + isoEndLen)]; -- } -- else { -+ if (doEnc) -+ { -+ char iso[] = "=?utf-8?q?"; -+ unsigned isoLen = 10; -+ char isoEnd[] = "?="; -+ unsigned isoEndLen = 2; -+ int desLen; -+ char *des; -+ -+ desLen = length * 3 + 20; -+ -+ des = calloc(desLen + 2, sizeof(char)); -+ -+ memcpy(des, iso, isoLen); -+ desLen = NGEncodeQuotedPrintableMime((unsigned char *)bytes, length, -+ (unsigned char *)(des + isoLen), -+ desLen - isoLen); -+ if (desLen != -1) { -+ memcpy(des + isoLen + desLen, isoEnd, isoEndLen); -+ [data appendBytes:des length:(isoLen + desLen + isoEndLen)]; -+ } -+ else { - [self logWithFormat:@"WARNING(%s:%i): An error occour during " - @"quoted-printable decoding", - __PRETTY_FUNCTION__, __LINE__]; -- } -- if (des) free(des); -+ if (des != NULL) free(des); -+ } - } -- else { -- [data appendBytes:ctmp length:len]; -+ else -+ { -+ [data appendBytes:[tmp cString] length:[tmp length]]; - } -- } -- // [data appendBytes:[tmp cString] length:[tmp length]]; -- [data appendBytes:"\"" length:1]; -+ -+ [data appendBytes:"\"" length:1]; - } - return data; - } -Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.m -=================================================================== ---- sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (revision 1632) -+++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (working copy) -@@ -713,6 +713,39 @@ - return ms; - } - -+/* GCSEOAdaptorChannel protocol */ -+static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ -+ @" c_name VARCHAR (256) NOT NULL PRIMARY KEY,\n" -+ @" c_content VARCHAR (100000) NOT NULL,\n" -+ @" c_creationdate INT4 NOT NULL,\n" -+ @" c_lastmodified INT4 NOT NULL,\n" -+ @" c_version INT4 NOT NULL,\n" -+ @" c_deleted INT4 NULL\n" -+ @")"); -+static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \ -+ @" c_uid VARCHAR (256) NOT NULL,\n" -+ @" c_object VARCHAR (256) NOT NULL,\n" -+ @" c_role VARCHAR (80) NOT NULL\n" -+ @")"); -+ -+- (NSException *) createGCSFolderTableWithName: (NSString *) tableName -+{ -+ NSString *sql; -+ -+ sql = [NSString stringWithFormat: sqlFolderFormat, tableName]; -+ -+ return [self evaluateExpressionX: sql]; -+} -+ -+- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName -+{ -+ NSString *sql; -+ -+ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName]; -+ -+ return [self evaluateExpressionX: sql]; -+} -+ - @end /* PostgreSQL72Channel */ - - @implementation PostgreSQL72Channel(PrimaryKeyGeneration) -Index: sope-gdl1/MySQL/MySQL4Channel.m -=================================================================== ---- sope-gdl1/MySQL/MySQL4Channel.m (revision 1632) -+++ sope-gdl1/MySQL/MySQL4Channel.m (working copy) -@@ -755,6 +755,39 @@ - return pkey; - } - -+/* GCSEOAdaptorChannel protocol */ -+static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ -+ @" c_name VARCHAR (256) NOT NULL PRIMARY KEY,\n" -+ @" c_content VARCHAR (100000) NOT NULL,\n" -+ @" c_creationdate INT NOT NULL,\n" -+ @" c_lastmodified INT NOT NULL,\n" -+ @" c_version INT NOT NULL,\n" -+ @" c_deleted INT NULL\n" -+ @")"); -+static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \ -+ @" c_uid VARCHAR (256) NOT NULL,\n" -+ @" c_object VARCHAR (256) NOT NULL,\n" -+ @" c_role VARCHAR (80) NOT NULL\n" -+ @")"); -+ -+- (NSException *) createGCSFolderTableWithName: (NSString *) tableName -+{ -+ NSString *sql; -+ -+ sql = [NSString stringWithFormat: sqlFolderFormat, tableName]; -+ -+ return [self evaluateExpressionX: sql]; -+} -+ -+- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName -+{ -+ NSString *sql; -+ -+ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName]; -+ -+ return [self evaluateExpressionX: sql]; -+} -+ - @end /* MySQL4Channel */ - - void __link_MySQL4Channel() { -Index: sope-gdl1/GDLAccess/EOAdaptor.m -=================================================================== ---- sope-gdl1/GDLAccess/EOAdaptor.m (revision 1632) -+++ sope-gdl1/GDLAccess/EOAdaptor.m (working copy) -@@ -202,6 +202,7 @@ - if ([_scheme isEqualToString:@"sybase"]) return @"Sybase10"; - if ([_scheme isEqualToString:@"sqlite"]) return @"SQLite3"; - if ([_scheme isEqualToString:@"oracle"]) return @"Oracle8"; -+ if ([_scheme isEqualToString:@"mysql"]) return @"MySQL"; - - if ([_scheme isEqualToString:@"http"]) { - NSLog(@"WARNING(%s): asked for 'http' URL, " -Index: sope-gdl1/Oracle8/OracleAdaptorChannel.m -=================================================================== ---- sope-gdl1/Oracle8/OracleAdaptorChannel.m (revision 1632) -+++ sope-gdl1/Oracle8/OracleAdaptorChannel.m (working copy) -@@ -1,7 +1,7 @@ - /* - ** OracleAdaptorChannel.m - ** --** Copyright (c) 2007 Inverse groupe conseil inc. and Ludovic Marcotte -+** Copyright (c) 2007-2009 Inverse inc. and Ludovic Marcotte - ** - ** Author: Ludovic Marcotte - ** -@@ -30,6 +30,11 @@ - - #import - -+#include -+ -+static BOOL debugOn = NO; -+static int maxTry = 3; -+static int maxSleep = 500; - // - // - // -@@ -41,10 +46,11 @@ - - @implementation OracleAdaptorChannel (Private) - --- (void) _cleanup -+- (void) _cleanup - { - column_info *info; - int c; -+ sword result; - - [_resultSetProperties removeAllObjects]; - -@@ -58,11 +64,29 @@ - // so we just free the value instead. - if (info->value) - { -- if (OCIDescriptorFree((dvoid *)info->value, (ub4)OCI_DTYPE_LOB) != OCI_SUCCESS) -+ if (info->type == SQLT_CLOB -+ || info->type == SQLT_BLOB -+ || info->type == SQLT_BFILEE -+ || info->type == SQLT_CFILEE) -+ { -+ result = OCIDescriptorFree((dvoid *)info->value, (ub4) OCI_DTYPE_LOB); -+ if (result != OCI_SUCCESS) -+ { -+ NSLog (@"value was not a LOB descriptor"); -+ abort(); -+ } -+ } -+ else - free(info->value); - info->value = NULL; - } -- free(info); -+ else -+ { -+ NSLog (@"trying to free an already freed value!"); -+ abort(); -+ } -+ free(info); -+ - [_row_buffer removeObjectAtIndex: c]; - } - -@@ -78,8 +102,7 @@ - // - @implementation OracleAdaptorChannel - --static void --DBTerminate() -+static void DBTerminate() - { - if (OCITerminate(OCI_DEFAULT)) - NSLog(@"FAILED: OCITerminate()"); -@@ -89,6 +112,11 @@ - - + (void) initialize - { -+ NSUserDefaults *ud; -+ -+ ud = [NSUserDefaults standardUserDefaults]; -+ debugOn = [ud boolForKey: @"OracleAdaptorDebug"]; -+ - // We Initialize the OCI process environment. - if (OCIInitialize((ub4)OCI_DEFAULT, (dvoid *)0, - (dvoid * (*)(dvoid *, size_t)) 0, -@@ -156,14 +184,17 @@ - [super closeChannel]; - - // We logoff from the database. -- if (OCILogoff(_oci_ctx, _oci_err)) -+ if (!_oci_ctx || !_oci_err || OCILogoff(_oci_ctx, _oci_err)) - { - NSLog(@"FAILED: OCILogoff()"); - } - -+ if (_oci_ctx) -+ OCIHandleFree(_oci_ctx, OCI_HTYPE_SVCCTX); - -- OCIHandleFree(_oci_ctx, OCI_HTYPE_SVCCTX); -- OCIHandleFree(_oci_err, OCI_HTYPE_ERROR); -+ if (_oci_err) -+ OCIHandleFree(_oci_err, OCI_HTYPE_ERROR); -+ - // OCIHandleFree(_oci_env, OCI_HTYPE_ENV); - - _oci_ctx = (OCISvcCtx *)0; -@@ -177,7 +208,8 @@ - // - - (void) dealloc - { -- //NSLog(@"OracleAdaptorChannel: -dealloc"); -+ if (debugOn) -+ NSLog(@"OracleAdaptorChannel: -dealloc"); - - [self _cleanup]; - -@@ -222,7 +254,7 @@ - { - EOAttribute *attribute; - OCIParam *param; -- -+ int rCount; - column_info *info; - ub4 i, clen, count; - text *sql, *cname; -@@ -231,6 +263,9 @@ - - [self _cleanup]; - -+ if (debugOn) -+ [self logWithFormat: @"expression: %@", theExpression]; -+ - if (!theExpression || ![theExpression length]) - { - [NSException raise: @"OracleInvalidExpressionException" -@@ -244,7 +279,9 @@ - } - - sql = (text *)[theExpression UTF8String]; -- -+ -+ rCount = 0; -+ retry: - // We alloc our statement handle - if ((status = OCIHandleAlloc((dvoid *)_oci_env, (dvoid **)&_current_stm, (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0))) - { -@@ -264,13 +301,39 @@ - // We check if we're doing a SELECT and if so, we're fetching data! - OCIAttrGet(_current_stm, OCI_HTYPE_STMT, &type, 0, OCI_ATTR_STMT_TYPE, _oci_err); - self->isFetchInProgress = (type == OCI_STMT_SELECT ? YES : NO); -- -+ - // We execute our statement. Not that we _MUST_ set iter to 0 for non-SELECT statements. - if ((status = OCIStmtExecute(_oci_ctx, _current_stm, _oci_err, (self->isFetchInProgress ? (ub4)0 : (ub4)1), (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, - ([(OracleAdaptorContext *)[self adaptorContext] autoCommit] ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT)))) - { -+ ub4 serverStatus; -+ - checkerr(_oci_err, status); - NSLog(@"Statement execute failed (OCI_ERROR): %@", theExpression); -+ -+ // We check to see if we lost connection and need to reconnect. -+ serverStatus = 0; -+ OCIAttrGet((dvoid *)_oci_env, OCI_HTYPE_SERVER, (dvoid *)&serverStatus, (ub4 *)0, OCI_ATTR_SERVER_STATUS, _oci_err); -+ -+ if (serverStatus == OCI_SERVER_NOT_CONNECTED) -+ { -+ // We cleanup our previous handles -+ [self cancelFetch]; -+ [self closeChannel]; -+ -+ // We try to reconnect a couple of times before giving up... -+ while (rCount < maxTry) -+ { -+ usleep(maxSleep); -+ rCount++; -+ -+ if ([self openChannel]) -+ { -+ NSLog(@"Connection re-established to Oracle - retrying to process the statement."); -+ goto retry; -+ } -+ } -+ } - return NO; - } - -@@ -302,7 +365,9 @@ - // We read the maximum width of a column - info->max_width = 0; - status = OCIAttrGet((dvoid*)param, (ub4)OCI_DTYPE_PARAM, (dvoid*)&(info->max_width), (ub4 *)0, (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)_oci_err); -- -+ -+ if (debugOn) -+ NSLog(@"name: %s, type: %d", cname, info->type); - attribute = [EOAttribute attributeWithOracleType: info->type name: cname length: clen width: info->max_width]; - [_resultSetProperties addObject: attribute]; - -@@ -394,16 +459,17 @@ - return NO; - } - -- - if (OCIEnvInit((OCIEnv **)&_oci_env, (ub4)OCI_DEFAULT, (size_t)0, (dvoid **)0)) - { - NSLog(@"FAILED: OCIEnvInit()"); -+ [self closeChannel]; - return NO; - } - - if (OCIHandleAlloc((dvoid *)_oci_env, (dvoid *)&_oci_err, (ub4)OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0)) - { - NSLog(@"FAILED: OCIHandleAlloc() on errhp"); -+ [self closeChannel]; - return NO; - } - -@@ -414,7 +480,10 @@ - // Under Oracle 10g, the third parameter of OCILogon() has the form: [//]host[:port][/service_name] - // See http://download-west.oracle.com/docs/cd/B12037_01/network.101/b10775/naming.htm#i498306 for - // all juicy details. -- database = [[NSString stringWithFormat:@"%@:%@", [o serverName], [o port]] UTF8String]; -+ if ([o serverName] && [o port]) -+ database = [[NSString stringWithFormat:@"%@:%@/%@", [o serverName], [o port], [o databaseName]] UTF8String]; -+ else -+ database = [[o databaseName] UTF8String]; - - // We logon to the database. - if (OCILogon(_oci_env, _oci_err, &_oci_ctx, (const OraText*)username, strlen(username), -@@ -422,6 +491,7 @@ - { - NSLog(@"FAILED: OCILogon(). username = %s password = %s" - @" database = %s", username, password, database); -+ [self closeChannel]; - return NO; - } - -@@ -438,6 +508,11 @@ - { - sword status; - -+ // We check if our connection is open prior to trying to fetch any data. OCIStmtFetch2() returns -+ // NO error code if the OCI environment is set up but the OCILogon() has failed. -+ if (![self isOpen]) -+ return nil; -+ - status = OCIStmtFetch2(_current_stm, _oci_err, (ub4)1, (ub4)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); - - if (status == OCI_NO_DATA) -@@ -609,7 +684,7 @@ - - /* GCSEOAdaptorChannel protocol */ - static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ -- @" c_name VARCHAR2 (256) NOT NULL,\n" -+ @" c_name VARCHAR2 (256) NOT NULL PRIMARY KEY,\n" - @" c_content CLOB NOT NULL,\n" - @" c_creationdate INTEGER NOT NULL,\n" - @" c_lastmodified INTEGER NOT NULL,\n" -Index: sope-gdl1/Oracle8/OracleAdaptorChannelController.m -=================================================================== ---- sope-gdl1/Oracle8/OracleAdaptorChannelController.m (revision 1632) -+++ sope-gdl1/Oracle8/OracleAdaptorChannelController.m (working copy) -@@ -31,6 +31,8 @@ - #import - #import - -+static BOOL debugOn = NO; -+ - // - // - // -@@ -48,6 +50,14 @@ - // - @implementation OracleAdaptorChannelController - -++ (void) initialize -+{ -+ NSUserDefaults *ud; -+ -+ ud = [NSUserDefaults standardUserDefaults]; -+ debugOn = [ud boolForKey: @"OracleAdaptorDebug"]; -+} -+ - - (EODelegateResponse) adaptorChannel: (id) theChannel - willInsertRow: (NSMutableDictionary *) theRow - forEntity: (EOEntity *) theEntity -@@ -56,7 +66,8 @@ - NSArray *keys; - int i, c; - -- NSLog(@"willInsertRow: %@ %@", [theRow description], [theEntity description]); -+ if (debugOn) -+ NSLog(@"willInsertRow: %@ %@", [theRow description], [theEntity description]); - - s = AUTORELEASE([[NSMutableString alloc] init]); - -@@ -101,7 +112,8 @@ - NSArray *keys; - int i, c; - -- NSLog(@"willUpdatetRow: %@ %@", [theRow description], [theQualifier description]); -+ if (debugOn) -+ NSLog(@"willUpdateRow: %@ %@", [theRow description], [theQualifier description]); - - s = AUTORELEASE([[NSMutableString alloc] init]); - -Index: sope-core/NGExtensions/NGExtensions/NSString+Ext.h -=================================================================== ---- sope-core/NGExtensions/NGExtensions/NSString+Ext.h (revision 1632) -+++ sope-core/NGExtensions/NGExtensions/NSString+Ext.h (working copy) -@@ -30,6 +30,7 @@ - - @interface NSString(GSAdditions) - -+#if !GNUSTEP - - (NSString *)stringWithoutPrefix:(NSString *)_prefix; - - (NSString *)stringWithoutSuffix:(NSString *)_suffix; - -@@ -39,6 +40,7 @@ - - (NSString *)stringByTrimmingLeadSpaces; - - (NSString *)stringByTrimmingTailSpaces; - - (NSString *)stringByTrimmingSpaces; -+#endif /* !GNUSTEP */ - - /* the following are not available in gstep-base 1.6 ? */ - - (NSString *)stringByTrimmingLeadWhiteSpaces; -@@ -47,6 +49,8 @@ - - @end /* NSString(GSAdditions) */ - -+#if !GNUSTEP -+ - @interface NSMutableString(GNUstepCompatibility) - - - (void)trimLeadSpaces; -@@ -55,6 +59,8 @@ - - @end /* NSMutableString(GNUstepCompatibility) */ - -+#endif /* !GNUSTEP */ -+ - #endif - - /* specific to libFoundation */ -Index: sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m -=================================================================== ---- sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (revision 1632) -+++ sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (working copy) -@@ -39,18 +39,6 @@ - : (NSString *)[[self copy] autorelease]; - } - --- (NSString *)stringByReplacingString:(NSString *)_orignal -- withString:(NSString *)_replacement --{ -- /* very slow solution .. */ -- -- if ([self rangeOfString:_orignal].length == 0) -- return [[self copy] autorelease]; -- -- return [[self componentsSeparatedByString:_orignal] -- componentsJoinedByString:_replacement]; --} -- - - (NSString *)stringByTrimmingLeadWhiteSpaces - { - // should check 'whitespaceAndNewlineCharacterSet' .. -@@ -96,6 +84,25 @@ - return [[self copy] autorelease]; - } - -+- (NSString *)stringByTrimmingWhiteSpaces -+{ -+ return [[self stringByTrimmingTailWhiteSpaces] -+ stringByTrimmingLeadWhiteSpaces]; -+} -+ -+#ifndef GNUSTEP -+- (NSString *)stringByReplacingString:(NSString *)_orignal -+ withString:(NSString *)_replacement -+{ -+ /* very slow solution .. */ -+ -+ if ([self rangeOfString:_orignal].length == 0) -+ return [[self copy] autorelease]; -+ -+ return [[self componentsSeparatedByString:_orignal] -+ componentsJoinedByString:_replacement]; -+} -+ - - (NSString *)stringByTrimmingLeadSpaces - { - unsigned len; -@@ -117,6 +124,7 @@ - else - return [[self copy] autorelease]; - } -+ - - (NSString *)stringByTrimmingTailSpaces - { - unsigned len; -@@ -139,19 +147,17 @@ - return [[self copy] autorelease]; - } - --- (NSString *)stringByTrimmingWhiteSpaces --{ -- return [[self stringByTrimmingTailWhiteSpaces] -- stringByTrimmingLeadWhiteSpaces]; --} - - (NSString *)stringByTrimmingSpaces - { - return [[self stringByTrimmingTailSpaces] - stringByTrimmingLeadSpaces]; - } -+#endif - - @end /* NSString(GSAdditions) */ - -+#if !GNUSTEP -+ - @implementation NSMutableString(GNUstepCompatibility) - - - (void)trimLeadSpaces -@@ -169,6 +175,8 @@ - - @end /* NSMutableString(GNUstepCompatibility) */ - -+#endif /* !GNUSTEP */ -+ - @implementation NSString(lfNSURLUtilities) - - - (BOOL)isAbsoluteURL -Index: sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m -=================================================================== ---- sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (revision 1632) -+++ sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (working copy) -@@ -140,8 +140,12 @@ - - - #ifdef __linux__ -+#if __BYTE_ORDER == __LITTLE_ENDIAN - static NSString *unicharEncoding = @"UCS-2LE"; - #else -+static NSString *unicharEncoding = @"UCS-2BE"; -+#endif /* __BYTE_ORDER */ -+#else - static NSString *unicharEncoding = @"UCS-2-INTERNAL"; - #endif - static int IconvLogEnabled = -1; -@@ -149,21 +153,12 @@ - static void checkDefaults(void) { - NSUserDefaults *ud; - -- if (IconvLogEnabled != -1) -- return; -- ud = [NSUserDefaults standardUserDefaults]; -- IconvLogEnabled = [ud boolForKey:@"IconvLogEnabled"]?1:0; -+ if (IconvLogEnabled == -1) { -+ ud = [NSUserDefaults standardUserDefaults]; -+ IconvLogEnabled = [ud boolForKey:@"IconvLogEnabled"]?1:0; - --#ifdef __linux__ -- if (NSHostByteOrder() == NS_BigEndian) { -- NSLog(@"Note: using UCS-2 big endian on Linux."); -- unicharEncoding = @"UCS-2BE"; -+ NSLog(@"Note: using '%@' on Linux.", unicharEncoding); - } -- else { -- NSLog(@"Note: using UCS-2 little endian on Linux."); -- unicharEncoding = @"UCS-2LE"; -- } --#endif - } - - static char *iconv_wrapper(id self, char *_src, unsigned _srcLen, -Index: sope-core/NGExtensions/NGCalendarDateRange.m -=================================================================== ---- sope-core/NGExtensions/NGCalendarDateRange.m (revision 1632) -+++ sope-core/NGExtensions/NGCalendarDateRange.m (working copy) -@@ -50,6 +50,12 @@ - return self; - } - -+- (void)dealloc { -+ [self->startDate release]; -+ [self->endDate release]; -+ [super dealloc]; -+} -+ - /* NSCopying */ - - - (id)copyWithZone:(NSZone *)zone { -Index: sope-core/NGExtensions/NGQuotedPrintableCoding.m -=================================================================== ---- sope-core/NGExtensions/NGQuotedPrintableCoding.m (revision 1632) -+++ sope-core/NGExtensions/NGQuotedPrintableCoding.m (working copy) -@@ -278,7 +278,12 @@ - - for (cnt = 0; (cnt < _srcLen) && (destCnt < _destLen); cnt++) { - char c = _src[cnt]; -- if ((c == 9) || -+ if (c == 95) { // we encode the _, otherwise we'll always decode it as a space! -+ _dest[destCnt++] = '='; -+ _dest[destCnt++] = '5'; -+ _dest[destCnt++] = 'F'; -+ } -+ else if ((c == 9) || - (c == 10) || - (c == 13) || - ((c > 31) && (c < 61)) || -Index: sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m -=================================================================== ---- sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (revision 1632) -+++ sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (working copy) -@@ -19,6 +19,7 @@ - 02111-1307, USA. - */ - -+#import - #import - #import - -Index: sope-core/NGExtensions/ChangeLog -=================================================================== ---- sope-core/NGExtensions/ChangeLog (revision 1632) -+++ sope-core/NGExtensions/ChangeLog (working copy) -@@ -1,3 +1,8 @@ -+2009-03-24 Wolfgang Sourdeau -+ -+ * NGCalendarDateRange.m ([NGCalendarDateRange -dealloc]): release -+ endDate and startDate. -+ - 2008-03-11 Helge Hess - - * FdExt.subproj/NSArray+enumerator.m: fixed for MacOS 10.5 (v4.7.201) -Index: sope-core/NGStreams/GNUmakefile.preamble -=================================================================== ---- sope-core/NGStreams/GNUmakefile.preamble (revision 1632) -+++ sope-core/NGStreams/GNUmakefile.preamble (working copy) -@@ -1,7 +1,10 @@ - # compilation settings - -+MACHCPU = $(shell echo $$MACHTYPE | cut -f 1 -d '-') -+ - libNGStreams_INCLUDE_DIRS += \ - -I$(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS) \ -+ -I./$(MACHCPU)/$(GNUSTEP_TARGET_OS) \ - -INGStreams \ - -I../NGExtensions \ - -I.. -Index: sope-xml/libxmlSAXDriver/ChangeLog -=================================================================== ---- sope-xml/libxmlSAXDriver/ChangeLog (revision 1632) -+++ sope-xml/libxmlSAXDriver/ChangeLog (working copy) -@@ -1,3 +1,8 @@ -+2009-03-24 Wolfgang Sourdeau -+ -+ * libxmlSAXDriver.m (_startElement): autorelease "nsDict" when its -+ instantiated from a copy of "ns". -+ - 2006-07-03 Helge Hess - - * libXMLSaxDriver.m: fixed last changes for libFoundation (v4.5.24) -Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h -=================================================================== ---- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (revision 1632) -+++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (working copy) -@@ -19,6 +19,8 @@ - 02111-1307, USA. - */ - -+#include -+ - #include - #include - #include -@@ -34,7 +36,7 @@ - - @interface libxmlHTMLSAXDriver : NSObject < SaxXMLReader > - { -- id contentHandler; -+ NSObject *contentHandler; - id dtdHandler; - id errorHandler; - id entityResolver; -Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m -=================================================================== ---- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (revision 1632) -+++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (working copy) -@@ -30,6 +30,12 @@ - #include - #include - -+@interface NSObject (contentHandlerExtensions) -+ -+- (xmlCharEncoding) contentEncoding; -+ -+@end -+ - @interface libxmlHTMLSAXDriver(PrivateMethods) - - - (void)tearDownParser; -@@ -194,10 +200,10 @@ - return self->entityResolver; - } - --- (void)setContentHandler:(id)_handler { -+- (void)setContentHandler:(NSObject *)_handler { - ASSIGN(self->contentHandler, _handler); - } --- (id)contentHandler { -+- (NSObject *)contentHandler { - return self->contentHandler; - } - -@@ -205,6 +211,7 @@ - - - (void)setupParserWithDocumentPath:(NSString *)_path { - xmlSAXHandler sax; -+ xmlCharEncoding charEncoding; - - if (self->ctxt != NULL) { - NSLog(@"WARNING(%s): HTML parser context already setup !", -@@ -223,14 +230,18 @@ - __PRETTY_FUNCTION__, self, activeDriver); - } - activeDriver = self; -- -+ -+ if ([self->contentHandler respondsToSelector: @selector (contentEncoding)]) -+ charEncoding = [self->contentHandler contentEncoding]; -+ else -+ charEncoding = XML_CHAR_ENCODING_8859_1; -+ - self->ctxt = htmlCreatePushParserCtxt(&sax /* sax */, - NULL /*self*/ /* userdata */, - NULL /* chunk */, - 0 /* chunklen */, - [_path cString] /* filename */, -- XML_CHAR_ENCODING_8859_1 -- /* encoding */); -+ charEncoding /* encoding */); - self->doc = NULL; - } - - (void)tearDownParser { -Index: sope-xml/libxmlSAXDriver/libxmlSAXDriver.m -=================================================================== ---- sope-xml/libxmlSAXDriver/libxmlSAXDriver.m (revision 1632) -+++ sope-xml/libxmlSAXDriver/libxmlSAXDriver.m (working copy) -@@ -614,7 +614,7 @@ - xmlParseDocument(ctxt); - - if (!(((xmlParserCtxtPtr)self->ctxt)->wellFormed)) -- NSLog(@"%@: not well formed", _sysId); -+ NSLog(@"%@: not well formed 1", _sysId); - - if (((xmlParserCtxtPtr)self->ctxt)->input != NULL && [_sysId length] > 0) { - ((xmlParserInputPtr)((xmlParserCtxtPtr)self->ctxt)->input)->filename -@@ -737,7 +737,7 @@ - } - - if (!(((xmlParserCtxtPtr)self->ctxt)->wellFormed)) -- NSLog(@"%@: not well formed", _sysId); -+ NSLog(@"%@: not well formed 2", _sysId); - - ((xmlParserCtxtPtr)self->ctxt)->sax = NULL; - xmlFreeParserCtxt(self->ctxt); -@@ -872,6 +872,7 @@ - } - - nsDict = [ns copy]; -+ [nsDict autorelease]; - [ns release]; - } - -Index: sope-appserver/mod_ngobjweb/config.c -=================================================================== ---- sope-appserver/mod_ngobjweb/config.c (revision 1632) -+++ sope-appserver/mod_ngobjweb/config.c (working copy) -@@ -21,7 +21,7 @@ - - #include "common.h" - --//#define LOG_CONFIG 1 -+#define LOG_CONFIG 0 - - static char *_makeString(char *buf, char *str, int max) { - if (buf == NULL) -Index: sope-appserver/mod_ngobjweb/GNUmakefile -=================================================================== ---- sope-appserver/mod_ngobjweb/GNUmakefile (revision 1632) -+++ sope-appserver/mod_ngobjweb/GNUmakefile (working copy) -@@ -82,7 +82,7 @@ - - CFLAGS = -Wall -I. -fPIC \ - $(APXS_CFLAGS) $(APR_CFLAGS) \ -- $(APXS_INCLUDE_DIRS) $(APR_INCLUDE_DIRS) -+ $(APXS_INCLUDE_DIRS) $(APR_INCLUDE_DIRS) -O0 -ggdb - - LDFLAGS = $(APXS_LDFLAGS) $(APR_LDFLAGS) -shared -fPIC - LDLIBS = $(APXS_LIBS) $(APR_LIBS) -@@ -111,8 +111,7 @@ - apache-dir : - $(MKDIRS) $(GNUSTEP_INSTALLATION_DIR) - --install :: apache-dir all -- $(INSTALL_PROGRAM) $(product) $(GNUSTEP_INSTALLATION_DIR) -+install :: - - install-usr-libexec :: all - $(INSTALL_PROGRAM) $(product) /usr/libexec/httpd/ -Index: sope-appserver/mod_ngobjweb/NGBufferedDescriptor.c -=================================================================== ---- sope-appserver/mod_ngobjweb/NGBufferedDescriptor.c (revision 1632) -+++ sope-appserver/mod_ngobjweb/NGBufferedDescriptor.c (working copy) -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include "common.h" - #include "NGBufferedDescriptor.h" - - // returns the number of bytes which where read from the buffer -Index: sope-appserver/NGObjWeb/GNUmakefile.postamble -=================================================================== ---- sope-appserver/NGObjWeb/GNUmakefile.postamble (revision 1632) -+++ sope-appserver/NGObjWeb/GNUmakefile.postamble (working copy) -@@ -23,14 +23,20 @@ - - # install makefiles - --after-install :: -- $(MKDIRS) $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional/ -- $(INSTALL_DATA) ngobjweb.make $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make -+after-install :: $(DESTDIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make - - ifneq ($(GNUSTEP_MAKE_VERSION),1.3.0) --after-install :: -+after-install :: $(DESTDIR)/$(GNUSTEP_MAKEFILES)/woapp.make $(DESTDIR)/$(GNUSTEP_MAKEFILES)/wobundle.make -+endif -+ -+$(DESTDIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make: ngobjweb.make -+ $(MKDIRS) $(DESTDIR)/$(GNUSTEP_MAKEFILES)/Additional/ -+ $(INSTALL_DATA) ngobjweb.make $(DESTDIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make -+ -+$(DESTDIR)/$(GNUSTEP_MAKEFILES)/woapp.make: woapp-gs.make - $(INSTALL_DATA) woapp-gs.make \ -- $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/woapp.make -+ $(DESTDIR)/$(GNUSTEP_MAKEFILES)/woapp.make -+ -+$(DESTDIR)/$(GNUSTEP_MAKEFILES)/wobundle.make: wobundle-gs.make - $(INSTALL_DATA) wobundle-gs.make \ -- $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/wobundle.make --endif -+ $(DESTDIR)/$(GNUSTEP_MAKEFILES)/wobundle.make -Index: sope-appserver/NGObjWeb/WOContext.m -=================================================================== ---- sope-appserver/NGObjWeb/WOContext.m (revision 1632) -+++ sope-appserver/NGObjWeb/WOContext.m (working copy) -@@ -64,11 +64,13 @@ - static BOOL testNSURLs = NO; - static BOOL newCURLStyle = NO; - static NSString *WOApplicationSuffix = nil; -+static NSURL *redirectURL = nil; - - + (void)initialize { - static BOOL didInit = NO; - NSUserDefaults *ud; - NSString *cn; -+ NSString *url; - - if (didInit) return; - -@@ -91,6 +93,9 @@ - debugCursor = [ud boolForKey:@"WODebugCursor"] ? 1 : 0; - debugComponentAwake = [ud boolForKey:@"WODebugComponentAwake"]; - WOApplicationSuffix = [[ud stringForKey:@"WOApplicationSuffix"] copy]; -+ url = [ud stringForKey:@"WOApplicationRedirectURL"]; -+ if (url != nil) -+ redirectURL = [NSURL URLWithString: url]; - } - - + (id)contextWithRequest:(WORequest *)_r { -@@ -503,6 +508,11 @@ - return nil; - } - -+ if (redirectURL) { -+ // Use URL from user defaults (WOApplicationRedirectURL) -+ return redirectURL; -+ } -+ - if ((serverURL = [rq headerForKey:@"x-webobjects-server-url"]) == nil) { - if ((host = [rq headerForKey:@"host"])) - serverURL = [@"http://" stringByAppendingString:host]; -Index: sope-appserver/NGObjWeb/ChangeLog -=================================================================== ---- sope-appserver/NGObjWeb/ChangeLog (revision 1632) -+++ sope-appserver/NGObjWeb/ChangeLog (working copy) -@@ -1,3 +1,9 @@ -+2009-03-24 Wolfgang Sourdeau -+ -+ * SoObjects/SoActionInvocation.m ([SoActionInvocation -+ -bindToObject:inContext:]): do not retain methodObject when -+ instantiated since it is not autoreleased. -+ - 2008-12-11 Helge Hess - - * WOHttpAdaptor/WOHttpAdaptor.m: properly embed threaded request -@@ -3,4 +9,9 @@ - handler in a top-level pool (v4.7.27) - -+2008-09-01 Ludovic Marcotte -+ -+ * WORequest.m ([WORequest -browserLanguages]): we ensure -+ "language" never is an empty string, otherwise we ignore it. -+ - 2008-05-21 Sebastian Reitenbach - -Index: sope-appserver/NGObjWeb/DAVPropMap.plist -=================================================================== ---- sope-appserver/NGObjWeb/DAVPropMap.plist (revision 1632) -+++ sope-appserver/NGObjWeb/DAVPropMap.plist (working copy) -@@ -24,13 +24,19 @@ - "{DAV:}status" = "davStatus"; - "{http://apache.org/dav/props/}executable" = "davIsExecutable"; - -+ /* RFC 3253 - Versioning Extensions to WebDAV (DeltaV) */ -+ "{DAV:}comment" = "davComment"; -+ "{DAV:}creator-displayname" = "davCreatorDisplayName"; -+ "{DAV:}supported-method-set" = "davSupportedMethodSet"; -+ "{DAV:}supported-live-property-set" = "davSupportedLivePropertySet"; -+ "{DAV:}supported-report-set" = "davSupportedReportSet"; -+ - /* used with Apple WebDAV */ - "{DAV:}quota" = davQuota; - "{DAV:}quotaused" = davQuotaUsed; - "{http://www.apple.com/webdav_fs/props/}appledoubleheader"=appleDoubleHeader; - - /* Novell NetDrive */ -- "{DAV:}owner" = davOwner; - "{DAV:}locktoken" = davLockToken; - "{DAV:}activelock" = davActiveLock; - // TODO: non-standard?, also used by WebDrive -@@ -120,12 +126,31 @@ - "{http://ucb.openoffice.org/dav/props/}IsRemoveable" = isOOoRemoveable; - "{http://ucb.openoffice.org/dav/props/}IsVolume" = isOOoVolume; - "{http://ucb.openoffice.org/dav/props/}TargetURL" = davOOoTargetURL; -- -+ - /* WebDAV ACL */ -+ "{DAV:}owner" = davOwner; -+ "{DAV:}group" = davGroup; -+ "{DAV:}supported-privilege-set" = davSupportedPrivilegeSet; -+ "{DAV:}principal-collection-set" = davPrincipalCollectionSet; -+ "{DAV:}acl" = davAcl; -+ "{DAV:}acl-restrictions" = davAclRestrictions; - "{DAV:}current-user-privilege-set" = davCurrentUserPrivilegeSet; -+ "{DAV:}inherited-acl-set" = davInheritedAclSet; -+ "{DAV:}principal-URL" = davPrincipalURL; -+ "{DAV:}alternate-URI-set" = davAlternateURISet; -+ "{DAV:}group-member-set" = davGroupMemberSet; -+ "{DAV:}group-membership" = davGroupMembership; - - /* CalDAV */ -+ "{urn:ietf:params:xml:ns:caldav}calendar-data" = davCalendarData; -+ "{urn:ietf:params:xml:ns:caldav}calendar-description" = davDescription; - "{urn:ietf:params:xml:ns:caldav}calendar-home-set" = davCalendarHomeSet; -+ "{urn:ietf:params:xml:ns:caldav}calendar-user-address-set" = -+ davCalendarUserAddressSet; -+ "{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set" = -+ davCalendarFreeBusySet; -+ "{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL" = davCalendarScheduleInboxURL; -+ "{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL" = davCalendarScheduleOutboxURL; - "{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set" = - davCalendarComponentSet; - "{urn:ietf:params:xml:ns:caldav}supported-calendar-data" = -@@ -133,18 +158,20 @@ - "{urn:ietf:params:xml:ns:caldav}calendar-description" = davDescription; - - /* CardDAV */ -+ "{urn:ietf:params:xml:ns:carddav}addressbook-home-set" = davAddressbookHomeSet; - "{urn:ietf:params:xml:ns:carddav}supported-address-data" = - davSupportedAddressDataTypes; - "{urn:ietf:params:xml:ns:carddav}addressbook-description" = davDescription; - - /* Apple CalServer */ -- "{http://apple.com/ns/calendarserver/}dropbox-home-URL" = -- davDropboxHomeURL; -- "{http://apple.com/ns/calendarserver/}notifications-URL" = -- davNotificationsURL; -- "{com.apple.ical:}calendarcolor" = davCalendarColor; -+ "{http://calendarserver.org/ns/}dropbox-home-URL" = davDropboxHomeURL; -+ "{http://calendarserver.org/ns/}notifications-URL" = davNotificationsURL; - "{http://calendarserver.org/ns/}getctag" = davCollectionTag; - -+ /* Apple extensions */ -+ "{http://apple.com/ns/ical/}calendar-color" = davCalendarColor; -+ "{http://apple.com/ns/ical/}calendar-order" = davCalendarOrder; -+ - /* GroupDAV */ - "{http://www.groupdav.org/}component-set" = gdavComponentSet; - "{http://groupdav.org/}component-set" = gdavComponentSet; -Index: sope-appserver/NGObjWeb/WebDAV/SaxDAVHandler.m -=================================================================== ---- sope-appserver/NGObjWeb/WebDAV/SaxDAVHandler.m (revision 1632) -+++ sope-appserver/NGObjWeb/WebDAV/SaxDAVHandler.m (working copy) -@@ -655,6 +655,7 @@ - if (self->responses == nil) - self->responses = [[NSMutableArray alloc] initWithCapacity:64]; - } -+ - break; - - case 'n': -Index: sope-appserver/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.m -=================================================================== ---- sope-appserver/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.m (revision 1632) -+++ sope-appserver/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.m (working copy) -@@ -1523,16 +1523,16 @@ - - (id)doREPORT:(WOContext *)_ctx { - id domDocument; - WORequest *rq; -- NSString *mname; -+ NSString *mname, *ctype; - id method, resultObject; - - rq = [_ctx request]; - - /* ensure XML */ - -- if ((![[rq headerForKey:@"content-type"] hasPrefix:@"text/xml"]) && -- (![[rq headerForKey:@"content-type"] hasPrefix:@"application/xml"])) -- { -+ ctype = [rq headerForKey:@"content-type"]; -+ if (!([ctype hasPrefix:@"text/xml"] -+ || [ctype hasPrefix:@"application/xml"])) { - return [self httpException:400 /* invalid request */ - reason:@"XML entity expected for WebDAV REPORT."]; - } -@@ -1601,8 +1601,60 @@ - /* CalDAV */ - - - (id)doMKCALENDAR:(WOContext *)_ctx { -- return [self httpException:405 /* method not allowed */ -- reason:@"CalDAV calendar creation not yet implemented."]; -+ SoSecurityManager *sm; -+ NSException *e; -+ NSString *pathInfo; -+ -+ pathInfo = [_ctx pathInfo]; -+ if (![pathInfo isNotEmpty]) { -+ /* MKCALENDAR target already exists ... */ -+ WOResponse *r; -+ -+ [self logWithFormat:@"MKCALENDAR target exists !"]; -+ -+ r = [_ctx response]; -+ [r setStatus:405 /* method not allowed */]; -+ [r appendContentString:@"calendar collection already exists !"]; -+ return r; -+ } -+ -+ /* check permissions */ -+ -+ sm = [_ctx soSecurityManager]; -+ e = [sm validatePermission:SoPerm_AddFolders -+ onObject:self->object -+ inContext:_ctx]; -+ if (e != nil) return e; -+ -+ /* check whether all the parent collections are available */ -+ if ([pathInfo rangeOfString:@"/"].length > 0) { -+ return [self httpException:409 /* Conflict */ -+ reason: -+ @"invalid WebDAV MKCALENDAR request, first create all " -+ @"parent collections !"]; -+ } -+ -+ /* check whether the object supports creating collections */ -+ -+ if (![self->object respondsToSelector: -+ @selector(davCreateCalendarCollection:inContext:)]) { -+ /* Note: this should never happen, as this is implemented on NSObject */ -+ -+ [self logWithFormat:@"MKCALENDAR: object '%@' path-info '%@'", -+ self->object, pathInfo]; -+ return [self httpException:405 /* not allowed */ -+ reason: -+ @"this object cannot create a new calendar collection with MKCALENDAR"]; -+ } -+ -+ if ((e = [self->object davCreateCalendarCollection:pathInfo inContext:_ctx])) { -+ [self debugWithFormat:@"creation of calendar collection '%@' failed: %@", -+ pathInfo, e]; -+ return e; -+ } -+ -+ [self debugWithFormat:@"created calendar collection."]; -+ return [NSNumber numberWithBool:YES]; - } - - /* DAV access control lists */ -Index: sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m -=================================================================== ---- sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m (revision 1632) -+++ sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m (working copy) -@@ -277,7 +277,8 @@ - ok = [self renderLockToken:_object inContext:_ctx]; - break; - case 'M': -- if ([m isEqualToString:@"MKCOL"]) -+ if ([m isEqualToString:@"MKCOL"] -+ || [m isEqualToString:@"MKCALENDAR"]) - ok = [self renderMkColResult:_object inContext:_ctx]; - else if ([m isEqualToString:@"MOVE"]) { - ok = [self renderStatusResult:_object -Index: sope-appserver/NGObjWeb/WebDAV/SoObject+SoDAV.h -=================================================================== ---- sope-appserver/NGObjWeb/WebDAV/SoObject+SoDAV.h (revision 1632) -+++ sope-appserver/NGObjWeb/WebDAV/SoObject+SoDAV.h (working copy) -@@ -62,6 +62,7 @@ - properties:(NSDictionary *)_props - inContext:(id)_ctx; - - (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx; -+- (NSException *)davCreateCalendarCollection:(NSString *)_name inContext:(id)_ctx; - - - (NSException *)davMoveToTargetObject:(id)_target newName:(NSString *)_name - inContext:(id)_ctx; -Index: sope-appserver/NGObjWeb/WODirectAction.m -=================================================================== ---- sope-appserver/NGObjWeb/WODirectAction.m (revision 1632) -+++ sope-appserver/NGObjWeb/WODirectAction.m (working copy) -@@ -46,7 +46,7 @@ - } - - (id)initWithContext:(WOContext *)_ctx { - if ((self = [self initWithRequest:[_ctx request]])) { -- self->context = [_ctx retain]; -+ self->context = _ctx; - } - return self; - } -@@ -54,16 +54,16 @@ - return [self initWithRequest:nil]; - } - --- (void)dealloc { -- [self->context release]; -- [super dealloc]; --} -+// - (void)dealloc { -+// [self->context release]; -+// [super dealloc]; -+// } - - /* accessors */ - - - (WOContext *)context { - if (self->context == nil) -- self->context = [[[WOApplication application] context] retain]; -+ self->context = [[WOApplication application] context]; - return self->context; - } - -Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m -=================================================================== ---- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (revision 1632) -+++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (working copy) -@@ -216,6 +216,12 @@ - assocCount++; - } - } -+ if (count > 0) { -+ if ((self->isAbsolute = OWGetProperty(_config, @"absolute"))) { -+ count--; -+ assocCount++; -+ } -+ } - - self->rest = _config; - -Index: sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m -=================================================================== ---- sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (revision 1632) -+++ sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (working copy) -@@ -41,6 +41,7 @@ - WOAssociation *string; - WOAssociation *target; - WOAssociation *disabled; -+ WOAssociation *isAbsolute; - WOElement *template; - - /* new in WO4: */ -@@ -360,6 +361,7 @@ - { - if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) { - self->href = _info->href; -+ self->isAbsolute = _info->isAbsolute; - } - return self; - } -@@ -375,8 +377,11 @@ - // TODO: we need a binding to disable rewriting! - NSRange r; - -+ if ([[self->isAbsolute valueInContext:_ctx] boolValue] == YES) -+ return NO; -+ - r.length = [_s length]; -- -+ - /* do not rewrite pure fragment URLs */ - if (r.length > 0 && [_s characterAtIndex:0] == '#') - return NO; -Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h -=================================================================== ---- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (revision 1632) -+++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (working copy) -@@ -41,7 +41,8 @@ - WOAssociation *pageName; - WOAssociation *actionClass; - WOAssociation *directActionName; -- -+ WOAssociation *isAbsolute; -+ - BOOL sidInUrl; - - /* 'ivar' associations */ -Index: sope-appserver/NGObjWeb/SoObjects/SoObject.m -=================================================================== ---- sope-appserver/NGObjWeb/SoObjects/SoObject.m (revision 1632) -+++ sope-appserver/NGObjWeb/SoObjects/SoObject.m (working copy) -@@ -39,22 +39,34 @@ - static int debugLookup = -1; - static int debugBaseURL = -1; - static int useRelativeURLs = -1; -+static int redirectInitted = -1; -+static NSURL *redirectURL = nil; -+ - static void _initialize(void) { -+ NSString *url; -+ NSUserDefaults *ud; -+ -+ ud = [NSUserDefaults standardUserDefaults]; -+ - if (debugLookup == -1) { -- debugLookup = [[NSUserDefaults standardUserDefaults] -- boolForKey:@"SoDebugKeyLookup"] ? 1 : 0; -+ debugLookup = [ud boolForKey:@"SoDebugKeyLookup"] ? 1 : 0; - NSLog(@"Note(SoObject): SoDebugKeyLookup is enabled!"); - } - if (debugBaseURL == -1) { -- debugBaseURL = [[NSUserDefaults standardUserDefaults] -- boolForKey:@"SoDebugBaseURL"] ? 1 : 0; -+ debugBaseURL = [ud boolForKey:@"SoDebugBaseURL"] ? 1 : 0; - NSLog(@"Note(SoObject): SoDebugBaseURL is enabled!"); - } - if (useRelativeURLs == -1) { -- useRelativeURLs = [[NSUserDefaults standardUserDefaults] -- boolForKey:@"WOUseRelativeURLs"] ?1:0; -+ useRelativeURLs = [ud boolForKey:@"WOUseRelativeURLs"] ?1:0; - NSLog(@"Note(SoObject): relative base URLs are enabled."); - } -+ if (redirectInitted == -1) { -+ url = [ud stringForKey:@"WOApplicationRedirectURL"]; -+ if ([url length]) { -+ redirectURL = [[NSURL alloc] initWithString: url]; -+ } -+ redirectInitted = 1; -+ } - } - - /* classes */ -@@ -318,56 +330,61 @@ - - rq = [_ctx request]; - ms = [[NSMutableString alloc] initWithCapacity:128]; -+ -+ if (redirectURL) { -+ [ms appendString: [redirectURL absoluteString]]; -+ } -+ else { -+ if (!useRelativeURLs) { -+ port = [[rq headerForKey:@"x-webobjects-server-port"] intValue]; - -- if (!useRelativeURLs) { -- port = [[rq headerForKey:@"x-webobjects-server-port"] intValue]; -- -- /* this is actually a bug in Apache */ -- if (port == 0) { -- static BOOL didWarn = NO; -- if (!didWarn) { -- [self warnWithFormat:@"(%s:%i): got an empty port from Apache!", -- __PRETTY_FUNCTION__, __LINE__]; -- didWarn = YES; -+ /* this is actually a bug in Apache */ -+ if (port == 0) { -+ static BOOL didWarn = NO; -+ if (!didWarn) { -+ [self warnWithFormat:@"(%s:%i): got an empty port from Apache!", -+ __PRETTY_FUNCTION__, __LINE__]; -+ didWarn = YES; -+ } -+ port = 80; - } -- port = 80; -- } - -- if ((tmp = [rq headerForKey:@"host"]) != nil) { -- /* check whether we have a host header with port */ -- if ([tmp rangeOfString:@":"].length == 0) -- tmp = nil; -- } -- if (tmp != nil) { /* we have a host header with port */ -- isHTTPS = -- [[rq headerForKey:@"x-webobjects-server-url"] hasPrefix:@"https"]; -- [ms appendString:isHTTPS ? @"https://" : @"http://"]; -- [ms appendString:tmp]; -- } -- else if ((tmp = [rq headerForKey:@"x-webobjects-server-url"]) != nil) { -- /* sometimes the URL is just wrong! (suggests port 80) */ -- if ([tmp hasSuffix:@":0"] && [tmp length] > 2) { // TODO: bad bad bad -- [self warnWithFormat:@"%s: got incorrect URL from Apache: '%@'", -- __PRETTY_FUNCTION__, tmp]; -- tmp = [tmp substringToIndex:([tmp length] - 2)]; -+ if ((tmp = [rq headerForKey:@"host"]) != nil) { -+ /* check whether we have a host header with port */ -+ if ([tmp rangeOfString:@":"].length == 0) -+ tmp = nil; - } -- else if ([tmp hasSuffix:@":443"] && [tmp hasPrefix:@"http://"]) { -- /* see OGo bug #1435, Debian Apache hack */ -- [self warnWithFormat:@"%s: got 'http' protocol but 443 port, " -- @"assuming Debian/Apache bug (OGo #1435): '%@'", -- __PRETTY_FUNCTION__, tmp]; -- tmp = [tmp substringWithRange:NSMakeRange(4, [tmp length] - 4 - 4)]; -- tmp = [@"https" stringByAppendingString:tmp]; -+ if (tmp != nil) { /* we have a host header with port */ -+ isHTTPS = -+ [[rq headerForKey:@"x-webobjects-server-url"] hasPrefix:@"https"]; -+ [ms appendString:isHTTPS ? @"https://" : @"http://"]; -+ [ms appendString:tmp]; - } -- [ms appendString:tmp]; -- } -- else { -- // TODO: isHTTPS always no in this case? -- [ms appendString:isHTTPS ? @"https://" : @"http://"]; -+ else if ((tmp = [rq headerForKey:@"x-webobjects-server-url"]) != nil) { -+ /* sometimes the URL is just wrong! (suggests port 80) */ -+ if ([tmp hasSuffix:@":0"] && [tmp length] > 2) { // TODO: bad bad bad -+ [self warnWithFormat:@"%s: got incorrect URL from Apache: '%@'", -+ __PRETTY_FUNCTION__, tmp]; -+ tmp = [tmp substringToIndex:([tmp length] - 2)]; -+ } -+ else if ([tmp hasSuffix:@":443"] && [tmp hasPrefix:@"http://"]) { -+ /* see OGo bug #1435, Debian Apache hack */ -+ [self warnWithFormat:@"%s: got 'http' protocol but 443 port, " -+ @"assuming Debian/Apache bug (OGo #1435): '%@'", -+ __PRETTY_FUNCTION__, tmp]; -+ tmp = [tmp substringWithRange:NSMakeRange(4, [tmp length] - 4 - 4)]; -+ tmp = [@"https" stringByAppendingString:tmp]; -+ } -+ [ms appendString:tmp]; -+ } -+ else { -+ // TODO: isHTTPS always no in this case? -+ [ms appendString:isHTTPS ? @"https://" : @"http://"]; - -- [ms appendString:[rq headerForKey:@"x-webobjects-server-name"]]; -- if ((isHTTPS ? (port != 443) : (port != 80)) && port != 0) -- [ms appendFormat:@":%i", port]; -+ [ms appendString:[rq headerForKey:@"x-webobjects-server-name"]]; -+ if ((isHTTPS ? (port != 443) : (port != 80)) && port != 0) -+ [ms appendFormat:@":%i", port]; -+ } - } - } - -Index: sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.m -=================================================================== ---- sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.m (revision 1632) -+++ sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.m (working copy) -@@ -338,7 +338,7 @@ - inv->actionName = [self->actionName copy]; - inv->argumentSpecifications = [self->argumentSpecifications copy]; - -- inv->methodObject = [[inv instantiateMethodInContext:_ctx] retain]; -+ inv->methodObject = [inv instantiateMethodInContext:_ctx]; - if (inv->methodObject == nil) { - [self errorWithFormat:@"did not find method '%@'", [self actionClassName]]; - return nil; -Index: sope-appserver/NGObjWeb/SoObjects/SoObject+Traversal.m -=================================================================== ---- sope-appserver/NGObjWeb/SoObjects/SoObject+Traversal.m (revision 1632) -+++ sope-appserver/NGObjWeb/SoObjects/SoObject+Traversal.m (working copy) -@@ -195,7 +195,8 @@ - isCreateIfMissingMethod = YES; - else if ([m isEqualToString:@"PROPPATCH"]) - isCreateIfMissingMethod = YES; -- else if ([m isEqualToString:@"MKCOL"]) -+ else if ([m isEqualToString:@"MKCOL"] -+ || [m isEqualToString:@"MKCALENDAR"]) - /* this one is strictly creating */ - isCreateMethod = YES; - // TODO: the following are only create-if-missing on the target! -Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m -=================================================================== ---- sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m (revision 1632) -+++ sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m (working copy) -@@ -32,6 +32,7 @@ - #include - #include - #include -+#include - #include "common.h" - - #include -@@ -1042,6 +1043,12 @@ - - (void)parser:(NGMimePartParser *)_parser didParseHeader:(NGHashMap *)_header { - } - -+- (NGMimeType *)parser:(id)_parser -+ contentTypeOfPart:(id)_part -+{ -+ return [NGMimeType mimeType: @"text/plain; charset=utf-8"]; -+} -+ - @end /* WOHttpAdaptor */ - - @implementation WOCoreApplication(SimpleParserSelection) -Index: sope-appserver/NGObjWeb/Defaults.plist -=================================================================== ---- sope-appserver/NGObjWeb/Defaults.plist (revision 1632) -+++ sope-appserver/NGObjWeb/Defaults.plist (working copy) -@@ -216,7 +216,7 @@ - SoWebDAVDisableCrossHostMoveCheck = NO; - - SoWebDAVDefaultAllowMethods = ( -- GET, HEAD, POST, OPTIONS, MKCOL, DELETE, PUT, -+ GET, HEAD, POST, OPTIONS, MKCOL, MKCALENDAR, DELETE, PUT, - LOCK, UNLOCK, COPY, MOVE - /* , NOTIFY, POLL, SUBSCRIBE, UNSUBSCRIBE */ - ); -@@ -224,6 +224,7 @@ - SoWebDAVDetectionMethods = ( - OPTIONS, - MKCOL, -+ MKCALENDAR, - PROPFIND, - PROPPATCH, - DELETE, -Index: sope-appserver/NGObjWeb/WORequest.m -=================================================================== ---- sope-appserver/NGObjWeb/WORequest.m (revision 1632) -+++ sope-appserver/NGObjWeb/WORequest.m (working copy) -@@ -597,6 +597,8 @@ - if (r.length > 0) - language = [language substringToIndex:r.location]; - language = [language stringByTrimmingSpaces]; -+ -+ if (![language length]) continue; - - /* check in map */ - if ((tmp = [self languageForBrowserLanguageCode:language])) -Index: sope-appserver/NGObjWeb/NGHttp/NGHttpRequest.h -=================================================================== ---- sope-appserver/NGObjWeb/NGHttp/NGHttpRequest.h (revision 1632) -+++ sope-appserver/NGObjWeb/NGHttp/NGHttpRequest.h (working copy) -@@ -62,6 +62,10 @@ - /* RFC 3253 (DeltaV) */ - NGHttpMethod_REPORT, - NGHttpMethod_VERSION_CONTROL, -+ /* RFC 4791 (CalDAV) */ -+ NGHttpMethod_MKCALENDAR, -+ /* http://ietfreport.isoc.org/idref/draft-daboo-carddav/ (CardDAV) */ -+ NGHttpMethod_MKADDRESSBOOK, - NGHttpMethod_last - } NGHttpMethod; - -Index: sope-appserver/NGObjWeb/NGHttp/NGHttpRequest.m -=================================================================== ---- sope-appserver/NGObjWeb/NGHttp/NGHttpRequest.m (revision 1632) -+++ sope-appserver/NGObjWeb/NGHttp/NGHttpRequest.m (working copy) -@@ -59,6 +59,10 @@ - /* RFC 3253 (DeltaV) */ - @"REPORT", - @"VERSION-CONTROL", -+ /* RFC 4791 (CalDAV) */ -+ @"MKCALENDAR", -+ /* http://ietfreport.isoc.org/idref/draft-daboo-carddav/ (CardDAV) */ -+ @"MKADDRESSBOOK", - nil - }; - diff --git a/SOPE/sope-patchset-r1657.diff b/SOPE/sope-patchset-r1657.diff index b2c638086..be579afa4 100644 --- a/SOPE/sope-patchset-r1657.diff +++ b/SOPE/sope-patchset-r1657.diff @@ -1,6 +1,407 @@ +Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.m +=================================================================== +--- sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (revision 1660) ++++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (working copy) +@@ -713,6 +713,39 @@ + return ms; + } + ++/* GCSEOAdaptorChannel protocol */ ++static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ ++ @" c_name VARCHAR (256) NOT NULL PRIMARY KEY,\n" ++ @" c_content VARCHAR (100000) NOT NULL,\n" ++ @" c_creationdate INT4 NOT NULL,\n" ++ @" c_lastmodified INT4 NOT NULL,\n" ++ @" c_version INT4 NOT NULL,\n" ++ @" c_deleted INT4 NULL\n" ++ @")"); ++static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \ ++ @" c_uid VARCHAR (256) NOT NULL,\n" ++ @" c_object VARCHAR (256) NOT NULL,\n" ++ @" c_role VARCHAR (80) NOT NULL\n" ++ @")"); ++ ++- (NSException *) createGCSFolderTableWithName: (NSString *) tableName ++{ ++ NSString *sql; ++ ++ sql = [NSString stringWithFormat: sqlFolderFormat, tableName]; ++ ++ return [self evaluateExpressionX: sql]; ++} ++ ++- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName ++{ ++ NSString *sql; ++ ++ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName]; ++ ++ return [self evaluateExpressionX: sql]; ++} ++ + @end /* PostgreSQL72Channel */ + + @implementation PostgreSQL72Channel(PrimaryKeyGeneration) +Index: sope-gdl1/MySQL/MySQL4Channel.m +=================================================================== +--- sope-gdl1/MySQL/MySQL4Channel.m (revision 1660) ++++ sope-gdl1/MySQL/MySQL4Channel.m (working copy) +@@ -755,6 +755,39 @@ + return pkey; + } + ++/* GCSEOAdaptorChannel protocol */ ++static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ ++ @" c_name VARCHAR (256) NOT NULL PRIMARY KEY,\n" ++ @" c_content VARCHAR (100000) NOT NULL,\n" ++ @" c_creationdate INT NOT NULL,\n" ++ @" c_lastmodified INT NOT NULL,\n" ++ @" c_version INT NOT NULL,\n" ++ @" c_deleted INT NULL\n" ++ @")"); ++static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \ ++ @" c_uid VARCHAR (256) NOT NULL,\n" ++ @" c_object VARCHAR (256) NOT NULL,\n" ++ @" c_role VARCHAR (80) NOT NULL\n" ++ @")"); ++ ++- (NSException *) createGCSFolderTableWithName: (NSString *) tableName ++{ ++ NSString *sql; ++ ++ sql = [NSString stringWithFormat: sqlFolderFormat, tableName]; ++ ++ return [self evaluateExpressionX: sql]; ++} ++ ++- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName ++{ ++ NSString *sql; ++ ++ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName]; ++ ++ return [self evaluateExpressionX: sql]; ++} ++ + @end /* MySQL4Channel */ + + void __link_MySQL4Channel() { +Index: sope-gdl1/Oracle8/OracleAdaptorChannel.m +=================================================================== +--- sope-gdl1/Oracle8/OracleAdaptorChannel.m (revision 1660) ++++ sope-gdl1/Oracle8/OracleAdaptorChannel.m (working copy) +@@ -1,7 +1,7 @@ + /* + ** OracleAdaptorChannel.m + ** +-** Copyright (c) 2007 Inverse groupe conseil inc. and Ludovic Marcotte ++** Copyright (c) 2007-2009 Inverse inc. and Ludovic Marcotte + ** + ** Author: Ludovic Marcotte + ** +@@ -30,6 +30,11 @@ + + #import + ++#include ++ ++static BOOL debugOn = NO; ++static int maxTry = 3; ++static int maxSleep = 500; + // + // + // +@@ -41,10 +46,11 @@ + + @implementation OracleAdaptorChannel (Private) + +-- (void) _cleanup ++- (void) _cleanup + { + column_info *info; + int c; ++ sword result; + + [_resultSetProperties removeAllObjects]; + +@@ -58,11 +64,29 @@ + // so we just free the value instead. + if (info->value) + { +- if (OCIDescriptorFree((dvoid *)info->value, (ub4)OCI_DTYPE_LOB) != OCI_SUCCESS) ++ if (info->type == SQLT_CLOB ++ || info->type == SQLT_BLOB ++ || info->type == SQLT_BFILEE ++ || info->type == SQLT_CFILEE) ++ { ++ result = OCIDescriptorFree((dvoid *)info->value, (ub4) OCI_DTYPE_LOB); ++ if (result != OCI_SUCCESS) ++ { ++ NSLog (@"value was not a LOB descriptor"); ++ abort(); ++ } ++ } ++ else + free(info->value); + info->value = NULL; + } +- free(info); ++ else ++ { ++ NSLog (@"trying to free an already freed value!"); ++ abort(); ++ } ++ free(info); ++ + [_row_buffer removeObjectAtIndex: c]; + } + +@@ -78,8 +102,7 @@ + // + @implementation OracleAdaptorChannel + +-static void +-DBTerminate() ++static void DBTerminate() + { + if (OCITerminate(OCI_DEFAULT)) + NSLog(@"FAILED: OCITerminate()"); +@@ -89,6 +112,11 @@ + + + (void) initialize + { ++ NSUserDefaults *ud; ++ ++ ud = [NSUserDefaults standardUserDefaults]; ++ debugOn = [ud boolForKey: @"OracleAdaptorDebug"]; ++ + // We Initialize the OCI process environment. + if (OCIInitialize((ub4)OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, +@@ -156,14 +184,17 @@ + [super closeChannel]; + + // We logoff from the database. +- if (OCILogoff(_oci_ctx, _oci_err)) ++ if (!_oci_ctx || !_oci_err || OCILogoff(_oci_ctx, _oci_err)) + { + NSLog(@"FAILED: OCILogoff()"); + } + ++ if (_oci_ctx) ++ OCIHandleFree(_oci_ctx, OCI_HTYPE_SVCCTX); + +- OCIHandleFree(_oci_ctx, OCI_HTYPE_SVCCTX); +- OCIHandleFree(_oci_err, OCI_HTYPE_ERROR); ++ if (_oci_err) ++ OCIHandleFree(_oci_err, OCI_HTYPE_ERROR); ++ + // OCIHandleFree(_oci_env, OCI_HTYPE_ENV); + + _oci_ctx = (OCISvcCtx *)0; +@@ -177,7 +208,8 @@ + // + - (void) dealloc + { +- //NSLog(@"OracleAdaptorChannel: -dealloc"); ++ if (debugOn) ++ NSLog(@"OracleAdaptorChannel: -dealloc"); + + [self _cleanup]; + +@@ -222,7 +254,7 @@ + { + EOAttribute *attribute; + OCIParam *param; +- ++ int rCount; + column_info *info; + ub4 i, clen, count; + text *sql, *cname; +@@ -231,6 +263,9 @@ + + [self _cleanup]; + ++ if (debugOn) ++ [self logWithFormat: @"expression: %@", theExpression]; ++ + if (!theExpression || ![theExpression length]) + { + [NSException raise: @"OracleInvalidExpressionException" +@@ -244,7 +279,9 @@ + } + + sql = (text *)[theExpression UTF8String]; +- ++ ++ rCount = 0; ++ retry: + // We alloc our statement handle + if ((status = OCIHandleAlloc((dvoid *)_oci_env, (dvoid **)&_current_stm, (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0))) + { +@@ -264,13 +301,39 @@ + // We check if we're doing a SELECT and if so, we're fetching data! + OCIAttrGet(_current_stm, OCI_HTYPE_STMT, &type, 0, OCI_ATTR_STMT_TYPE, _oci_err); + self->isFetchInProgress = (type == OCI_STMT_SELECT ? YES : NO); +- ++ + // We execute our statement. Not that we _MUST_ set iter to 0 for non-SELECT statements. + if ((status = OCIStmtExecute(_oci_ctx, _current_stm, _oci_err, (self->isFetchInProgress ? (ub4)0 : (ub4)1), (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, + ([(OracleAdaptorContext *)[self adaptorContext] autoCommit] ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT)))) + { ++ ub4 serverStatus; ++ + checkerr(_oci_err, status); + NSLog(@"Statement execute failed (OCI_ERROR): %@", theExpression); ++ ++ // We check to see if we lost connection and need to reconnect. ++ serverStatus = 0; ++ OCIAttrGet((dvoid *)_oci_env, OCI_HTYPE_SERVER, (dvoid *)&serverStatus, (ub4 *)0, OCI_ATTR_SERVER_STATUS, _oci_err); ++ ++ if (serverStatus == OCI_SERVER_NOT_CONNECTED) ++ { ++ // We cleanup our previous handles ++ [self cancelFetch]; ++ [self closeChannel]; ++ ++ // We try to reconnect a couple of times before giving up... ++ while (rCount < maxTry) ++ { ++ usleep(maxSleep); ++ rCount++; ++ ++ if ([self openChannel]) ++ { ++ NSLog(@"Connection re-established to Oracle - retrying to process the statement."); ++ goto retry; ++ } ++ } ++ } + return NO; + } + +@@ -302,7 +365,9 @@ + // We read the maximum width of a column + info->max_width = 0; + status = OCIAttrGet((dvoid*)param, (ub4)OCI_DTYPE_PARAM, (dvoid*)&(info->max_width), (ub4 *)0, (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)_oci_err); +- ++ ++ if (debugOn) ++ NSLog(@"name: %s, type: %d", cname, info->type); + attribute = [EOAttribute attributeWithOracleType: info->type name: cname length: clen width: info->max_width]; + [_resultSetProperties addObject: attribute]; + +@@ -394,16 +459,17 @@ + return NO; + } + +- + if (OCIEnvInit((OCIEnv **)&_oci_env, (ub4)OCI_DEFAULT, (size_t)0, (dvoid **)0)) + { + NSLog(@"FAILED: OCIEnvInit()"); ++ [self closeChannel]; + return NO; + } + + if (OCIHandleAlloc((dvoid *)_oci_env, (dvoid *)&_oci_err, (ub4)OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0)) + { + NSLog(@"FAILED: OCIHandleAlloc() on errhp"); ++ [self closeChannel]; + return NO; + } + +@@ -414,7 +480,10 @@ + // Under Oracle 10g, the third parameter of OCILogon() has the form: [//]host[:port][/service_name] + // See http://download-west.oracle.com/docs/cd/B12037_01/network.101/b10775/naming.htm#i498306 for + // all juicy details. +- database = [[NSString stringWithFormat:@"%@:%@", [o serverName], [o port]] UTF8String]; ++ if ([o serverName] && [o port]) ++ database = [[NSString stringWithFormat:@"%@:%@/%@", [o serverName], [o port], [o databaseName]] UTF8String]; ++ else ++ database = [[o databaseName] UTF8String]; + + // We logon to the database. + if (OCILogon(_oci_env, _oci_err, &_oci_ctx, (const OraText*)username, strlen(username), +@@ -422,6 +491,7 @@ + { + NSLog(@"FAILED: OCILogon(). username = %s password = %s" + @" database = %s", username, password, database); ++ [self closeChannel]; + return NO; + } + +@@ -438,6 +508,11 @@ + { + sword status; + ++ // We check if our connection is open prior to trying to fetch any data. OCIStmtFetch2() returns ++ // NO error code if the OCI environment is set up but the OCILogon() has failed. ++ if (![self isOpen]) ++ return nil; ++ + status = OCIStmtFetch2(_current_stm, _oci_err, (ub4)1, (ub4)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_NO_DATA) +@@ -609,7 +684,7 @@ + + /* GCSEOAdaptorChannel protocol */ + static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ +- @" c_name VARCHAR2 (256) NOT NULL,\n" ++ @" c_name VARCHAR2 (256) NOT NULL PRIMARY KEY,\n" + @" c_content CLOB NOT NULL,\n" + @" c_creationdate INTEGER NOT NULL,\n" + @" c_lastmodified INTEGER NOT NULL,\n" +Index: sope-gdl1/Oracle8/OracleAdaptorChannelController.m +=================================================================== +--- sope-gdl1/Oracle8/OracleAdaptorChannelController.m (revision 1660) ++++ sope-gdl1/Oracle8/OracleAdaptorChannelController.m (working copy) +@@ -31,6 +31,8 @@ + #import + #import + ++static BOOL debugOn = NO; ++ + // + // + // +@@ -48,6 +50,14 @@ + // + @implementation OracleAdaptorChannelController + +++ (void) initialize ++{ ++ NSUserDefaults *ud; ++ ++ ud = [NSUserDefaults standardUserDefaults]; ++ debugOn = [ud boolForKey: @"OracleAdaptorDebug"]; ++} ++ + - (EODelegateResponse) adaptorChannel: (id) theChannel + willInsertRow: (NSMutableDictionary *) theRow + forEntity: (EOEntity *) theEntity +@@ -56,7 +66,8 @@ + NSArray *keys; + int i, c; + +- NSLog(@"willInsertRow: %@ %@", [theRow description], [theEntity description]); ++ if (debugOn) ++ NSLog(@"willInsertRow: %@ %@", [theRow description], [theEntity description]); + + s = AUTORELEASE([[NSMutableString alloc] init]); + +@@ -101,7 +112,8 @@ + NSArray *keys; + int i, c; + +- NSLog(@"willUpdatetRow: %@ %@", [theRow description], [theQualifier description]); ++ if (debugOn) ++ NSLog(@"willUpdateRow: %@ %@", [theRow description], [theQualifier description]); + + s = AUTORELEASE([[NSMutableString alloc] init]); + Index: sope-mime/NGImap4/NGImap4Functions.m =================================================================== ---- sope-mime/NGImap4/NGImap4Functions.m (revision 1657) +--- sope-mime/NGImap4/NGImap4Functions.m (revision 1660) +++ sope-mime/NGImap4/NGImap4Functions.m (working copy) @@ -367,3 +367,16 @@ } @@ -21,7 +422,7 @@ Index: sope-mime/NGImap4/NGImap4Functions.m +} Index: sope-mime/NGImap4/NGImap4Client.h =================================================================== ---- sope-mime/NGImap4/NGImap4Client.h (revision 1657) +--- sope-mime/NGImap4/NGImap4Client.h (revision 1660) +++ sope-mime/NGImap4/NGImap4Client.h (working copy) @@ -62,6 +62,8 @@ NGImap4ResponseNormalizer *normer; @@ -51,7 +452,7 @@ Index: sope-mime/NGImap4/NGImap4Client.h - (NSDictionary *)copyUid:(unsigned)_uid toFolder:(NSString *)_folder; Index: sope-mime/NGImap4/NGImap4Client.m =================================================================== ---- sope-mime/NGImap4/NGImap4Client.m (revision 1657) +--- sope-mime/NGImap4/NGImap4Client.m (revision 1660) +++ sope-mime/NGImap4/NGImap4Client.m (working copy) @@ -24,6 +24,8 @@ #include "NGImap4Client.h" @@ -456,29 +857,61 @@ 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 @@ +@@ -1412,21 +1517,24 @@ return nil; } - array = [_folder pathComponents]; +// array = [_folder pathComponents]; -+ array = [_folder componentsSeparatedByString:self->delimiter]; ++ array = [_folder componentsSeparatedByString:@"/"]; - if ([array isNotEmpty]) { +- if ([array isNotEmpty]) { ++ if ([array count]) { NSString *o; -@@ -1445,7 +1551,8 @@ + + o = [array objectAtIndex:0]; +- if (([o isEqualToString:@"/"]) || ([o length] == 0)) ++ if ([o length] == 0) + array = [array subarrayWithRange:NSMakeRange(1, [array count] - 1)]; +- +- o = [array lastObject]; +- if (([o length] == 0) || ([o isEqualToString:@"/"])) +- array = [array subarrayWithRange:NSMakeRange(0, [array count] - 1)]; ++ ++ if ([array count]) { ++ o = [array lastObject]; ++ if ([o length] == 0) ++ array = [array subarrayWithRange:NSMakeRange(0, [array count] - 1)]; ++ } + } + return [[array componentsJoinedByString:self->delimiter] +- stringByEncodingImap4FolderName]; ++ stringByEncodingImap4FolderName]; + } + + - (NSString *)_imapFolder2Folder:(NSString *)_folder { +@@ -1442,10 +1550,16 @@ + return nil; + } + ++ if ([_folder hasPrefix: self->delimiter]) ++ _folder = [_folder substringFromIndex: 1]; ++ if ([_folder hasSuffix: self->delimiter]) ++ _folder = [_folder substringToIndex: [_folder length] - 2]; ++ array = [array arrayByAddingObjectsFromArray: [_folder componentsSeparatedByString:[self delimiter]]]; - +- - return [[NSString pathWithComponents:array] stringByDecodingImap4FolderName]; -+ return [[array componentsJoinedByString: self->delimiter] ++ ++ return [[array componentsJoinedByString: @"/"] + stringByDecodingImap4FolderName]; } - (void)setContext:(NGImap4Context *)_ctx { Index: sope-mime/NGImap4/NGSieveClient.m =================================================================== ---- sope-mime/NGImap4/NGSieveClient.m (revision 1657) +--- sope-mime/NGImap4/NGSieveClient.m (revision 1660) +++ sope-mime/NGImap4/NGSieveClient.m (working copy) @@ -294,8 +294,8 @@ return con; @@ -514,7 +947,7 @@ Index: sope-mime/NGImap4/NGSieveClient.m /* write */ Index: sope-mime/NGImap4/NGImap4Connection.h =================================================================== ---- sope-mime/NGImap4/NGImap4Connection.h (revision 1657) +--- sope-mime/NGImap4/NGImap4Connection.h (revision 1660) +++ sope-mime/NGImap4/NGImap4Connection.h (working copy) @@ -89,6 +89,7 @@ @@ -526,7 +959,7 @@ Index: sope-mime/NGImap4/NGImap4Connection.h Index: sope-mime/NGImap4/NGImap4Connection.m =================================================================== ---- sope-mime/NGImap4/NGImap4Connection.m (revision 1657) +--- sope-mime/NGImap4/NGImap4Connection.m (revision 1660) +++ sope-mime/NGImap4/NGImap4Connection.m (working copy) @@ -22,6 +22,7 @@ #include "NGImap4Connection.h" @@ -536,7 +969,24 @@ Index: sope-mime/NGImap4/NGImap4Connection.m #include "imCommon.h" @implementation NGImap4Connection -@@ -373,7 +374,9 @@ +@@ -321,13 +322,15 @@ + return nil; + if ([folderName characterAtIndex:0] == '/') + folderName = [folderName substringFromIndex:1]; ++ if ([folderName hasSuffix: @"/"]) ++ folderName = [folderName substringToIndex:[folderName length] - 1]; + + if (_delfn) folderName = [folderName stringByDeletingLastPathComponent]; + + if ([[self imap4Separator] isEqualToString:@"/"]) + return folderName; + +- names = [folderName pathComponents]; ++ names = [folderName componentsSeparatedByString: @"/"]; + return [names componentsJoinedByString:[self imap4Separator]]; + } + - (NSString *)imap4FolderNameForURL:(NSURL *)_url { +@@ -373,7 +376,9 @@ /* folder operations */ @@ -547,7 +997,7 @@ Index: sope-mime/NGImap4/NGImap4Connection.m NSDictionary *result; if ((result = [self cachedHierarchyResults]) != nil) -@@ -381,8 +384,12 @@ +@@ -381,8 +386,12 @@ if (debugCache) [self logWithFormat:@" no folders cached yet .."]; @@ -562,7 +1012,7 @@ Index: sope-mime/NGImap4/NGImap4Connection.m if (![[result valueForKey:@"result"] boolValue]) { [self errorWithFormat:@"Could not list mailbox hierarchy!"]; return nil; -@@ -400,6 +407,11 @@ +@@ -400,6 +409,11 @@ return result; } @@ -574,7 +1024,7 @@ Index: sope-mime/NGImap4/NGImap4Connection.m - (NSArray *)subfoldersForURL:(NSURL *)_url { NSDictionary *result; -@@ -413,10 +425,13 @@ +@@ -413,10 +427,13 @@ return [self extractSubfoldersForURL:_url fromResultSet:result]; } @@ -590,7 +1040,7 @@ Index: sope-mime/NGImap4/NGImap4Connection.m return nil; if ([result isKindOfClass:[NSException class]]) { [self errorWithFormat:@"failed to retrieve hierarchy: %@", result]; -@@ -426,6 +441,11 @@ +@@ -426,6 +443,11 @@ return [self extractFoldersFromResultSet:result]; } @@ -602,7 +1052,7 @@ Index: sope-mime/NGImap4/NGImap4Connection.m /* message operations */ - (NSArray *)fetchUIDsInURL:(NSURL *)_url qualifier:(id)_qualifier -@@ -646,7 +666,7 @@ +@@ -646,7 +668,7 @@ /* store flags */ @@ -611,7 +1061,7 @@ Index: sope-mime/NGImap4/NGImap4Connection.m if (![[result valueForKey:@"result"] boolValue]) { return [self errorForResult:result text:@"Failed to change flags of IMAP4 message"]; -@@ -760,11 +780,11 @@ +@@ -760,11 +782,11 @@ // TODO: we should probably just fetch the whole hierarchy? folderName = [self imap4FolderNameForURL:_url]; @@ -628,9 +1078,19 @@ Index: sope-mime/NGImap4/NGImap4Connection.m } - (id)infoForMailboxAtURL:(NSURL *)_url { +@@ -789,7 +811,8 @@ + /* construct path */ + + newPath = [self imap4FolderNameForURL:_url]; +- newPath = [newPath stringByAppendingString:[self imap4Separator]]; ++ if ([newPath length]) ++ newPath = [newPath stringByAppendingString:[self imap4Separator]]; + newPath = [newPath stringByAppendingString:_mailbox]; + + /* create */ Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.m =================================================================== ---- sope-mime/NGImap4/NGImap4ResponseNormalizer.m (revision 1657) +--- sope-mime/NGImap4/NGImap4ResponseNormalizer.m (revision 1660) +++ sope-mime/NGImap4/NGImap4ResponseNormalizer.m (working copy) @@ -76,22 +76,6 @@ return self; @@ -729,7 +1189,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.m if (objs) free(objs); Index: sope-mime/NGImap4/NGImap4ResponseParser.m =================================================================== ---- sope-mime/NGImap4/NGImap4ResponseParser.m (revision 1657) +--- sope-mime/NGImap4/NGImap4ResponseParser.m (revision 1660) +++ sope-mime/NGImap4/NGImap4ResponseParser.m (working copy) @@ -31,6 +31,7 @@ @interface NGImap4ResponseParser(ParsingPrivates) @@ -1209,7 +1669,7 @@ Index: sope-mime/NGImap4/NGImap4ResponseParser.m self->serverResponseDebug = Index: sope-mime/NGImap4/ChangeLog =================================================================== ---- sope-mime/NGImap4/ChangeLog (revision 1657) +--- sope-mime/NGImap4/ChangeLog (revision 1660) +++ sope-mime/NGImap4/ChangeLog (working copy) @@ -1,3 +1,39 @@ +2009-06-15 Wolfgang Sourdeau @@ -1253,7 +1713,7 @@ Index: sope-mime/NGImap4/ChangeLog * NGImap4Connection.m: some fix for folders ending with a slash (OGo Index: sope-mime/NGImap4/NGImap4ConnectionManager.m =================================================================== ---- sope-mime/NGImap4/NGImap4ConnectionManager.m (revision 1657) +--- sope-mime/NGImap4/NGImap4ConnectionManager.m (revision 1660) +++ sope-mime/NGImap4/NGImap4ConnectionManager.m (working copy) @@ -38,6 +38,9 @@ debugCache = [ud boolForKey:@"NGImap4EnableIMAP4CacheDebug"]; @@ -1380,7 +1840,7 @@ Index: sope-mime/NGImap4/NGImap4ConnectionManager.m /* client object */ Index: sope-mime/NGImap4/NSString+Imap4.m =================================================================== ---- sope-mime/NGImap4/NSString+Imap4.m (revision 1657) +--- sope-mime/NGImap4/NSString+Imap4.m (revision 1660) +++ sope-mime/NGImap4/NSString+Imap4.m (working copy) @@ -20,117 +20,86 @@ 02111-1307, USA. @@ -1944,7 +2404,7 @@ Index: sope-mime/NGImap4/NSString+Imap4.m -} Index: sope-mime/NGImap4/NGImap4Functions.h =================================================================== ---- sope-mime/NGImap4/NGImap4Functions.h (revision 1657) +--- sope-mime/NGImap4/NGImap4Functions.h (revision 1660) +++ sope-mime/NGImap4/NGImap4Functions.h (working copy) @@ -58,4 +58,6 @@ id_folder); @@ -1955,7 +2415,7 @@ Index: sope-mime/NGImap4/NGImap4Functions.h #endif /* __NGMime_NGImap4_NGImap4Functions_H__ */ Index: sope-mime/NGMail/NGMailAddressParser.h =================================================================== ---- sope-mime/NGMail/NGMailAddressParser.h (revision 1657) +--- sope-mime/NGMail/NGMailAddressParser.h (revision 1660) +++ sope-mime/NGMail/NGMailAddressParser.h (working copy) @@ -24,7 +24,9 @@ @@ -1993,7 +2453,7 @@ Index: sope-mime/NGMail/NGMailAddressParser.h Index: sope-mime/NGMail/NGMimeMessageGenerator.m =================================================================== ---- sope-mime/NGMail/NGMimeMessageGenerator.m (revision 1657) +--- sope-mime/NGMail/NGMimeMessageGenerator.m (revision 1660) +++ sope-mime/NGMail/NGMimeMessageGenerator.m (working copy) @@ -86,37 +86,40 @@ char *des = NULL; @@ -2059,7 +2519,7 @@ Index: sope-mime/NGMail/NGMimeMessageGenerator.m unsigned isoEndLen = 2; Index: sope-mime/NGMail/NGMailAddressParser.m =================================================================== ---- sope-mime/NGMail/NGMailAddressParser.m (revision 1657) +--- sope-mime/NGMail/NGMailAddressParser.m (revision 1660) +++ sope-mime/NGMail/NGMailAddressParser.m (working copy) @@ -52,9 +52,9 @@ StrClass = [NSString class]; @@ -2204,7 +2664,7 @@ Index: sope-mime/NGMail/NGMailAddressParser.m self->dataPos = 0; Index: sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m =================================================================== ---- sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (revision 1657) +--- sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (revision 1660) +++ sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (working copy) @@ -19,88 +19,45 @@ 02111-1307, USA. @@ -2609,7 +3069,7 @@ Index: sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m #if 0 Index: sope-mime/NGMime/NGMimeMultipartBodyParser.m =================================================================== ---- sope-mime/NGMime/NGMimeMultipartBodyParser.m (revision 1657) +--- sope-mime/NGMime/NGMimeMultipartBodyParser.m (revision 1660) +++ sope-mime/NGMime/NGMimeMultipartBodyParser.m (working copy) @@ -428,6 +428,7 @@ NSString *boundary = nil; @@ -2634,7 +3094,7 @@ Index: sope-mime/NGMime/NGMimeMultipartBodyParser.m if (rawBodyParts) { Index: sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m =================================================================== ---- sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (revision 1657) +--- sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (revision 1660) +++ sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (working copy) @@ -77,6 +77,7 @@ [rfc822Set setGenerator:gen forField:@"bcc"]; @@ -2646,7 +3106,7 @@ Index: sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m Index: sope-mime/NGMime/NGMimeType.m =================================================================== ---- sope-mime/NGMime/NGMimeType.m (revision 1657) +--- sope-mime/NGMime/NGMimeType.m (revision 1660) +++ sope-mime/NGMime/NGMimeType.m (working copy) @@ -120,30 +120,27 @@ @@ -2749,7 +3209,7 @@ Index: sope-mime/NGMime/NGMimeType.m - (NSString *)stringValue { Index: sope-mime/NGMime/NGMimeBodyPart.m =================================================================== ---- sope-mime/NGMime/NGMimeBodyPart.m (revision 1657) +--- sope-mime/NGMime/NGMimeBodyPart.m (revision 1660) +++ sope-mime/NGMime/NGMimeBodyPart.m (working copy) @@ -31,18 +31,6 @@ return 2; @@ -2787,7 +3247,7 @@ Index: sope-mime/NGMime/NGMimeBodyPart.m - (NSString *)contentId { Index: sope-mime/NGMime/ChangeLog =================================================================== ---- sope-mime/NGMime/ChangeLog (revision 1657) +--- sope-mime/NGMime/ChangeLog (revision 1660) +++ sope-mime/NGMime/ChangeLog (working copy) @@ -1,3 +1,25 @@ +2008-09-08 Wolfgang Sourdeau @@ -2817,7 +3277,7 @@ Index: sope-mime/NGMime/ChangeLog * fixes for OGo bug #789 (reply-to QP encoding) Index: sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m =================================================================== ---- sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (revision 1657) +--- sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (revision 1660) +++ sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (working copy) @@ -36,8 +36,7 @@ NGMimeType *type = nil; // only one content-type field @@ -2957,7 +3417,7 @@ Index: sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m } Index: sope-mime/NGMime/NGMimePartGenerator.m =================================================================== ---- sope-mime/NGMime/NGMimePartGenerator.m (revision 1657) +--- sope-mime/NGMime/NGMimePartGenerator.m (revision 1660) +++ sope-mime/NGMime/NGMimePartGenerator.m (working copy) @@ -155,8 +155,9 @@ BOOL isMultiValue, isFirst; @@ -2982,7 +3442,7 @@ Index: sope-mime/NGMime/NGMimePartGenerator.m Index: sope-mime/NGMime/NGMimeBodyParser.m =================================================================== ---- sope-mime/NGMime/NGMimeBodyParser.m (revision 1657) +--- sope-mime/NGMime/NGMimeBodyParser.m (revision 1660) +++ sope-mime/NGMime/NGMimeBodyParser.m (working copy) @@ -67,7 +67,10 @@ if (_data == nil) return nil; @@ -3021,7 +3481,7 @@ Index: sope-mime/NGMime/NGMimeBodyParser.m } Index: sope-mime/NGMime/NGMimePartParser.h =================================================================== ---- sope-mime/NGMime/NGMimePartParser.h (revision 1657) +--- sope-mime/NGMime/NGMimePartParser.h (revision 1660) +++ sope-mime/NGMime/NGMimePartParser.h (working copy) @@ -117,6 +117,7 @@ BOOL parserParseRawBodyDataOfPart:1; @@ -3043,7 +3503,7 @@ Index: sope-mime/NGMime/NGMimePartParser.h @interface NSObject(NGMimePartParser) Index: sope-mime/NGMime/NGMimePartParser.m =================================================================== ---- sope-mime/NGMime/NGMimePartParser.m (revision 1657) +--- sope-mime/NGMime/NGMimePartParser.m (revision 1660) +++ sope-mime/NGMime/NGMimePartParser.m (working copy) @@ -227,7 +227,7 @@ } @@ -3068,7 +3528,7 @@ Index: sope-mime/NGMime/NGMimePartParser.m : [NGMimeType mimeType:[ctype stringValue]]; Index: sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m =================================================================== ---- sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (revision 1657) +--- sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (revision 1660) +++ sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (working copy) @@ -105,10 +105,10 @@ } @@ -3154,7 +3614,7 @@ Index: sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m return data; Index: sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m =================================================================== ---- sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (revision 1657) +--- sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (revision 1660) +++ sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (working copy) @@ -49,80 +49,70 @@ @@ -3288,410 +3748,9 @@ Index: sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m } return data; } -Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.m -=================================================================== ---- sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (revision 1657) -+++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (working copy) -@@ -713,6 +713,39 @@ - return ms; - } - -+/* GCSEOAdaptorChannel protocol */ -+static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ -+ @" c_name VARCHAR (256) NOT NULL PRIMARY KEY,\n" -+ @" c_content VARCHAR (100000) NOT NULL,\n" -+ @" c_creationdate INT4 NOT NULL,\n" -+ @" c_lastmodified INT4 NOT NULL,\n" -+ @" c_version INT4 NOT NULL,\n" -+ @" c_deleted INT4 NULL\n" -+ @")"); -+static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \ -+ @" c_uid VARCHAR (256) NOT NULL,\n" -+ @" c_object VARCHAR (256) NOT NULL,\n" -+ @" c_role VARCHAR (80) NOT NULL\n" -+ @")"); -+ -+- (NSException *) createGCSFolderTableWithName: (NSString *) tableName -+{ -+ NSString *sql; -+ -+ sql = [NSString stringWithFormat: sqlFolderFormat, tableName]; -+ -+ return [self evaluateExpressionX: sql]; -+} -+ -+- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName -+{ -+ NSString *sql; -+ -+ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName]; -+ -+ return [self evaluateExpressionX: sql]; -+} -+ - @end /* PostgreSQL72Channel */ - - @implementation PostgreSQL72Channel(PrimaryKeyGeneration) -Index: sope-gdl1/MySQL/MySQL4Channel.m -=================================================================== ---- sope-gdl1/MySQL/MySQL4Channel.m (revision 1657) -+++ sope-gdl1/MySQL/MySQL4Channel.m (working copy) -@@ -755,6 +755,39 @@ - return pkey; - } - -+/* GCSEOAdaptorChannel protocol */ -+static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ -+ @" c_name VARCHAR (256) NOT NULL PRIMARY KEY,\n" -+ @" c_content VARCHAR (100000) NOT NULL,\n" -+ @" c_creationdate INT NOT NULL,\n" -+ @" c_lastmodified INT NOT NULL,\n" -+ @" c_version INT NOT NULL,\n" -+ @" c_deleted INT NULL\n" -+ @")"); -+static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \ -+ @" c_uid VARCHAR (256) NOT NULL,\n" -+ @" c_object VARCHAR (256) NOT NULL,\n" -+ @" c_role VARCHAR (80) NOT NULL\n" -+ @")"); -+ -+- (NSException *) createGCSFolderTableWithName: (NSString *) tableName -+{ -+ NSString *sql; -+ -+ sql = [NSString stringWithFormat: sqlFolderFormat, tableName]; -+ -+ return [self evaluateExpressionX: sql]; -+} -+ -+- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName -+{ -+ NSString *sql; -+ -+ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName]; -+ -+ return [self evaluateExpressionX: sql]; -+} -+ - @end /* MySQL4Channel */ - - void __link_MySQL4Channel() { -Index: sope-gdl1/Oracle8/OracleAdaptorChannel.m -=================================================================== ---- sope-gdl1/Oracle8/OracleAdaptorChannel.m (revision 1657) -+++ sope-gdl1/Oracle8/OracleAdaptorChannel.m (working copy) -@@ -1,7 +1,7 @@ - /* - ** OracleAdaptorChannel.m - ** --** Copyright (c) 2007 Inverse groupe conseil inc. and Ludovic Marcotte -+** Copyright (c) 2007-2009 Inverse inc. and Ludovic Marcotte - ** - ** Author: Ludovic Marcotte - ** -@@ -30,6 +30,11 @@ - - #import - -+#include -+ -+static BOOL debugOn = NO; -+static int maxTry = 3; -+static int maxSleep = 500; - // - // - // -@@ -41,10 +46,11 @@ - - @implementation OracleAdaptorChannel (Private) - --- (void) _cleanup -+- (void) _cleanup - { - column_info *info; - int c; -+ sword result; - - [_resultSetProperties removeAllObjects]; - -@@ -58,11 +64,29 @@ - // so we just free the value instead. - if (info->value) - { -- if (OCIDescriptorFree((dvoid *)info->value, (ub4)OCI_DTYPE_LOB) != OCI_SUCCESS) -+ if (info->type == SQLT_CLOB -+ || info->type == SQLT_BLOB -+ || info->type == SQLT_BFILEE -+ || info->type == SQLT_CFILEE) -+ { -+ result = OCIDescriptorFree((dvoid *)info->value, (ub4) OCI_DTYPE_LOB); -+ if (result != OCI_SUCCESS) -+ { -+ NSLog (@"value was not a LOB descriptor"); -+ abort(); -+ } -+ } -+ else - free(info->value); - info->value = NULL; - } -- free(info); -+ else -+ { -+ NSLog (@"trying to free an already freed value!"); -+ abort(); -+ } -+ free(info); -+ - [_row_buffer removeObjectAtIndex: c]; - } - -@@ -78,8 +102,7 @@ - // - @implementation OracleAdaptorChannel - --static void --DBTerminate() -+static void DBTerminate() - { - if (OCITerminate(OCI_DEFAULT)) - NSLog(@"FAILED: OCITerminate()"); -@@ -89,6 +112,11 @@ - - + (void) initialize - { -+ NSUserDefaults *ud; -+ -+ ud = [NSUserDefaults standardUserDefaults]; -+ debugOn = [ud boolForKey: @"OracleAdaptorDebug"]; -+ - // We Initialize the OCI process environment. - if (OCIInitialize((ub4)OCI_DEFAULT, (dvoid *)0, - (dvoid * (*)(dvoid *, size_t)) 0, -@@ -156,14 +184,17 @@ - [super closeChannel]; - - // We logoff from the database. -- if (OCILogoff(_oci_ctx, _oci_err)) -+ if (!_oci_ctx || !_oci_err || OCILogoff(_oci_ctx, _oci_err)) - { - NSLog(@"FAILED: OCILogoff()"); - } - -+ if (_oci_ctx) -+ OCIHandleFree(_oci_ctx, OCI_HTYPE_SVCCTX); - -- OCIHandleFree(_oci_ctx, OCI_HTYPE_SVCCTX); -- OCIHandleFree(_oci_err, OCI_HTYPE_ERROR); -+ if (_oci_err) -+ OCIHandleFree(_oci_err, OCI_HTYPE_ERROR); -+ - // OCIHandleFree(_oci_env, OCI_HTYPE_ENV); - - _oci_ctx = (OCISvcCtx *)0; -@@ -177,7 +208,8 @@ - // - - (void) dealloc - { -- //NSLog(@"OracleAdaptorChannel: -dealloc"); -+ if (debugOn) -+ NSLog(@"OracleAdaptorChannel: -dealloc"); - - [self _cleanup]; - -@@ -222,7 +254,7 @@ - { - EOAttribute *attribute; - OCIParam *param; -- -+ int rCount; - column_info *info; - ub4 i, clen, count; - text *sql, *cname; -@@ -231,6 +263,9 @@ - - [self _cleanup]; - -+ if (debugOn) -+ [self logWithFormat: @"expression: %@", theExpression]; -+ - if (!theExpression || ![theExpression length]) - { - [NSException raise: @"OracleInvalidExpressionException" -@@ -244,7 +279,9 @@ - } - - sql = (text *)[theExpression UTF8String]; -- -+ -+ rCount = 0; -+ retry: - // We alloc our statement handle - if ((status = OCIHandleAlloc((dvoid *)_oci_env, (dvoid **)&_current_stm, (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0))) - { -@@ -264,13 +301,39 @@ - // We check if we're doing a SELECT and if so, we're fetching data! - OCIAttrGet(_current_stm, OCI_HTYPE_STMT, &type, 0, OCI_ATTR_STMT_TYPE, _oci_err); - self->isFetchInProgress = (type == OCI_STMT_SELECT ? YES : NO); -- -+ - // We execute our statement. Not that we _MUST_ set iter to 0 for non-SELECT statements. - if ((status = OCIStmtExecute(_oci_ctx, _current_stm, _oci_err, (self->isFetchInProgress ? (ub4)0 : (ub4)1), (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, - ([(OracleAdaptorContext *)[self adaptorContext] autoCommit] ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT)))) - { -+ ub4 serverStatus; -+ - checkerr(_oci_err, status); - NSLog(@"Statement execute failed (OCI_ERROR): %@", theExpression); -+ -+ // We check to see if we lost connection and need to reconnect. -+ serverStatus = 0; -+ OCIAttrGet((dvoid *)_oci_env, OCI_HTYPE_SERVER, (dvoid *)&serverStatus, (ub4 *)0, OCI_ATTR_SERVER_STATUS, _oci_err); -+ -+ if (serverStatus == OCI_SERVER_NOT_CONNECTED) -+ { -+ // We cleanup our previous handles -+ [self cancelFetch]; -+ [self closeChannel]; -+ -+ // We try to reconnect a couple of times before giving up... -+ while (rCount < maxTry) -+ { -+ usleep(maxSleep); -+ rCount++; -+ -+ if ([self openChannel]) -+ { -+ NSLog(@"Connection re-established to Oracle - retrying to process the statement."); -+ goto retry; -+ } -+ } -+ } - return NO; - } - -@@ -302,7 +365,9 @@ - // We read the maximum width of a column - info->max_width = 0; - status = OCIAttrGet((dvoid*)param, (ub4)OCI_DTYPE_PARAM, (dvoid*)&(info->max_width), (ub4 *)0, (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)_oci_err); -- -+ -+ if (debugOn) -+ NSLog(@"name: %s, type: %d", cname, info->type); - attribute = [EOAttribute attributeWithOracleType: info->type name: cname length: clen width: info->max_width]; - [_resultSetProperties addObject: attribute]; - -@@ -394,16 +459,17 @@ - return NO; - } - -- - if (OCIEnvInit((OCIEnv **)&_oci_env, (ub4)OCI_DEFAULT, (size_t)0, (dvoid **)0)) - { - NSLog(@"FAILED: OCIEnvInit()"); -+ [self closeChannel]; - return NO; - } - - if (OCIHandleAlloc((dvoid *)_oci_env, (dvoid *)&_oci_err, (ub4)OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0)) - { - NSLog(@"FAILED: OCIHandleAlloc() on errhp"); -+ [self closeChannel]; - return NO; - } - -@@ -414,7 +480,10 @@ - // Under Oracle 10g, the third parameter of OCILogon() has the form: [//]host[:port][/service_name] - // See http://download-west.oracle.com/docs/cd/B12037_01/network.101/b10775/naming.htm#i498306 for - // all juicy details. -- database = [[NSString stringWithFormat:@"%@:%@", [o serverName], [o port]] UTF8String]; -+ if ([o serverName] && [o port]) -+ database = [[NSString stringWithFormat:@"%@:%@/%@", [o serverName], [o port], [o databaseName]] UTF8String]; -+ else -+ database = [[o databaseName] UTF8String]; - - // We logon to the database. - if (OCILogon(_oci_env, _oci_err, &_oci_ctx, (const OraText*)username, strlen(username), -@@ -422,6 +491,7 @@ - { - NSLog(@"FAILED: OCILogon(). username = %s password = %s" - @" database = %s", username, password, database); -+ [self closeChannel]; - return NO; - } - -@@ -438,6 +508,11 @@ - { - sword status; - -+ // We check if our connection is open prior to trying to fetch any data. OCIStmtFetch2() returns -+ // NO error code if the OCI environment is set up but the OCILogon() has failed. -+ if (![self isOpen]) -+ return nil; -+ - status = OCIStmtFetch2(_current_stm, _oci_err, (ub4)1, (ub4)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); - - if (status == OCI_NO_DATA) -@@ -609,7 +684,7 @@ - - /* GCSEOAdaptorChannel protocol */ - static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ -- @" c_name VARCHAR2 (256) NOT NULL,\n" -+ @" c_name VARCHAR2 (256) NOT NULL PRIMARY KEY,\n" - @" c_content CLOB NOT NULL,\n" - @" c_creationdate INTEGER NOT NULL,\n" - @" c_lastmodified INTEGER NOT NULL,\n" -Index: sope-gdl1/Oracle8/OracleAdaptorChannelController.m -=================================================================== ---- sope-gdl1/Oracle8/OracleAdaptorChannelController.m (revision 1657) -+++ sope-gdl1/Oracle8/OracleAdaptorChannelController.m (working copy) -@@ -31,6 +31,8 @@ - #import - #import - -+static BOOL debugOn = NO; -+ - // - // - // -@@ -48,6 +50,14 @@ - // - @implementation OracleAdaptorChannelController - -++ (void) initialize -+{ -+ NSUserDefaults *ud; -+ -+ ud = [NSUserDefaults standardUserDefaults]; -+ debugOn = [ud boolForKey: @"OracleAdaptorDebug"]; -+} -+ - - (EODelegateResponse) adaptorChannel: (id) theChannel - willInsertRow: (NSMutableDictionary *) theRow - forEntity: (EOEntity *) theEntity -@@ -56,7 +66,8 @@ - NSArray *keys; - int i, c; - -- NSLog(@"willInsertRow: %@ %@", [theRow description], [theEntity description]); -+ if (debugOn) -+ NSLog(@"willInsertRow: %@ %@", [theRow description], [theEntity description]); - - s = AUTORELEASE([[NSMutableString alloc] init]); - -@@ -101,7 +112,8 @@ - NSArray *keys; - int i, c; - -- NSLog(@"willUpdatetRow: %@ %@", [theRow description], [theQualifier description]); -+ if (debugOn) -+ NSLog(@"willUpdateRow: %@ %@", [theRow description], [theQualifier description]); - - s = AUTORELEASE([[NSMutableString alloc] init]); - Index: sope-core/NGExtensions/NGExtensions/NSString+Ext.h =================================================================== ---- sope-core/NGExtensions/NGExtensions/NSString+Ext.h (revision 1657) +--- sope-core/NGExtensions/NGExtensions/NSString+Ext.h (revision 1660) +++ sope-core/NGExtensions/NGExtensions/NSString+Ext.h (working copy) @@ -30,6 +30,7 @@ @@ -3729,7 +3788,7 @@ Index: sope-core/NGExtensions/NGExtensions/NSString+Ext.h /* specific to libFoundation */ Index: sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m =================================================================== ---- sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (revision 1657) +--- sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (revision 1660) +++ sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (working copy) @@ -39,18 +39,6 @@ : (NSString *)[[self copy] autorelease]; @@ -3818,7 +3877,7 @@ Index: sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m - (BOOL)isAbsoluteURL Index: sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m =================================================================== ---- sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (revision 1657) +--- sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (revision 1660) +++ sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (working copy) @@ -140,8 +140,12 @@ @@ -3861,7 +3920,7 @@ Index: sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m static char *iconv_wrapper(id self, char *_src, unsigned _srcLen, Index: sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m =================================================================== ---- sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (revision 1657) +--- sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (revision 1660) +++ sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (working copy) @@ -19,6 +19,7 @@ 02111-1307, USA. @@ -3873,7 +3932,7 @@ Index: sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h =================================================================== ---- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (revision 1657) +--- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (revision 1660) +++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (working copy) @@ -19,6 +19,8 @@ 02111-1307, USA. @@ -3895,7 +3954,7 @@ Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h id entityResolver; Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m =================================================================== ---- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (revision 1657) +--- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (revision 1660) +++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (working copy) @@ -200,10 +200,10 @@ return self->entityResolver; @@ -3912,7 +3971,7 @@ Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m Index: sope-appserver/mod_ngobjweb/GNUmakefile =================================================================== ---- sope-appserver/mod_ngobjweb/GNUmakefile (revision 1657) +--- sope-appserver/mod_ngobjweb/GNUmakefile (revision 1660) +++ sope-appserver/mod_ngobjweb/GNUmakefile (working copy) @@ -82,7 +82,7 @@ @@ -3935,7 +3994,7 @@ Index: sope-appserver/mod_ngobjweb/GNUmakefile $(INSTALL_PROGRAM) $(product) /usr/libexec/httpd/ Index: sope-appserver/NGObjWeb/GNUmakefile.postamble =================================================================== ---- sope-appserver/NGObjWeb/GNUmakefile.postamble (revision 1657) +--- sope-appserver/NGObjWeb/GNUmakefile.postamble (revision 1660) +++ sope-appserver/NGObjWeb/GNUmakefile.postamble (working copy) @@ -23,14 +23,20 @@ @@ -3967,7 +4026,7 @@ Index: sope-appserver/NGObjWeb/GNUmakefile.postamble + $(DESTDIR)/$(GNUSTEP_MAKEFILES)/wobundle.make Index: sope-appserver/NGObjWeb/WODirectAction.m =================================================================== ---- sope-appserver/NGObjWeb/WODirectAction.m (revision 1657) +--- sope-appserver/NGObjWeb/WODirectAction.m (revision 1660) +++ sope-appserver/NGObjWeb/WODirectAction.m (working copy) @@ -46,7 +46,7 @@ } @@ -4002,7 +4061,7 @@ Index: sope-appserver/NGObjWeb/WODirectAction.m Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m =================================================================== ---- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (revision 1657) +--- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (revision 1660) +++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (working copy) @@ -216,6 +216,12 @@ assocCount++; @@ -4019,7 +4078,7 @@ Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m Index: sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m =================================================================== ---- sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (revision 1657) +--- sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (revision 1660) +++ sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (working copy) @@ -41,6 +41,7 @@ WOAssociation *string; @@ -4052,7 +4111,7 @@ Index: sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m return NO; Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h =================================================================== ---- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (revision 1657) +--- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (revision 1660) +++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (working copy) @@ -41,7 +41,8 @@ WOAssociation *pageName; @@ -4066,7 +4125,7 @@ Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h /* 'ivar' associations */ Index: sope-appserver/NGObjWeb/SoObjects/SoObject.m =================================================================== ---- sope-appserver/NGObjWeb/SoObjects/SoObject.m (revision 1657) +--- sope-appserver/NGObjWeb/SoObjects/SoObject.m (revision 1660) +++ sope-appserver/NGObjWeb/SoObjects/SoObject.m (working copy) @@ -39,22 +39,34 @@ static int debugLookup = -1;