From 905d2c885ca8c8167c811018841bc9e542bbf9a5 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 27 Mar 2012 16:47:14 +0000 Subject: [PATCH 1/5] Monotone-Parent: b4a3ddf3836324fd1f4925acb0426089a4a0350a Monotone-Revision: c1548a6a3e72a7d9b567b63d50198115fa48ab0b Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-03-27T16:47:14 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 17 ++ SoObjects/Contacts/SOGoContactFolders.m | 46 ++++ SoObjects/Contacts/SOGoContactLDIFEntry.m | 5 + SoObjects/Contacts/SOGoContactSourceFolder.m | 274 +++++++++++++++++++ SoObjects/Contacts/SOGoUserFolder+Contacts.m | 27 ++ 5 files changed, 369 insertions(+) diff --git a/ChangeLog b/ChangeLog index 7afe15f01..8c39ecf6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2012-03-27 Wolfgang Sourdeau + + * SoObjects/Contacts/SOGoContactFolders.m + (-lookupName:inContext:acquire:): overriden method that enables + the lookup of hidden public sources with iOS devices. + + * SoObjects/Contacts/SOGoContactLDIFEntry.m (-davAddressData): new + getter similar to davCalendarData. + + * SoObjects/Contacts/SOGoContactSourceFolder.m + (-davAddressbookMultiget): new REPORT handler based on + -[SOGoAppointmentFolder davCalendarMultiget]. + + * SoObjects/Contacts/SOGoUserFolder+Contacts.m + (-davDirectoryGateway): new getter that returns the url to the + first available directory source. + 2012-03-26 Wolfgang Sourdeau * OpenChange/MAPIStoreTasksMessage.m (-save): take PR_HTML as diff --git a/SoObjects/Contacts/SOGoContactFolders.m b/SoObjects/Contacts/SOGoContactFolders.m index 01b1f3abb..537d7a08a 100644 --- a/SoObjects/Contacts/SOGoContactFolders.m +++ b/SoObjects/Contacts/SOGoContactFolders.m @@ -259,6 +259,52 @@ return keys; } +- (id) lookupName: (NSString *) name + inContext: (WOContext *) lookupContext + acquire: (BOOL) acquire +{ + id folder = nil; + SOGoUser *currentUser; + SOGoUserManager *um; + SOGoSystemDefaults *sd; + NSEnumerator *domains; + NSArray *sourceIDs; + NSString *domain, *srcDisplayName; + + if ([[context request] isIPhoneAddressBookApp]) + { + currentUser = [context activeUser]; + if (activeUserIsOwner + || [[currentUser login] isEqualToString: owner]) + { + domain = [currentUser domain]; + um = [SOGoUserManager sharedUserManager]; + sd = [SOGoSystemDefaults sharedSystemDefaults]; + domains = [[sd visibleDomainsForDomain: domain] objectEnumerator]; + while (domain) + { + sourceIDs = [um addressBookSourceIDsInDomain: domain]; + if ([sourceIDs containsObject: name]) + { + srcDisplayName = [um displayNameForSourceWithID: name]; + folder = [SOGoContactSourceFolder + folderWithName: name + andDisplayName: srcDisplayName + inContainer: self]; + [folder setSource: [um sourceWithID: name]]; + } + domain = [domains nextObject]; + } + } + } + + if (!folder) + folder = [super lookupName: name inContext: lookupContext + acquire: acquire]; + + return folder; +} + - (NSException *) setDavContactsCategories: (NSString *) newCategories { SOGoUser *ownerUser; diff --git a/SoObjects/Contacts/SOGoContactLDIFEntry.m b/SoObjects/Contacts/SOGoContactLDIFEntry.m index 6801875fb..4472ae901 100644 --- a/SoObjects/Contacts/SOGoContactLDIFEntry.m +++ b/SoObjects/Contacts/SOGoContactLDIFEntry.m @@ -166,6 +166,11 @@ return @"text/x-vcard"; } +- (NSString *) davAddressData +{ + return [self contentAsString]; +} + - (NSException *) save { return [(SOGoContactSourceFolder *) container saveLDIFEntry: self]; diff --git a/SoObjects/Contacts/SOGoContactSourceFolder.m b/SoObjects/Contacts/SOGoContactSourceFolder.m index b4a5b2318..1f6437bb9 100644 --- a/SoObjects/Contacts/SOGoContactSourceFolder.m +++ b/SoObjects/Contacts/SOGoContactSourceFolder.m @@ -24,6 +24,7 @@ #import #import #import +#import #import #import @@ -34,17 +35,23 @@ #import #import #import +#import #import +#import +#import #import #import +#import #import #import #import +#import #import #import #import #import +#import #import "SOGoContactFolders.h" #import "SOGoContactGCSFolder.h" @@ -350,6 +357,273 @@ return result; } +- (NSString *) _deduceObjectNameFromURL: (NSString *) url + fromBaseURL: (NSString *) baseURL +{ + NSRange urlRange; + NSString *name; + + urlRange = [url rangeOfString: baseURL]; + if (urlRange.location != NSNotFound) + { + name = [url substringFromIndex: NSMaxRange (urlRange)]; + if ([name hasPrefix: @"/"]) + name = [name substringFromIndex: 1]; + } + else + name = nil; + + return name; +} + +/* TODO: multiget reorg */ +- (NSString *) _nodeTagForProperty: (NSString *) property +{ + NSString *namespace, *nodeName, *nsRep; + NSRange nsEnd; + + nsEnd = [property rangeOfString: @"}"]; + namespace + = [property substringFromRange: NSMakeRange (1, nsEnd.location - 1)]; + nodeName = [property substringFromIndex: nsEnd.location + 1]; + if ([namespace isEqualToString: XMLNS_CARDDAV]) + nsRep = @"C"; + else + nsRep = @"D"; + + return [NSString stringWithFormat: @"%@:%@", nsRep, nodeName]; +} + +- (NSString *) _nodeTag: (NSString *) property +{ + static NSMutableDictionary *tags = nil; + NSString *nodeTag; + + if (!tags) + tags = [NSMutableDictionary new]; + nodeTag = [tags objectForKey: property]; + if (!nodeTag) + { + nodeTag = [self _nodeTagForProperty: property]; + [tags setObject: nodeTag forKey: property]; + } + + return nodeTag; +} + +- (NSString **) _properties: (NSString **) properties + count: (unsigned int) propertiesCount + ofObject: (NSDictionary *) object +{ + SOGoContactLDIFEntry *ldifEntry; + NSString **currentProperty; + NSString **values, **currentValue; + SEL methodSel; + +// NSLog (@"_properties:ofObject:: %@", [NSDate date]); + + values = NSZoneMalloc (NULL, + (propertiesCount + 1) * sizeof (NSString *)); + *(values + propertiesCount) = nil; + + ldifEntry = [SOGoContactLDIFEntry + contactEntryWithName: [object objectForKey: @"c_name"] + withLDIFEntry: object + inContainer: self]; + currentProperty = properties; + currentValue = values; + while (*currentProperty) + { + methodSel = SOGoSelectorForPropertyGetter (*currentProperty); + if (methodSel && [ldifEntry respondsToSelector: methodSel]) + *currentValue = [[ldifEntry performSelector: methodSel] + stringByEscapingXMLString]; + currentProperty++; + currentValue++; + } + +// NSLog (@"/_properties:ofObject:: %@", [NSDate date]); + + return values; +} + +- (NSArray *) _propstats: (NSString **) properties + count: (unsigned int) propertiesCount + ofObject: (NSDictionary *) object +{ + NSMutableArray *propstats, *properties200, *properties404, *propDict; + NSString **property, **values, **currentValue; + NSString *propertyValue, *nodeTag; + +// NSLog (@"_propstats:ofObject:: %@", [NSDate date]); + + propstats = [NSMutableArray array]; + + properties200 = [NSMutableArray array]; + properties404 = [NSMutableArray array]; + + values = [self _properties: properties count: propertiesCount + ofObject: object]; + currentValue = values; + + property = properties; + while (*property) + { + nodeTag = [self _nodeTag: *property]; + if (*currentValue) + { + propertyValue = [NSString stringWithFormat: @"<%@>%@", + nodeTag, *currentValue, nodeTag]; + propDict = properties200; + } + else + { + propertyValue = [NSString stringWithFormat: @"<%@/>", nodeTag]; + propDict = properties404; + } + [propDict addObject: propertyValue]; + property++; + currentValue++; + } + free (values); + + if ([properties200 count]) + [propstats addObject: [NSDictionary dictionaryWithObjectsAndKeys: + properties200, @"properties", + @"HTTP/1.1 200 OK", @"status", + nil]]; + if ([properties404 count]) + [propstats addObject: [NSDictionary dictionaryWithObjectsAndKeys: + properties404, @"properties", + @"HTTP/1.1 404 Not Found", @"status", + nil]]; +// NSLog (@"/_propstats:ofObject:: %@", [NSDate date]); + + return propstats; +} + +- (void) _appendPropstat: (NSDictionary *) propstat + toBuffer: (NSMutableString *) r +{ + NSArray *properties; + unsigned int count, max; + + [r appendString: @""]; + properties = [propstat objectForKey: @"properties"]; + max = [properties count]; + for (count = 0; count < max; count++) + [r appendString: [properties objectAtIndex: count]]; + [r appendString: @""]; + [r appendString: [propstat objectForKey: @"status"]]; + [r appendString: @""]; +} + +- (void) appendObject: (NSDictionary *) object + properties: (NSString **) properties + count: (unsigned int) propertiesCount + withBaseURL: (NSString *) baseURL + toBuffer: (NSMutableString *) r +{ + NSArray *propstats; + unsigned int count, max; + + [r appendFormat: @""]; + [r appendString: baseURL]; + [r appendString: [[object objectForKey: @"c_name"] stringByEscapingURL]]; + [r appendString: @""]; + +// NSLog (@"(appendPropstats...): %@", [NSDate date]); + propstats = [self _propstats: properties count: propertiesCount + ofObject: object]; + max = [propstats count]; + for (count = 0; count < max; count++) + [self _appendPropstat: [propstats objectAtIndex: count] + toBuffer: r]; +// NSLog (@"/(appendPropstats...): %@", [NSDate date]); + + [r appendString: @""]; +} + +- (void) appendMissingObjectRef: (NSString *) href + toBuffer: (NSMutableString *) r +{ + [r appendString: @""]; + [r appendString: href]; + [r appendString: @"HTTP/1.1 404 Not Found"]; +} + +- (void) _appendComponentProperties: (NSArray *) properties + matchingURLs: (id ) refs + toResponse: (WOResponse *) response +{ + NSObject *element; + NSString *url, *baseURL, *cname; + NSString **propertiesArray; + NSMutableString *buffer; + unsigned int count, max, propertiesCount; + + baseURL = [self davURLAsString]; +#warning review this when fixing http://www.scalableogo.org/bugs/view.php?id=276 + if (![baseURL hasSuffix: @"/"]) + baseURL = [NSString stringWithFormat: @"%@/", baseURL]; + + propertiesArray = [properties asPointersOfObjects]; + propertiesCount = [properties count]; + + max = [refs length]; + buffer = [NSMutableString stringWithCapacity: max*512]; + + for (count = 0; count < max; count++) + { + element = [refs objectAtIndex: count]; + url = [[[element firstChild] nodeValue] stringByUnescapingURL]; + cname = [self _deduceObjectNameFromURL: url fromBaseURL: baseURL]; + if (cname) + [self appendObject: [source lookupContactEntry: cname] + properties: propertiesArray + count: propertiesCount + withBaseURL: baseURL + toBuffer: buffer]; + else + [self appendMissingObjectRef: url + toBuffer: buffer]; + } + [response appendContentString: buffer]; +// NSLog (@"/adding properties with url"); + + NSZoneFree (NULL, propertiesArray); +} + +- (WOResponse *) performMultigetInContext: (WOContext *) queryContext + inNamespace: (NSString *) namespace +{ + WOResponse *r; + id document; + DOMElement *documentElement, *propElement; + + r = [context response]; + [r prepareDAVResponse]; + [r appendContentString: + [NSString stringWithFormat: @"", namespace]]; + document = [[queryContext request] contentAsDOMDocument]; + documentElement = (DOMElement *) [document documentElement]; + propElement = [documentElement firstElementWithTag: @"prop" + inNamespace: @"DAV:"]; + [self _appendComponentProperties: [propElement flatPropertyNameOfSubElements] + matchingURLs: [documentElement getElementsByTagName: @"href"] + toResponse: r]; + [r appendContentString:@""]; + + return r; +} + +- (id) davAddressbookMultiget: (id) queryContext +{ + return [self performMultigetInContext: queryContext + inNamespace: @"urn:ietf:params:xml:ns:carddav"]; +} + - (NSString *) davDisplayName { return displayName; diff --git a/SoObjects/Contacts/SOGoUserFolder+Contacts.m b/SoObjects/Contacts/SOGoUserFolder+Contacts.m index 817c91cb8..2244456d4 100644 --- a/SoObjects/Contacts/SOGoUserFolder+Contacts.m +++ b/SoObjects/Contacts/SOGoUserFolder+Contacts.m @@ -29,6 +29,7 @@ #import #import +#import #import #import @@ -58,4 +59,30 @@ return [NSArray arrayWithObject: tag]; } +- (NSArray *) davDirectoryGateway +{ + NSArray *tag, *sources; + SOGoContactFolders *parent; + SOGoUserManager *um; + NSString *domain, *url; + + domain = [[context activeUser] domain]; + um = [SOGoUserManager sharedUserManager]; + sources = [um addressBookSourceIDsInDomain: domain]; + if ([sources count] > 0) + { + parent = [self privateContacts: @"Contacts" inContext: context]; + url = [NSString stringWithFormat: @"%@%@/", [parent davURLAsString], + [sources objectAtIndex: 0]]; + tag = [NSArray arrayWithObject: + [NSArray arrayWithObjects: @"href", @"DAV:", @"D", + url, nil]]; + } + else + tag = nil; + + return tag; +} + + @end From 4489085c59496805223fb1df9e885cd9a5dfae5f Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 27 Mar 2012 20:55:20 +0000 Subject: [PATCH 2/5] Monotone-Parent: c1548a6a3e72a7d9b567b63d50198115fa48ab0b Monotone-Revision: 7a38303ac45419355a1bdedefd53d63339248410 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-03-27T20:55:20 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 1 + SoObjects/Contacts/SOGoContactSourceFolder.m | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8c39ecf6a..b053aa93c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,7 @@ * SoObjects/Contacts/SOGoUserFolder+Contacts.m (-davDirectoryGateway): new getter that returns the url to the first available directory source. + (-davResourceType): declare resource as "directory" (carddav). 2012-03-26 Wolfgang Sourdeau diff --git a/SoObjects/Contacts/SOGoContactSourceFolder.m b/SoObjects/Contacts/SOGoContactSourceFolder.m index 1f6437bb9..260a7ce35 100644 --- a/SoObjects/Contacts/SOGoContactSourceFolder.m +++ b/SoObjects/Contacts/SOGoContactSourceFolder.m @@ -137,14 +137,13 @@ - (NSArray *) davResourceType { NSMutableArray *resourceType; - NSArray *cardDavCollection; - - cardDavCollection - = [NSArray arrayWithObjects: @"addressbook", - @"urn:ietf:params:xml:ns:carddav", nil]; + NSArray *type; resourceType = [NSMutableArray arrayWithArray: [super davResourceType]]; - [resourceType addObject: cardDavCollection]; + type = [NSArray arrayWithObjects: @"addressbook", XMLNS_CARDDAV, nil]; + [resourceType addObject: type]; + type = [NSArray arrayWithObjects: @"directory", XMLNS_CARDDAV, nil]; + [resourceType addObject: type]; return resourceType; } @@ -621,7 +620,7 @@ - (id) davAddressbookMultiget: (id) queryContext { return [self performMultigetInContext: queryContext - inNamespace: @"urn:ietf:params:xml:ns:carddav"]; + inNamespace: XMLNS_CARDDAV]; } - (NSString *) davDisplayName From d28ca1ecdcdfbcbd3c2090d04f3132885cdb04f3 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 28 Mar 2012 04:42:02 +0000 Subject: [PATCH 3/5] Monotone-Parent: 7a38303ac45419355a1bdedefd53d63339248410 Monotone-Revision: f8af7a968c459aff400e85a6c5422a0c7a370167 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-03-28T04:42:02 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 +++++ SoObjects/SOGo/LDAPSource.m | 14 +++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index b053aa93c..efb9ae8ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-03-28 Wolfgang Sourdeau + + * SoObjects/SOGo/LDAPSource.m (-allEntryIDs): take the _filter + ivar into account. + 2012-03-27 Wolfgang Sourdeau * SoObjects/Contacts/SOGoContactFolders.m diff --git a/SoObjects/SOGo/LDAPSource.m b/SoObjects/SOGo/LDAPSource.m index b5cbc146a..3269ca10c 100644 --- a/SoObjects/SOGo/LDAPSource.m +++ b/SoObjects/SOGo/LDAPSource.m @@ -830,6 +830,8 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField NSEnumerator *entries; NGLdapEntry *currentEntry; NGLdapConnection *ldapConnection; + EOQualifier *qualifier; + NSMutableString *qs; NSString *value; NSArray *attributes; NSMutableArray *ids; @@ -838,17 +840,23 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField ldapConnection = [self _ldapConnection]; attributes = [NSArray arrayWithObject: IDField]; + + qs = [NSMutableString stringWithFormat: @"(%@='*')", CNField]; + if ([_filter length]) + [qs appendFormat: @" AND %@", _filter]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + if ([_scope caseInsensitiveCompare: @"BASE"] == NSOrderedSame) entries = [ldapConnection baseSearchAtBaseDN: baseDN - qualifier: nil + qualifier: qualifier attributes: attributes]; else if ([_scope caseInsensitiveCompare: @"ONE"] == NSOrderedSame) entries = [ldapConnection flatSearchAtBaseDN: baseDN - qualifier: nil + qualifier: qualifier attributes: attributes]; else entries = [ldapConnection deepSearchAtBaseDN: baseDN - qualifier: nil + qualifier: qualifier attributes: attributes]; while ((currentEntry = [entries nextObject])) From dcb952e1b7e04e2c42c43338e72602d0a588e7f9 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 28 Mar 2012 15:05:58 +0000 Subject: [PATCH 4/5] Monotone-Parent: f8af7a968c459aff400e85a6c5422a0c7a370167 Monotone-Revision: 600b3a1c268cabeca401fb335f2e4c76bd1709b7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-03-28T15:05:58 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 ++++++ SoObjects/Contacts/SOGoFolder+CardDAV.m | 17 +++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index efb9ae8ec..ca5486e35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2012-03-28 Wolfgang Sourdeau + * SoObjects/Contacts/SOGoFolder+CardDAV.m (_isValidFilter:): + accept "email" as filter name. + (_appendObject:withBaseURL:toREPORTResponse:): fixed the ordering + of XML elements as the address*-data props where put outside of + the tree. + * SoObjects/SOGo/LDAPSource.m (-allEntryIDs): take the _filter ivar into account. diff --git a/SoObjects/Contacts/SOGoFolder+CardDAV.m b/SoObjects/Contacts/SOGoFolder+CardDAV.m index fed4c2105..3466e940e 100644 --- a/SoObjects/Contacts/SOGoFolder+CardDAV.m +++ b/SoObjects/Contacts/SOGoFolder+CardDAV.m @@ -73,17 +73,17 @@ etagLine = [NSString stringWithFormat: @"%@", [component davEntityTag]]; [r appendContentString: etagLine]; - [r appendContentString: @"" - @"HTTP/1.1 200 OK" - @"" - @""]; + [r appendContentString: @""]; contactString = [[component contentAsString] stringByEscapingXMLString]; [r appendContentString: contactString]; - [r appendContentString: @"" - @""]; - [r appendContentString: contactString]; [r appendContentString: @"" - @""]; + @""]; + [r appendContentString: contactString]; + [r appendContentString: @"" + @"" + @"HTTP/1.1 200 OK" + @"" + @""]; } } @@ -124,6 +124,7 @@ return ([newString isEqualToString: @"sn"] || [newString isEqualToString: @"givenname"] + || [newString isEqualToString: @"email"] || [newString isEqualToString: @"mail"] || [newString isEqualToString: @"telephonenumber"]); } From 269393250b5b2a4b2aece6145b5c20a9a0e47f6a Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 28 Mar 2012 20:04:32 +0000 Subject: [PATCH 5/5] Monotone-Parent: 600b3a1c268cabeca401fb335f2e4c76bd1709b7 Monotone-Revision: d93b5b4142f73cdb24bac181e6d92140b7a59313 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-03-28T20:04:32 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 +++++++ OpenChange/SOGoMAPIFSMessage.h | 2 +- OpenChange/SOGoMAPIFSMessage.m | 33 ++++++++++++++++----------------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index ca5486e35..a7793891b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2012-03-28 Wolfgang Sourdeau + * OpenChange/SOGoMAPIFSMessage.m + (_readFileChangesDataWithDate:andInode:): use the inode number + rather than the filesize as change indicator since a new file is + created each time the dictionary is written to disk, thanks to the + "atomically" flag. + (-save): write the file atomically. + * SoObjects/Contacts/SOGoFolder+CardDAV.m (_isValidFilter:): accept "email" as filter name. (_appendObject:withBaseURL:toREPORTResponse:): fixed the ordering diff --git a/OpenChange/SOGoMAPIFSMessage.h b/OpenChange/SOGoMAPIFSMessage.h index 0a0385721..ec6494938 100644 --- a/OpenChange/SOGoMAPIFSMessage.h +++ b/OpenChange/SOGoMAPIFSMessage.h @@ -31,7 +31,7 @@ @interface SOGoMAPIFSMessage : SOGoMAPIVolatileMessage { NSString *completeFilename; - NSUInteger fileSize; + NSUInteger inode; NSData *lastModificationTime; } diff --git a/OpenChange/SOGoMAPIFSMessage.m b/OpenChange/SOGoMAPIFSMessage.m index 495bba96d..8a854fa1d 100644 --- a/OpenChange/SOGoMAPIFSMessage.m +++ b/OpenChange/SOGoMAPIFSMessage.m @@ -41,7 +41,7 @@ if ((self = [super init])) { completeFilename = nil; - fileSize = 0; + inode = 0; lastModificationTime = nil; } @@ -86,7 +86,7 @@ } - (BOOL) _readFileChangesDataWithDate: (NSDate **) newLMTime - andSize: (NSUInteger *) newFileSize + andInode: (NSUInteger *) newInode { BOOL rc; NSDictionary *attributes; @@ -97,7 +97,7 @@ if (attributes) { *newLMTime = [attributes fileModificationDate]; - *newFileSize = [attributes fileSize]; + *newInode = [attributes fileSystemFileNumber]; rc = YES; } else @@ -107,22 +107,22 @@ } - (BOOL) _checkFileChangesDataWithDate: (NSDate **) newLMTime - andSize: (NSUInteger *) newFileSize + andInode: (NSUInteger *) newInode { BOOL hasChanged = NO; NSDate *lastLMTime; - NSUInteger lastFileSize; + NSUInteger lastInode; if ([self _readFileChangesDataWithDate: &lastLMTime - andSize: &lastFileSize]) + andInode: &lastInode]) { - if (fileSize != lastFileSize + if (inode != lastInode || ![lastModificationTime isEqual: lastLMTime]) { if (lastLMTime) *newLMTime = lastLMTime; - if (newFileSize) - *newFileSize = lastFileSize; + if (newInode) + *newInode = lastInode; hasChanged = YES; } } @@ -136,10 +136,10 @@ NSString *error; NSPropertyListFormat format; NSDate *lastLMTime; - NSUInteger lastFileSize; + NSUInteger lastInode; if ([self _checkFileChangesDataWithDate: &lastLMTime - andSize: &lastFileSize]) + andInode: &lastInode]) { [self logWithFormat: @"file '%@' new or modified: rereading properties", [self completeFilename]]; @@ -158,7 +158,7 @@ @" of message: '%@'", error]; } ASSIGN (lastModificationTime, lastLMTime); - fileSize = lastFileSize; + inode = lastInode; } return [super properties]; @@ -168,7 +168,7 @@ { NSData *content; NSDate *lastLMTime; - NSUInteger lastFileSize; + NSUInteger lastInode; [container ensureDirectory]; @@ -178,14 +178,13 @@ dataFromPropertyList: [self properties] format: NSPropertyListBinaryFormat_v1_0 errorDescription: NULL]; - if (![content writeToFile: [self completeFilename] atomically: NO]) + if (![content writeToFile: [self completeFilename] atomically: YES]) [NSException raise: @"MAPIStoreIOException" format: @"could not save message"]; - [self _readFileChangesDataWithDate: &lastLMTime - andSize: &lastFileSize]; + [self _readFileChangesDataWithDate: &lastLMTime andInode: &lastInode]; ASSIGN (lastModificationTime, lastLMTime); - fileSize = lastFileSize; + inode = lastInode; // [self logWithFormat: @"fs message written to '%@'", [self completeFilename]]; }