From e551f917d5e1301a377f9697f4176e22272d0172 Mon Sep 17 00:00:00 2001 From: C Robert Date: Tue, 2 Jun 2009 14:05:59 +0000 Subject: [PATCH 1/9] Monotone-Parent: 52ed7c612278254b79fdf946b5a0b54fe032dad4 Monotone-Revision: e88954c069bb059beab0f156e13851671bd1054a Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-06-02T14:05:59 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 9 + .../Appointments/SOGoAppointmentFolder.m | 167 +++++++++++++----- 2 files changed, 134 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2518c58c3..e67cd00d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-06-02 Cyril Robert + + * SoObjects/Appointments/SOGoAppointmentFolder.m (_enforceTimeLimitOnFilter): + Rewrote algorithm. + 2009-06-02 Ludovic Marcotte * Updated the documentation (version change, Russian @@ -19,6 +24,10 @@ * UI/WebServerResources/UIxContactsUserFolders.js (onSearchFormSubmit): Fixed encoding issue/crash. + * SoObjects/Appointments/SOGoAppointmentFolder.m (_parseCalendarFilter): + Added support for default SOGoDAVCalendarStartTimeLimit, which is the + maximum number of days for dav queries. + Added: _enforceTimeLimitOnFilter, _getMaxStartDate and _getStartTimeLimit 2009-05-30 Ludovic Marcotte diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index d24730ac4..3c4d1f3c7 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -1224,6 +1224,75 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir [r appendString: @"HTTP/1.1 404 Not Found"]; } +- (int) _getStartTimeLimit +{ + NSUserDefaults *ud; + int interval; + + ud = [NSUserDefaults standardUserDefaults]; + interval = [ud integerForKey: @"SOGoDAVCalendarStartTimeLimit"]; + + return interval; +} + +- (NSCalendarDate *) _getMaxStartDate +{ + NSCalendarDate *tmp, *rc = NULL; + int interval; + + interval = [self _getStartTimeLimit]; + if (interval > 0) + { + tmp = [NSCalendarDate date]; + rc = [tmp addTimeInterval: interval * -86400]; + } + + return rc; +} + +- (void) _enforceTimeLimitOnFilter: (NSMutableDictionary *) filter +{ + NSCalendarDate *start, *end, *now; + int limit, interval, intervalStart, intervalEnd; + + start = [filter objectForKey: @"start"]; + end = [filter objectForKey: @"end"]; + now = [NSCalendarDate date]; + limit = [self _getStartTimeLimit]; + interval = ([end timeIntervalSinceDate: start] / 86400); + + if (limit > 0 && interval > limit) + { + if ([now compare: start] == NSOrderedDescending + && [now compare: end] == NSOrderedAscending) + { + intervalStart = [now timeIntervalSinceDate: start] / 86400; + intervalEnd = [end timeIntervalSinceDate: now] / 86400; + if (intervalStart > limit / 2) + { + start = [now addTimeInterval: (limit / 2) * -86400]; + [filter setObject: start forKey: @"start"]; + } + if (intervalEnd > limit / 2) + { + end = [now addTimeInterval: (limit / 2) * 86400]; + [filter setObject: end forKey: @"end"]; + } + + } + else if ([now compare: end] == NSOrderedDescending) + { + start = [end addTimeInterval: limit * -86400]; + [filter setObject: start forKey: @"start"]; + } + else if ([now compare: start] == NSOrderedAscending) + { + end = [start addTimeInterval: limit * 86400]; + [filter setObject: end forKey: @"end"]; + } + } +} + - (void) _appendTimeRange: (id ) timeRangeElement toFilter: (NSMutableDictionary *) filter { @@ -1233,6 +1302,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir [filter setObject: parsedDate forKey: @"start"]; parsedDate = [[timeRangeElement attribute: @"end"] asCalendarDate]; [filter setObject: parsedDate forKey: @"end"]; + + [self _enforceTimeLimitOnFilter: filter]; } #warning This method lacks support for timeranges @@ -1264,6 +1335,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir id parentNode; id elements; NSString *componentName; + NSCalendarDate *maxStart; parentNode = (id ) [filterElement parentNode]; if ([[parentNode tagName] isEqualToString: @"comp-filter"] @@ -1281,6 +1353,18 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir if ([elements length]) [self _appendPropertyFilter: [elements objectAtIndex: 0] toFilter: filterData]; + + if ( ![filterData objectForKey: @"start"] ) + { + maxStart = [self _getMaxStartDate]; + if (maxStart) + { + [filterData setObject: maxStart + forKey: @"start"]; + [filterData setObject: [NSCalendarDate distantFuture] + forKey: @"end"]; + } + } } else filterData = nil; @@ -1306,21 +1390,21 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir children = [[propList objectAtIndex: count] childNodes]; max2 = [children length]; for (count2 = 0; count2 < max2; count2++) - { - currentChild = [children objectAtIndex: count2]; - if ([currentChild conformsToProtocol: @protocol (DOMElement)]) - { - flatProperty = [NSString stringWithFormat: @"{%@}%@", - [currentChild namespaceURI], - [currentChild nodeName]]; - [properties addObject: flatProperty]; - } - } + { + currentChild = [children objectAtIndex: count2]; + if ([currentChild conformsToProtocol: @protocol (DOMElement)]) + { + flatProperty = [NSString stringWithFormat: @"{%@}%@", + [currentChild namespaceURI], + [currentChild nodeName]]; + [properties addObject: flatProperty]; + } + } -// while ([children hasChildNodes]) -// [properties addObject: [children next]]; + // while ([children hasChildNodes]) + // [properties addObject: [children next]]; } -// NSLog (@"/parseRequestProperties: %@", [NSDate date]); + // NSLog (@"/parseRequestProperties: %@", [NSDate date]); return properties; } @@ -1343,7 +1427,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir node = [children objectAtIndex: count]; filter = [self _parseCalendarFilter: node]; if (filter) - [filters addObject: filter]; + [filters addObject: filter]; } // NSLog (@"/parseCalendarFilter: %@", [NSDate date]); @@ -1390,11 +1474,11 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir { keyField = [NSString stringWithFormat: @"c_%@", currentKey]; if ([fields containsObject: keyField]) - { - filterString = [self _additionalFilterKey: keyField - value: [filter objectForKey: currentKey]]; - [filters addObject: filterString]; - } + { + filterString = [self _additionalFilterKey: keyField + value: [filter objectForKey: currentKey]]; + [filters addObject: filterString]; + } } if ([filters count]) @@ -1473,10 +1557,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir return nil; } - - (void) _appendComponentProperties: (NSString **) properties - matchingFilters: (NSArray *) filters - toResponse: (WOResponse *) response + matchingFilters: (NSArray *) filters + toResponse: (WOResponse *) response { NSArray *apts, *fields; NSDictionary *currentFilter; @@ -1495,8 +1578,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir if ([*properties caseInsensitiveCompare: @"{DAV:}getetag"] == NSOrderedSame && !*(properties+1)) fields = [NSArray arrayWithObjects: @"c_name", @"c_creationdate", - @"c_lastmodified", @"c_version", - @"c_component", nil]; + @"c_lastmodified", @"c_version", + @"c_component", nil]; else fields = reportQueryFields; @@ -1506,19 +1589,19 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir additionalFilters = [self _composeAdditionalFilters: currentFilter]; //NSLog(@"query"); apts = [self bareFetchFields: fields - from: [currentFilter objectForKey: @"start"] - to: [currentFilter objectForKey: @"end"] - title: [currentFilter objectForKey: @"title"] - component: [currentFilter objectForKey: @"name"] - additionalFilters: additionalFilters]; + from: [currentFilter objectForKey: @"start"] + to: [currentFilter objectForKey: @"end"] + title: [currentFilter objectForKey: @"title"] + component: [currentFilter objectForKey: @"name"] + additionalFilters: additionalFilters]; //NSLog(@"adding properties"); max = [apts count]; buffer = [[NSMutableString alloc] initWithCapacity: max*512]; for (count = 0; count < max; count++) - [self appendObject: [apts objectAtIndex: count] - properties: properties - withBaseURL: baseURL - toBuffer: buffer]; + [self appendObject: [apts objectAtIndex: count] + properties: properties + withBaseURL: baseURL + toBuffer: buffer]; //NSLog(@"done"); [response appendContentString: buffer]; [buffer release]; @@ -1672,15 +1755,15 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir record = [records objectAtIndex: count]; recordURL = [cnames objectForKey: [record objectForKey: @"c_name"]]; if (recordURL) - [components setObject: record forKey: recordURL]; + [components setObject: record forKey: recordURL]; } return components; } - (void) _appendComponentProperties: (NSString **) properties - matchingURLs: (id ) refs - toResponse: (WOResponse *) response + matchingURLs: (id ) refs + toResponse: (WOResponse *) response { NSObject *element; NSDictionary *currentComponent, *components; @@ -1708,13 +1791,13 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir { currentComponent = [components objectForKey: [urls objectAtIndex: count]]; if (currentComponent) - [self appendObject: currentComponent - properties: properties - withBaseURL: baseURL - toBuffer: buffer]; + [self appendObject: currentComponent + properties: properties + withBaseURL: baseURL + toBuffer: buffer]; else - [self appendMissingObjectRef: currentURL - toBuffer: buffer]; + [self appendMissingObjectRef: currentURL + toBuffer: buffer]; } [response appendContentString: buffer]; [buffer release]; From 1802fe1e63164bae9f02ae0153f98d952630b741 Mon Sep 17 00:00:00 2001 From: C Robert Date: Tue, 2 Jun 2009 14:39:21 +0000 Subject: [PATCH 2/9] Fixed incoherence Monotone-Parent: e88954c069bb059beab0f156e13851671bd1054a Monotone-Revision: 2e82af935f99a50853aa4b3dfee4ab97d8f9fc66 Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-06-02T14:39:21 Monotone-Branch: ca.inverse.sogo --- .../Appointments/SOGoAppointmentFolder.m | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 3c4d1f3c7..3a6aeeaf3 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -901,8 +901,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir title: (NSString *) title component: (id) _component additionalFilters: (NSString *) filters - includeProtectedInformation: (BOOL) _includeProtectedInformation; - + includeProtectedInformation: (BOOL) _includeProtectedInformation { EOQualifier *qualifier; GCSFolder *folder; @@ -1306,6 +1305,20 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir [self _enforceTimeLimitOnFilter: filter]; } +- (void) _addDateRangeLimitToFilter: (NSMutableDictionary *) filter +{ + NSCalendarDate *now; + int limit; + + now = [NSCalendarDate date]; + limit = [self _getStartTimeLimit]; + + [filter setObject: [now addTimeInterval: (limit / 2) * -86400] + forKey: @"start"]; + [filter setObject: [now addTimeInterval: (limit / 2) * 86400] + forKey: @"end"]; +} + #warning This method lacks support for timeranges - (void) _appendPropertyFilter: (id ) propFilter toFilter: (NSMutableDictionary *) filter @@ -1359,10 +1372,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir maxStart = [self _getMaxStartDate]; if (maxStart) { - [filterData setObject: maxStart - forKey: @"start"]; - [filterData setObject: [NSCalendarDate distantFuture] - forKey: @"end"]; + [self _addDateRangeLimitToFilter: filterData]; } } } From 3354a88c47d8714e429f41a4aebe5b52dec8e49e Mon Sep 17 00:00:00 2001 From: C Robert Date: Tue, 2 Jun 2009 14:40:50 +0000 Subject: [PATCH 3/9] Reindent Monotone-Parent: 2e82af935f99a50853aa4b3dfee4ab97d8f9fc66 Monotone-Revision: 73b8ecc6d6621856d5066773cd34a3de9ba7df47 Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-06-02T14:40:50 Monotone-Branch: ca.inverse.sogo --- .../Appointments/SOGoAppointmentFolder.m | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 3a6aeeaf3..f8776336f 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -880,27 +880,27 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir while ((currentRecord = [ma nextObject])) { accessClass - = [[currentRecord objectForKey: @"c_classification"] intValue]; + = [[currentRecord objectForKey: @"c_classification"] intValue]; role = roles[accessClass]; if (!role) - { - fullRole = [self roleForComponentsWithAccessClass: accessClass - forUser: uid]; - if ([fullRole length] > 9) - role = [fullRole substringFromIndex: 9]; - roles[accessClass] = role; - } + { + fullRole = [self roleForComponentsWithAccessClass: accessClass + forUser: uid]; + if ([fullRole length] > 9) + role = [fullRole substringFromIndex: 9]; + roles[accessClass] = role; + } if ([role isEqualToString: @"DAndTViewer"]) - [currentRecord removeObjectsForKeys: stripFields]; + [currentRecord removeObjectsForKeys: stripFields]; } } - (NSArray *) fetchFields: (NSArray *) _fields - from: (NSCalendarDate *) _startDate - to: (NSCalendarDate *) _endDate - title: (NSString *) title - component: (id) _component - additionalFilters: (NSString *) filters + from: (NSCalendarDate *) _startDate + to: (NSCalendarDate *) _endDate + title: (NSString *) title + component: (id) _component + additionalFilters: (NSString *) filters includeProtectedInformation: (BOOL) _includeProtectedInformation { EOQualifier *qualifier; @@ -928,11 +928,11 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir if (_startDate) { if (_endDate) - endDate = _endDate; + endDate = _endDate; else - endDate = [NSCalendarDate distantFuture]; + endDate = [NSCalendarDate distantFuture]; r = [NGCalendarDateRange calendarDateRangeWithStartDate: _startDate - endDate: endDate]; + endDate: endDate]; dateSqlString = [self _sqlStringRangeFrom: _startDate to: endDate]; } else @@ -995,14 +995,14 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir records = [folder fetchFields: fields matchingQualifier: qualifier]; if (records) - { - if (r) - records = [self fixupCyclicRecords: records fetchRange: r]; - if (ma) - [ma addObjectsFromArray: records]; - else - ma = [NSMutableArray arrayWithArray: records]; - } + { + if (r) + records = [self fixupCyclicRecords: records fetchRange: r]; + if (ma) + [ma addObjectsFromArray: records]; + else + ma = [NSMutableArray arrayWithArray: records]; + } } if (!ma) { From df68da38fa82bc7a02d2db29c37033bf268956c7 Mon Sep 17 00:00:00 2001 From: C Robert Date: Tue, 2 Jun 2009 15:28:42 +0000 Subject: [PATCH 4/9] Monotone-Parent: 73b8ecc6d6621856d5066773cd34a3de9ba7df47 Monotone-Revision: fd50c862e356e0c0c102bf3b5901ec2e9de8241e Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-06-02T15:28:42 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 2 +- .../Appointments/SOGoAppointmentFolder.m | 51 ++++++++++++++----- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index e67cd00d5..b044c20ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ 2009-06-02 Cyril Robert * SoObjects/Appointments/SOGoAppointmentFolder.m (_enforceTimeLimitOnFilter): - Rewrote algorithm. + Rewrote algorithm, fixed cyclic events issue. 2009-06-02 Ludovic Marcotte diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index f8776336f..109d1027a 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -475,11 +475,11 @@ static NSArray *reportQueryFields = nil; } - (NSArray *) bareFetchFields: (NSArray *) fields - from: (NSCalendarDate *) startDate - to: (NSCalendarDate *) endDate - title: (NSString *) title - component: (id) component - additionalFilters: (NSString *) filters + from: (NSCalendarDate *) startDate + to: (NSCalendarDate *) endDate + title: (NSString *) title + component: (id) component + additionalFilters: (NSString *) filters { EOQualifier *qualifier; GCSFolder *folder; @@ -1016,8 +1016,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir currentLogin = [[context activeUser] login]; if (![currentLogin isEqualToString: owner] && !_includeProtectedInformation) [self _fixupProtectedInformation: [ma objectEnumerator] - inFields: _fields - forUser: currentLogin]; + inFields: _fields + forUser: currentLogin]; if (rememberRecords) [self _rememberRecords: ma]; @@ -1375,6 +1375,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir [self _addDateRangeLimitToFilter: filterData]; } } + [filterData setObject: [NSNumber numberWithBool: NO] forKey: @"iscycle"]; } else filterData = nil; @@ -1419,6 +1420,18 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir return properties; } +- (NSDictionary *) _makeCyclicFilterFrom: (NSDictionary *) filter +{ + NSMutableDictionary *rc; + + rc = [NSMutableDictionary dictionaryWithDictionary: filter]; + [rc removeObjectForKey: @"start"]; + [rc removeObjectForKey: @"end"]; + [rc setObject: [NSNumber numberWithBool: YES] forKey: @"iscycle"]; + + return rc; +} + - (NSArray *) _parseCalendarFilters: (id ) parentNode { id children; @@ -1437,7 +1450,10 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir node = [children objectAtIndex: count]; filter = [self _parseCalendarFilter: node]; if (filter) - [filters addObject: filter]; + { + [filters addObject: filter]; + [filters addObject: [self _makeCyclicFilterFrom: filter]]; + } } // NSLog (@"/parseCalendarFilter: %@", [NSDate date]); @@ -1445,17 +1461,17 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir } - (NSString *) _additionalFilterKey: (NSString *) key - value: (NSString *) value + value: (NSString *) value { NSString *filterString; if ([value length]) { if ([value isEqualToString: @"NULL"]) - filterString = [NSString stringWithFormat: @"(%@ = '')", key]; + filterString = [NSString stringWithFormat: @"(%@ = '')", key]; else - filterString - = [NSString stringWithFormat: @"(%@ like '%%%@%%')", key, value]; + filterString + = [NSString stringWithFormat: @"(%@ like '%%%@%%')", key, value]; } else filterString = [NSString stringWithFormat: @"(%@ != '')", key]; @@ -1470,6 +1486,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir NSString *currentKey, *keyField, *filterString; static NSArray *fields = nil; NSMutableArray *filters; + NSNumber *cycle; #warning the list of fields should be taken from the .ocs description file if (!fields) @@ -1491,6 +1508,16 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir } } + // Exception for iscycle + cycle = [filter objectForKey: @"iscycle"]; + if (cycle) + { + filterString = [NSString stringWithFormat: @"(c_iscycle = '%d')", + [cycle intValue]]; + NSLog (filterString); + [filters addObject: filterString]; + } + if ([filters count]) additionalFilter = [filters componentsJoinedByString: @" and "]; else From f7ce31f7cbaac2e4b2e0d9aa06807ba979fe5b1d Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 2 Jun 2009 16:22:28 +0000 Subject: [PATCH 5/9] Monotone-Parent: fd50c862e356e0c0c102bf3b5901ec2e9de8241e Monotone-Revision: 480d39a8c4def3358ca87a844e455c2ffe987f5f Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-02T16:22:28 Monotone-Branch: ca.inverse.sogo --- SOPE/GDLContentStore/ChangeLog | 5 +++++ SOPE/GDLContentStore/GCSFolder.h | 2 ++ SOPE/GDLContentStore/GCSFolder.m | 37 ++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/SOPE/GDLContentStore/ChangeLog b/SOPE/GDLContentStore/ChangeLog index 7d27f8619..9093b1b91 100644 --- a/SOPE/GDLContentStore/ChangeLog +++ b/SOPE/GDLContentStore/ChangeLog @@ -1,3 +1,8 @@ +2009-06-02 Wolfgang Sourdeau + + * GCSFolder.m ([GCSFolder -recordsCountByExcludingDeleted:]): new + method that returns the amount of records in a GCS folder. + 2009-03-24 Wolfgang Sourdeau * GCSFolderType.m ([GCSFolderType +folderTypeWithName:_typeName]): diff --git a/SOPE/GDLContentStore/GCSFolder.h b/SOPE/GDLContentStore/GCSFolder.h index a586e9cad..91debe945 100644 --- a/SOPE/GDLContentStore/GCSFolder.h +++ b/SOPE/GDLContentStore/GCSFolder.h @@ -140,6 +140,8 @@ - (void) deleteAclMatchingQualifier: (EOQualifier *) _q; - (void) deleteAclWithSpecification: (EOFetchSpecification *) _fs; +- (unsigned int) recordsCountByExcludingDeleted: (BOOL) includeDeleted; + @end #endif /* __GDLContentStore_GCSFolder_H__ */ diff --git a/SOPE/GDLContentStore/GCSFolder.m b/SOPE/GDLContentStore/GCSFolder.m index 298c7187a..55dd40623 100644 --- a/SOPE/GDLContentStore/GCSFolder.m +++ b/SOPE/GDLContentStore/GCSFolder.m @@ -1291,6 +1291,43 @@ static NSArray *contentFieldNames = nil; } } +- (unsigned int) recordsCountByExcludingDeleted: (BOOL) excludeDeleted +{ + NSMutableString *sqlString; + EOAdaptorChannel *channel; + NSException *error; + NSDictionary *row; + unsigned int count; + NSArray *attrs; + + count = 0; + + sqlString = [NSMutableString stringWithFormat: + @"SELECT COUNT(*) AS CNT FROM %@", + [self storeTableName]]; + if (excludeDeleted) + [sqlString appendString: @" WHERE (c_deleted != 1 OR c_deleted IS NULL)"]; + + channel = [self acquireStoreChannel]; + if (channel) + { + error = [channel evaluateExpressionX: sqlString]; + if (error) + [self errorWithFormat: @"%s: cannot execute SQL '%@': %@", + __PRETTY_FUNCTION__, sqlString, error]; + else + { + attrs = [channel describeResults: NO]; + row = [channel fetchAttributes: attrs withZone: NULL]; + count = [[row objectForKey: @"cnt"] unsignedIntValue]; + [channel cancelFetch]; + } + [self releaseChannel: channel]; + } + + return count; +} + /* description */ - (NSString *)description { From 1f0b289ef7dfaed6746d9137766dc9b6cc60da06 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 2 Jun 2009 16:23:32 +0000 Subject: [PATCH 6/9] Monotone-Parent: 480d39a8c4def3358ca87a844e455c2ffe987f5f Monotone-Revision: 653a47a63f4f9fb59c7e85515dd7937dbaa2b23e Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-02T16:23:32 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 8 + Tools/GNUmakefile | 21 ++ Tools/GNUmakefile.preamble | 20 ++ Tools/sogo-contacts-checkdoubles.m | 187 +++++++++++ Tools/sogo-contacts-removedoubles.m | 476 ++++++++++++++++++++++++++++ 5 files changed, 712 insertions(+) create mode 100644 Tools/GNUmakefile create mode 100644 Tools/GNUmakefile.preamble create mode 100644 Tools/sogo-contacts-checkdoubles.m create mode 100644 Tools/sogo-contacts-removedoubles.m diff --git a/ChangeLog b/ChangeLog index b044c20ac..a45b11cbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-06-02 Wolfgang Sourdeau + + * Tools/sogo-contacts-removedoubles.m: new maintenance utility + that removes double records in specified addressbooks. + + * Tools/sogo-contacts-checkdoubles.m: new maintenance utility that + helps determine which contact folders need cleanup. + 2009-06-02 Cyril Robert * SoObjects/Appointments/SOGoAppointmentFolder.m (_enforceTimeLimitOnFilter): diff --git a/Tools/GNUmakefile b/Tools/GNUmakefile new file mode 100644 index 000000000..76e3dd808 --- /dev/null +++ b/Tools/GNUmakefile @@ -0,0 +1,21 @@ +# GNUstep makefile + +include ../config.make +include $(GNUSTEP_MAKEFILES)/common.make +include ../Version + +SOGO_CHECKDOUBLES = sogo-contacts-checkdoubles +$(SOGO_CHECKDOUBLES)_INSTALL_DIR = $(SOGO_ADMIN_TOOLS) +$(SOGO_CHECKDOUBLES)_OBJC_FILES += \ + sogo-contacts-checkdoubles.m + +SOGO_REMOVEDOUBLES = sogo-contacts-removedoubles +$(SOGO_REMOVEDOUBLES)_INSTALL_DIR = $(SOGO_ADMIN_TOOLS) +$(SOGO_REMOVEDOUBLES)_OBJC_FILES += \ + sogo-contacts-removedoubles.m + +TOOL_NAME = $(SOGO_CHECKDOUBLES) $(SOGO_REMOVEDOUBLES) + +-include GNUmakefile.preamble +include $(GNUSTEP_MAKEFILES)/tool.make +-include GNUmakefile.postamble diff --git a/Tools/GNUmakefile.preamble b/Tools/GNUmakefile.preamble new file mode 100644 index 000000000..85e2e5d24 --- /dev/null +++ b/Tools/GNUmakefile.preamble @@ -0,0 +1,20 @@ +# compile settings + +ADDITIONAL_CPPFLAGS += \ + -DSOGO_MAJOR_VERSION=$(MAJOR_VERSION) \ + -DSOGO_MINOR_VERSION=$(MINOR_VERSION) \ + -DSOGO_SUBMINOR_VERSION=$(SUBMINOR_VERSION) \ + -DSOGO_LIBDIR="\"$(SOGO_LIBDIR)\"" + +ADDITIONAL_INCLUDE_DIRS += \ + -I../SOPE/ -D_GNU_SOURCE + +ADDITIONAL_LIB_DIRS += \ + -L../SOPE/GDLContentStore/$(GNUSTEP_OBJ_DIR)/ -lGDLContentStore + +SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib + +$(SOGOD)_TOOL_LIBS += \ + -lGDLContentStore \ + -lGDLAccess \ + -lNGExtensions diff --git a/Tools/sogo-contacts-checkdoubles.m b/Tools/sogo-contacts-checkdoubles.m new file mode 100644 index 000000000..499388e5f --- /dev/null +++ b/Tools/sogo-contacts-checkdoubles.m @@ -0,0 +1,187 @@ +/* sogo-ab-checkdoubles.m - this file is part of SOGo + * + * Copyright (C) 2009 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* TODO: + - NSUserDefaults bootstrapping for using different backends + - make sure we don't end up using 3000 different channels because of the + amount of tables we need to wander */ + +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import + +typedef void (*NSUserDefaultsInitFunction) (); + +static unsigned int ContactsCountWarningLimit = 1000; + +static void +NSLogInhibitor (NSString *message) +{ +} + +@interface SOGoDoublesChecker : NSObject + +- (BOOL) run; + +@end + +@implementation SOGoDoublesChecker + ++ (void) initialize +{ + NSUserDefaults *ud; + NSNumber *warningLimit; + + _NSLog_printf_handler = NSLogInhibitor; + + ud = [NSUserDefaults standardUserDefaults]; + [ud addSuiteNamed: @"sogod"]; + warningLimit = [ud objectForKey: @"SOGoContactsCountWarningLimit"]; + if (warningLimit) + ContactsCountWarningLimit = [warningLimit unsignedIntValue]; + + fprintf (stderr, "The warning limit for folder records is set at %u\n", + ContactsCountWarningLimit); +} + +- (void) processIndexResults: (EOAdaptorChannel *) channel + withFoM: (GCSFolderManager *) fom +{ + NSArray *attrs; + NSDictionary *folderRow; + GCSFolder *currentFolder; + NSString *folderPath; + unsigned int recordsCount; + + attrs = [channel describeResults: NO]; + while ((folderRow = [channel fetchAttributes: attrs withZone: NULL])) + { + folderPath = [folderRow objectForKey: @"c_path"]; + currentFolder = [fom folderAtPath: folderPath]; + if (currentFolder) + { + recordsCount = [currentFolder recordsCountByExcludingDeleted: YES]; + if (recordsCount > ContactsCountWarningLimit) + { + fprintf (stderr, "'%s' (id: '%s'), of '%s': %u entries\n", + [[folderRow objectForKey: @"c_foldername"] + cStringUsingEncoding: NSUTF8StringEncoding], + [[currentFolder folderName] + cStringUsingEncoding: NSUTF8StringEncoding], + [[folderRow objectForKey: @"c_path2"] + cStringUsingEncoding: NSUTF8StringEncoding], + recordsCount); + } + } + else + fprintf (stderr, "folder at path '%s' could not be opened\n", + [folderPath cStringUsingEncoding: NSUTF8StringEncoding]); + } +} + +- (BOOL) processWithFoM: (GCSFolderManager *) fom +{ + BOOL rc; + NSString *sqlString; + GCSChannelManager *cm; + EOAdaptorChannel *channel; + NSException *ex; + + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: [fom folderInfoLocation]]; + if (channel) + { + sqlString = [NSString stringWithFormat: @"SELECT c_path, c_path2, c_foldername" + @" FROM %@" + @" WHERE c_folder_type = 'Contact'", + [fom folderInfoTableName]]; + ex = [channel evaluateExpressionX: sqlString]; + if (ex) + { + fprintf (stderr, "an exception occured during the fetching of folder names"); + [ex raise]; + rc = NO; + } + else + { + rc = YES; + [self processIndexResults: channel withFoM: fom]; + } + + [cm releaseChannel: channel]; + } + else + { + fprintf (stderr, "could not open channel"); + rc = NO; + } + + return rc; +} + +- (BOOL) run +{ + GCSFolderManager *fom; + BOOL rc; + + fom = [GCSFolderManager defaultFolderManager]; + if (fom) + rc = [self processWithFoM: fom]; + else + rc = NO; + + return rc; +} + +@end + +int +main (int argc, char **argv, char **env) +{ + NSAutoreleasePool *pool; + SOGoDoublesChecker *checker; + int rc; + + rc = 0; + + pool = [NSAutoreleasePool new]; + + checker = [SOGoDoublesChecker new]; + if ([checker run]) + rc = 0; + else + rc = -1; + [checker release]; + + [pool release]; + + return rc; +} diff --git a/Tools/sogo-contacts-removedoubles.m b/Tools/sogo-contacts-removedoubles.m new file mode 100644 index 000000000..934acdd4e --- /dev/null +++ b/Tools/sogo-contacts-removedoubles.m @@ -0,0 +1,476 @@ +/* sogo-ab-removedoubles.m - this file is part of SOGo + * + * Copyright (C) 2009 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* TODO: NSUserDefaults bootstrapping for using different backends */ + +#include + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import + +#import +#import +#import + +typedef void (*NSUserDefaultsInitFunction) (); + +static unsigned int ContactsCountWarningLimit = 1000; + +@interface SOGoDoublesRemover : NSObject +@end + +@implementation SOGoDoublesRemover + ++ (void) initialize +{ + NSUserDefaults *ud; + NSNumber *warningLimit; + + ud = [NSUserDefaults standardUserDefaults]; + [ud addSuiteNamed: @"sogod"]; + warningLimit = [ud objectForKey: @"SOGoContactsCountWarningLimit"]; + if (warningLimit) + ContactsCountWarningLimit = [warningLimit unsignedIntValue]; + + NSLog (@"The warning limit for folder records is set at %u", + ContactsCountWarningLimit); +} + +- (void) feedDoubleEmails: (NSMutableDictionary *) doubleEmails + withRecord: (NSDictionary *) record +{ + NSString *recordEmail; + NSMutableArray *recordList; + + /* we want to match c_mail case-insensitively */ + recordEmail = [[record objectForKey: @"c_mail"] uppercaseString]; + if ([recordEmail length]) + { + recordList = [doubleEmails objectForKey: recordEmail]; + if (!recordList) + { + recordList = [NSMutableArray arrayWithCapacity: 5]; + [doubleEmails setObject: recordList forKey: recordEmail]; + } + [recordList addObject: record]; + } +} + +- (void) cleanupSingleRecords: (NSMutableDictionary *) doubleEmails +{ + NSEnumerator *keys; + NSString *currentKey; + + keys = [[doubleEmails allKeys] objectEnumerator]; + while ((currentKey = [keys nextObject])) + { + if ([[doubleEmails objectForKey: currentKey] count] < 2) + [doubleEmails removeObjectForKey: currentKey]; + } +} + +- (NSDictionary *) detectDoubleEmailsFromRecords: (NSArray *) records +{ + NSMutableDictionary *doubleEmails; + unsigned int count, max; + + doubleEmails = [NSMutableDictionary dictionaryWithCapacity: [records count]]; + max = [records count]; + for (count = 0; count < max; count++) + [self feedDoubleEmails: doubleEmails + withRecord: [records objectAtIndex: count]]; + [self cleanupSingleRecords: doubleEmails]; + + return doubleEmails; +} + +- (void) removeRecord: (NSString *) recordName + fromTable: (NSString *) tableName + andQuickTable: (NSString *) quickTableName + usingChannel: (EOAdaptorChannel *) channel +{ + NSString *delSql; + + /* We remove the records without regards to c_deleted because we really want + to recover table space. */ + + delSql = [NSString stringWithFormat: @"DELETE FROM %@" + @" WHERE c_name = '%@'", + tableName, recordName]; + [channel evaluateExpressionX: delSql]; + delSql = [NSString stringWithFormat: @"DELETE FROM %@" + @" WHERE c_name = '%@'", + quickTableName, recordName]; + [channel evaluateExpressionX: delSql]; +} + +- (void) removeRecords: (NSArray *) recordNames + fromFolder: (GCSFolder *) folder +{ + EOAdaptorChannel *channel; + EOAdaptorContext *context; + NSString *tableName, *quickTableName, *currentRecordName; + NSEnumerator *recordsEnum; + + channel = [folder acquireStoreChannel]; + context = [channel adaptorContext]; + [context beginTransaction]; + + tableName = [folder storeTableName]; + quickTableName = [folder quickTableName]; + + recordsEnum = [recordNames objectEnumerator]; + while ((currentRecordName = [recordsEnum nextObject])) + [self removeRecord: currentRecordName + fromTable: tableName andQuickTable: quickTableName + usingChannel: channel]; + fprintf (stderr, "Removing %d records...\n", [recordNames count]); + + [context commitTransaction]; + [folder releaseChannel: channel]; +} + +- (NSArray *) namesOfRecords: (NSArray *) records + differentFrom: (unsigned int) keptRecord + count: (unsigned int) max +{ + NSMutableArray *recordsToRemove; + NSDictionary *currentRecord; + unsigned int count; + + recordsToRemove = [NSMutableArray arrayWithCapacity: (max - 1)]; + for (count = 0; count < max; count++) + { + if (count != keptRecord) + { + currentRecord = [records objectAtIndex: count]; + [recordsToRemove + addObject: [currentRecord objectForKey: @"c_name"]]; + } + } + + return recordsToRemove; +} + +- (NSArray *) records: (NSArray *) records + withLowestScores: (unsigned int *) scores + count: (unsigned int) max +{ + unsigned int count, highestScore; + int highestScoreRecord; + + highestScore = 0; + highestScoreRecord = -1; + for (count = 0; count < max; count++) + { + if (scores[count] > highestScore) + { + highestScore = scores[count]; + highestScoreRecord = count; + } + } + + if (highestScoreRecord == -1) + highestScoreRecord = 0; + + return [self namesOfRecords: records + differentFrom: highestScoreRecord + count: max]; +} + +- (unsigned int) mostModifiedRecord: (NSArray *) records + count: (unsigned int) max +{ + unsigned int mostModified, count, highestVersion, version; + NSNumber *currentVersion; + + mostModified = 0; + + highestVersion = 0; + for (count = 0; count < max; count++) + { + currentVersion + = [[records objectAtIndex: count] objectForKey: @"c_version"]; + version = [currentVersion intValue]; + if (version > highestVersion) + { + mostModified = count; + highestVersion = version; + } + } + + return mostModified; +} + +- (unsigned int) amountOfFilledQuickFields: (NSDictionary *) record +{ + static NSArray *quickFields = nil; + id value; + unsigned int amount, count, max; + + amount = 0; + + if (!quickFields) + { + quickFields = [NSArray arrayWithObjects: @"c_givenname", @"c_cn", + @"c_sn", @"c_screenname", @"c_l", @"c_mail", + @"c_o", @"c_ou", @"c_telephoneNumber", nil]; + [quickFields retain]; + } + + max = [quickFields count]; + for (count = 0; count < max; count++) + { + value = [record objectForKey: [quickFields objectAtIndex: count]]; + if ([value isKindOfClass: [NSString class]]) + { + if ([value length]) + amount++; + } + else if ([value isKindOfClass: [NSNumber class]]) + amount++; + } + + return amount; +} + +- (unsigned int) recordWithTheMostQuickFields: (NSArray *) records + count: (unsigned int) max +{ + unsigned int mostQuickFields, count, highestQFields, currentQFields; + + mostQuickFields = 0; + + highestQFields = 0; + for (count = 0; count < max; count++) + { + currentQFields + = [self amountOfFilledQuickFields: [records objectAtIndex: count]]; + if (currentQFields > highestQFields) + { + mostQuickFields = count; + highestQFields = currentQFields; + } + } + + return mostQuickFields; +} + +- (unsigned int) linesInContent: (NSString *) content +{ + unsigned int nbrLines; + NSArray *lines; + + lines = [content componentsSeparatedByString: @"\n"]; + nbrLines = [lines count]; + + /* sometimes the end line will finish with a CRLF, we fix this */ + if (![[lines objectAtIndex: nbrLines - 1] length]) + nbrLines--; + + return nbrLines; +} + +- (unsigned int) mostCompleteRecord: (NSArray *) records + count: (unsigned int) max +{ + unsigned int mostComplete, count, highestLines, lines; + NSString *content; + + mostComplete = 0; + + highestLines = 0; + for (count = 0; count < max; count++) + { + content = [[records objectAtIndex: count] objectForKey: @"c_content"]; + lines = [self linesInContent: content]; + if (lines > highestLines) + { + mostComplete = count; + highestLines = lines; + } + } + + return mostComplete; +} + +- (void) assignScores: (unsigned int *) scores + toRecords: (NSArray *) records + count: (unsigned int) max +{ + unsigned int recordIndex; + + recordIndex = [self mostModifiedRecord: records count: max]; + (*(scores + recordIndex))++; + recordIndex = [self mostCompleteRecord: records count: max]; + (*(scores + recordIndex)) += 2; + recordIndex = [self recordWithTheMostQuickFields: records count: max]; + (*(scores + recordIndex)) += 3; +} + +- (NSArray *) detectRecordsToRemove: (NSDictionary *) records +{ + NSMutableArray *recordsToRemove; + NSEnumerator *recordsEnum; + NSArray *currentRecords; + unsigned int *scores, max; + + recordsToRemove = [NSMutableArray arrayWithCapacity: [records count] * 4]; + recordsEnum = [[records allValues] objectEnumerator]; + while ((currentRecords = [recordsEnum nextObject])) + { + max = [currentRecords count]; + scores = NSZoneCalloc (NULL, max, sizeof (unsigned int)); + [self assignScores: scores toRecords: currentRecords count: max]; + [recordsToRemove addObjectsFromArray: [self records: currentRecords + withLowestScores: scores + count: max]]; + NSZoneFree (NULL, scores); + } + + return recordsToRemove; +} + +- (BOOL) removeDoublesFromFolder: (GCSFolder *) folder +{ + NSArray *fields, *records, *recordsToRemove; + BOOL rc; + + fields = [NSArray arrayWithObjects: @"c_name", @"c_givenname", @"c_cn", + @"c_sn", @"c_screenname", @"c_l", @"c_mail", @"c_o", + @"c_ou", @"c_telephoneNumber", @"c_content", @"c_version", + @"c_creationdate", @"c_lastmodified", nil]; + records = [folder fetchFields: fields fetchSpecification: nil]; + if (records) + { + rc = YES; + recordsToRemove + = [self detectRecordsToRemove: + [self detectDoubleEmailsFromRecords: records]]; + [self removeRecords: recordsToRemove fromFolder: folder]; + fprintf (stderr, "Removed %d records from %d.\n", + [recordsToRemove count], [records count]); + } + else + { + fprintf (stderr, "Unable to fetch required fields from folder.\n"); + rc = NO; + } + + return NO; +} + +- (BOOL) processFolder: (NSString *) folderId + ofUser: (NSString *) username + withFoM: (GCSFolderManager *) fom +{ + NSString *folderPath; + GCSFolder *folder; + BOOL rc; + + folderPath = [NSString stringWithFormat: @"/Users/%@/Contacts/%@", + username, folderId]; + folder = [fom folderAtPath: folderPath]; + if (folder) + { + rc = [self removeDoublesFromFolder: folder]; + } + else + { + fprintf (stderr, "Folder '%s' not found.\n", + [folderId cStringUsingEncoding: NSUTF8StringEncoding]); + rc = NO; + } + + return rc; +} + +- (BOOL) runWithFolder: (NSString *) folder + andUser: (NSString *) username +{ + GCSFolderManager *fom; + BOOL rc; + + fom = [GCSFolderManager defaultFolderManager]; + if (fom) + rc = [self processFolder: folder ofUser: username + withFoM: fom]; + else + rc = NO; + + return rc; +} + +@end + +static void +Usage (const char *name) +{ + const char *slash, *start; + + slash = strrchr (name, '/'); + if (slash) + start = slash + 1; + else + start = name; + fprintf (stderr, "Usage: %s USER FOLDER\n\n" + " USER the owner of the contact folder\n" + " FOLDER the id of the folder to clean up\n", + start); +} + +int +main (int argc, char **argv, char **env) +{ + NSAutoreleasePool *pool; + SOGoDoublesRemover *remover; + int rc; + + rc = -1; + + pool = [NSAutoreleasePool new]; + + if (argc > 2) + { + remover = [SOGoDoublesRemover new]; + if ([remover runWithFolder: [NSString stringWithFormat: @"%s", argv[2]] + andUser: [NSString stringWithFormat: @"%s", argv[1]]]) + rc = 0; + [remover release]; + } + else + Usage (argv[0]); + + [pool release]; + + return rc; +} From 97ce7fd2058b1df5294269cabfc1be8028bfb5d7 Mon Sep 17 00:00:00 2001 From: C Robert Date: Tue, 2 Jun 2009 17:10:33 +0000 Subject: [PATCH 7/9] Removed NSLog Monotone-Parent: fd50c862e356e0c0c102bf3b5901ec2e9de8241e Monotone-Revision: be1804befa03c2b271f09b1fa8f95c0d9877d056 Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-06-02T17:10:33 Monotone-Branch: ca.inverse.sogo --- SoObjects/Appointments/SOGoAppointmentFolder.m | 1 - 1 file changed, 1 deletion(-) diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 109d1027a..f5e84f7d5 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -1514,7 +1514,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir { filterString = [NSString stringWithFormat: @"(c_iscycle = '%d')", [cycle intValue]]; - NSLog (filterString); [filters addObject: filterString]; } From 363bfac5a5b4809699af673215f15e6603b7f18e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 2 Jun 2009 17:59:06 +0000 Subject: [PATCH 8/9] Monotone-Parent: 5f136163cb35bf4d930f90a158464f4eb5e1d55e Monotone-Revision: 619ec08b1e44eb1626e82e4a1d1a1ba80baa4346 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-02T17:59:06 Monotone-Branch: ca.inverse.sogo --- .../Appointments/SOGoAppointmentFolder.m | 30 ++++++++++--------- SoObjects/SOGo/SOGoObject.m | 2 +- SoObjects/SOGo/SOGoUser.m | 8 ++--- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index f5e84f7d5..428805af2 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -895,6 +895,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir } } +/* TODO: this method should make use of bareFetchFields instead and only keep + its "intelligence" part for handling protected infos and recurrent + events... */ - (NSArray *) fetchFields: (NSArray *) _fields from: (NSCalendarDate *) _startDate to: (NSCalendarDate *) _endDate @@ -1016,8 +1019,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir currentLogin = [[context activeUser] login]; if (![currentLogin isEqualToString: owner] && !_includeProtectedInformation) [self _fixupProtectedInformation: [ma objectEnumerator] - inFields: _fields - forUser: currentLogin]; + inFields: _fields + forUser: currentLogin]; if (rememberRecords) [self _rememberRecords: ma]; @@ -1277,7 +1280,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir end = [now addTimeInterval: (limit / 2) * 86400]; [filter setObject: end forKey: @"end"]; } - } else if ([now compare: end] == NSOrderedDescending) { @@ -1360,20 +1362,18 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir elements = [filterElement getElementsByTagName: @"time-range"]; if ([elements length]) [self _appendTimeRange: [elements objectAtIndex: 0] - toFilter: filterData]; + toFilter: filterData]; elements = [filterElement getElementsByTagName: @"prop-filter"]; if ([elements length]) [self _appendPropertyFilter: [elements objectAtIndex: 0] - toFilter: filterData]; + toFilter: filterData]; - if ( ![filterData objectForKey: @"start"] ) + if (![filterData objectForKey: @"start"]) { maxStart = [self _getMaxStartDate]; if (maxStart) - { - [self _addDateRangeLimitToFilter: filterData]; - } + [self _addDateRangeLimitToFilter: filterData]; } [filterData setObject: [NSNumber numberWithBool: NO] forKey: @"iscycle"]; } @@ -1427,7 +1427,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir rc = [NSMutableDictionary dictionaryWithDictionary: filter]; [rc removeObjectForKey: @"start"]; [rc removeObjectForKey: @"end"]; - [rc setObject: [NSNumber numberWithBool: YES] forKey: @"iscycle"]; + [rc setObject: sharedYes forKey: @"iscycle"]; return rc; } @@ -1502,8 +1502,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir keyField = [NSString stringWithFormat: @"c_%@", currentKey]; if ([fields containsObject: keyField]) { - filterString = [self _additionalFilterKey: keyField - value: [filter objectForKey: currentKey]]; + filterString + = [self _additionalFilterKey: keyField + value: [filter objectForKey: currentKey]]; [filters addObject: filterString]; } } @@ -1513,7 +1514,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir if (cycle) { filterString = [NSString stringWithFormat: @"(c_iscycle = '%d')", - [cycle intValue]]; + [cycle intValue]]; [filters addObject: filterString]; } @@ -1666,7 +1667,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir properties = [[self _parseRequestedProperties: documentElement] asPointersOfObjects]; [self _appendComponentProperties: properties - matchingFilters: [self _parseCalendarFilters: documentElement] + matchingFilters: [self _parseCalendarFilters: + documentElement] toResponse: r]; [r appendContentString:@""]; free (properties); diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index 44b613c87..f38c0b7f6 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -1667,7 +1667,7 @@ SEL SOGoSelectorForPropertySetter (NSString *property) { currentValue = [setProps objectForKey: currentProp]; exception = [self performSelector: methodSel - withObject: currentValue]; + withObject: currentValue]; } else exception diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index 3a12e643f..3a5587ed1 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -915,15 +915,15 @@ _timeValue (NSString *key) - (SOGoUserFolder *) homeFolderInContext: (id) context { return [[WOApplication application] lookupName: [self login] - inContext: context - acquire: NO]; + inContext: context + acquire: NO]; } - (SOGoAppointmentFolders *) calendarsFolderInContext: (WOContext *) context { return [[self homeFolderInContext: context] lookupName: @"Calendar" - inContext: context - acquire: NO]; + inContext: context + acquire: NO]; } - (SOGoAppointmentFolder *) From 7c3da75fa5178a2e40d428623d57884bce431eba Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 2 Jun 2009 18:00:19 +0000 Subject: [PATCH 9/9] Monotone-Parent: 619ec08b1e44eb1626e82e4a1d1a1ba80baa4346 Monotone-Revision: 3556596e54bd1f81160e5c10120b46259ec240f8 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-02T18:00:19 Monotone-Branch: ca.inverse.sogo --- SoObjects/Appointments/SOGoAppointmentFolder.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 428805af2..107d9ecb0 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -1625,6 +1625,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir { additionalFilters = [self _composeAdditionalFilters: currentFilter]; //NSLog(@"query"); + /* TODO: we should invoke bareFetchField:... twice and compute the + recurrent events properly instead of using _makeCyclicFilterFrom: */ apts = [self bareFetchFields: fields from: [currentFilter objectForKey: @"start"] to: [currentFilter objectForKey: @"end"]