From 0a19e30c14472f067ab8fdbfb796a6a2ce0ee777 Mon Sep 17 00:00:00 2001 From: wolfgang Date: Fri, 16 May 2008 18:05:48 +0000 Subject: [PATCH] git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1408 d1b88da0-ebda-0310-925b-ed51d893ca5b --- ChangeLog | 11 + .../Appointments/SOGoAppointmentFolder.h | 15 +- .../Appointments/SOGoAppointmentFolder.m | 272 ++++++++++++------ SoObjects/SOGo/LDAPSource.m | 11 +- UI/Contacts/UIxContactFoldersView.m | 5 - UI/Contacts/product.plist | 7 +- UI/WebServerResources/MailerUI.js | 18 +- 7 files changed, 216 insertions(+), 123 deletions(-) diff --git a/ChangeLog b/ChangeLog index c9ae036a..9f2635bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-05-16 Wolfgang Sourdeau + + * SoObjects/Appointments/SOGoAppointmentFolder.m + ([SOGoAppointmentFolder -davCalendarQuery:queryContext]): added + partial support for the "text-match" caldav directive. + +2008-05-15 Wolfgang Sourdeau + + * UI/Contacts/UIxContactFoldersView.m ([-newAction]): removed + useless method. + 2008-05-05 Wolfgang Sourdeau * SoObjects/SOGo/SOGoObject.m ([SOGoObject diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.h b/SoObjects/Appointments/SOGoAppointmentFolder.h index 7e340bba..c22f4942 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.h +++ b/SoObjects/Appointments/SOGoAppointmentFolder.h @@ -73,22 +73,21 @@ /* fetching */ - (NSArray *) fetchFields: (NSArray *) _fields - fromFolder: (GCSFolder *) _folder from: (NSCalendarDate *) _startDate to: (NSCalendarDate *) _endDate title: (NSString *) title - component: (id) _component; - -- (NSArray * ) fetchFields: (NSArray *) _fields - from: (NSCalendarDate *) _startDate - to: (NSCalendarDate *) _endDate - title: (NSString *) title - component: (id) _component; + component: (id) _component + additionalFilters: (NSString *) filters; - (NSArray *) fetchCoreInfosFrom: (NSCalendarDate *) _startDate to: (NSCalendarDate *) _endDate title: (NSString *) title component: (id) _component; +- (NSArray *) fetchCoreInfosFrom: (NSCalendarDate *) _startDate + to: (NSCalendarDate *) _endDate + title: (NSString *) title + component: (id) _component + additionalFilters: (NSString *) filters; - (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) _startDate to: (NSCalendarDate *) _endDate; diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 71c26f1c..961726e8 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -35,6 +35,7 @@ #import #import #import +#import #import #import #import @@ -504,6 +505,7 @@ static NSNumber *sharedYes = nil; return propstats; } +#warning We need to use the new DAV utilities here... - (void) appendObject: (NSDictionary *) object properties: (NSArray *) properties withBaseURL: (NSString *) baseURL @@ -546,11 +548,34 @@ static NSNumber *sharedYes = nil; [filter setObject: parsedDate forKey: @"end"]; } +#warning This method lacks support for timeranges +- (void) _appendPropertyFilter: (id ) propFilter + toFilter: (NSMutableDictionary *) filter +{ + NSString *propName, *textMatch; + id matches; + + propName = [[propFilter attribute: @"name"] lowercaseString]; + matches = [propFilter getElementsByTagName: @"text-match"]; + if ([matches length]) + textMatch = [[matches objectAtIndex: 0] textValue]; + else + { + matches = [propFilter getElementsByTagName: @"is-not-defined"]; + if ([matches length]) + textMatch = @"NULL"; + else + textMatch = @""; + } + + [filter setObject: textMatch forKey: propName]; +} + - (NSDictionary *) _parseCalendarFilter: (id ) filterElement { NSMutableDictionary *filterData; id parentNode; - id ranges; + id elements; NSString *componentName; parentNode = (id ) [filterElement parentNode]; @@ -558,12 +583,16 @@ static NSNumber *sharedYes = nil; && [[parentNode attribute: @"name"] isEqualToString: @"VCALENDAR"]) { componentName = [[filterElement attribute: @"name"] lowercaseString]; - filterData = [NSMutableDictionary new]; - [filterData autorelease]; + filterData = [NSMutableDictionary dictionary]; [filterData setObject: componentName forKey: @"name"]; - ranges = [filterElement getElementsByTagName: @"time-range"]; - if ([ranges length]) - [self _appendTimeRange: [ranges objectAtIndex: 0] + elements = [filterElement getElementsByTagName: @"time-range"]; + if ([elements length]) + [self _appendTimeRange: [elements objectAtIndex: 0] + toFilter: filterData]; + + elements = [filterElement getElementsByTagName: @"prop-filter"]; + if ([elements length]) + [self _appendPropertyFilter: [elements objectAtIndex: 0] toFilter: filterData]; } else @@ -623,36 +652,88 @@ static NSNumber *sharedYes = nil; return filters; } +- (NSString *) _additionalFilterKey: (NSString *) key + value: (NSString *) value +{ + NSString *filterString; + + if ([value length]) + { + if ([value isEqualToString: @"NULL"]) + filterString = [NSString stringWithFormat: @"(%@ = '')", key]; + else + filterString + = [NSString stringWithFormat: @"(%@ like '%%%@%%')", key, value]; + } + else + filterString = [NSString stringWithFormat: @"(%@ != '')", key]; + + return filterString; +} + +- (NSString *) _composeAdditionalFilters: (NSDictionary *) filter +{ + NSString *additionalFilter; + NSEnumerator *keys; + NSString *currentKey, *keyField, *filterString; + static NSArray *fields = nil; + NSMutableArray *filters; + +#warning the list of fields should be taken from the .ocs description file + if (!fields) + { + fields = [NSArray arrayWithObject: @"c_uid"]; + [fields retain]; + } + + filters = [NSMutableArray new]; + keys = [[filter allKeys] objectEnumerator]; + while ((currentKey = [keys nextObject])) + { + keyField = [NSString stringWithFormat: @"c_%@", currentKey]; + if ([fields containsObject: keyField]) + { + filterString = [self _additionalFilterKey: keyField + value: [filter objectForKey: currentKey]]; + [filters addObject: filterString]; + } + } + + if ([filters count]) + additionalFilter = [filters componentsJoinedByString: @" and "]; + else + additionalFilter = nil; + [filters release]; + + return additionalFilter; +} + - (void) _appendComponentProperties: (NSArray *) properties matchingFilters: (NSArray *) filters toResponse: (WOResponse *) response { NSArray *apts; - unsigned int count, max; NSDictionary *currentFilter, *appointment; - NSEnumerator *appointments; - NSString *baseURL; + NSEnumerator *appointments, *filterList; + NSString *baseURL, *additionalFilters; baseURL = [self baseURLInContext: context]; - max = [filters count]; - for (count = 0; count < max; count++) + filterList = [filters objectEnumerator]; + while ((currentFilter = [filterList nextObject])) { - currentFilter = [filters objectAtIndex: count]; + additionalFilters = [self _composeAdditionalFilters: currentFilter]; apts = [self fetchCoreInfosFrom: [currentFilter objectForKey: @"start"] to: [currentFilter objectForKey: @"end"] title: [currentFilter objectForKey: @"title"] - component: [currentFilter objectForKey: @"name"]]; + component: [currentFilter objectForKey: @"name"] + additionalFilters: additionalFilters]; appointments = [apts objectEnumerator]; - appointment = [appointments nextObject]; - while (appointment) - { - [self appendObject: appointment - properties: properties - withBaseURL: baseURL - toComplexResponse: response]; - appointment = [appointments nextObject]; - } + while ((appointment = [appointments nextObject])) + [self appendObject: appointment + properties: properties + withBaseURL: baseURL + toComplexResponse: response]; } } @@ -774,7 +855,8 @@ static NSNumber *sharedYes = nil; document = [[context request] contentAsDOMDocument]; documentElement = [document documentElement]; - [self _appendComponentProperties: [self _parseRequestedProperties: documentElement] + [self _appendComponentProperties: + [self _parseRequestedProperties: documentElement] matchingFilters: [self _parseCalendarFilters: documentElement] toResponse: r]; [r appendContentString:@"\r\n"]; @@ -989,8 +1071,13 @@ static NSNumber *sharedYes = nil; if (![_uid isNotNull]) return nil; - if ((rname = [uidToFilename objectForKey:_uid]) != nil) - return [rname isNotNull] ? rname : nil; + rname = [uidToFilename objectForKey:_uid]; + if (rname) + { + if (![rname isNotNull]) + rname = nil; + return rname; + } if ((folder = [self ocsFolder]) == nil) { [self errorWithFormat:@"(%s): missing folder for fetch!", @@ -1384,20 +1471,22 @@ static NSNumber *sharedYes = nil; } - (NSArray *) fetchFields: (NSArray *) _fields - fromFolder: (GCSFolder *) _folder from: (NSCalendarDate *) _startDate to: (NSCalendarDate *) _endDate title: (NSString *) title component: (id) _component + additionalFilters: (NSString *) filters { EOQualifier *qualifier; + GCSFolder *folder; NSMutableArray *fields, *ma = nil; NSArray *records; NSString *sql, *dateSqlString, *titleSqlString, *componentSqlString, - *privacySqlString, *currentLogin; + *privacySqlString, *currentLogin, *filterSqlString; NGCalendarDateRange *r; - if (!_folder) + folder = [self ocsFolder]; + if (!folder) { [self errorWithFormat:@"(%s): missing folder for fetch!", __PRETTY_FUNCTION__]; @@ -1424,6 +1513,10 @@ static NSNumber *sharedYes = nil; componentSqlString = [self _sqlStringForComponent: _component]; privacySqlString = [self _privacySqlString]; + if (filters) + filterSqlString = [NSString stringWithFormat: @"AND (%@)", filters]; + else + filterSqlString = @""; /* prepare mandatory fields */ @@ -1435,14 +1528,14 @@ static NSNumber *sharedYes = nil; if (logger) [self debugWithFormat:@"should fetch (%@=>%@) ...", _startDate, _endDate]; - sql = [NSString stringWithFormat: @"(c_iscycle = 0)%@%@%@%@", - dateSqlString, titleSqlString, - componentSqlString, privacySqlString]; + sql = [NSString stringWithFormat: @"(c_iscycle = 0)%@%@%@%@%@", + dateSqlString, titleSqlString, componentSqlString, + privacySqlString, filterSqlString]; /* fetch non-recurrent apts first */ qualifier = [EOQualifier qualifierWithQualifierFormat: sql]; - records = [_folder fetchFields: fields matchingQualifier: qualifier]; + records = [folder fetchFields: fields matchingQualifier: qualifier]; if (records) { if (r) @@ -1456,12 +1549,12 @@ static NSNumber *sharedYes = nil; /* fetch recurrent apts now. we do NOT consider the date range when doing that as the c_startdate/c_enddate of a recurring event is always set to the first recurrence - others are generated on the fly */ - sql = [NSString stringWithFormat: @"(c_iscycle = 1)%@%@%@", titleSqlString, - componentSqlString, privacySqlString]; + sql = [NSString stringWithFormat: @"(c_iscycle = 1)%@%@%@%@", titleSqlString, + componentSqlString, privacySqlString, filterSqlString]; qualifier = [EOQualifier qualifierWithQualifierFormat: sql]; - records = [_folder fetchFields: fields matchingQualifier: qualifier]; + records = [folder fetchFields: fields matchingQualifier: qualifier]; if (records) { @@ -1494,27 +1587,6 @@ static NSNumber *sharedYes = nil; return ma; } -/* override this in subclasses */ -- (NSArray *) fetchFields: (NSArray *) _fields - from: (NSCalendarDate *) _startDate - to: (NSCalendarDate *) _endDate - title: (NSString *) title - component: (id) _component -{ - GCSFolder *folder; - - if ((folder = [self ocsFolder]) == nil) { - [self errorWithFormat:@"(%s): missing folder for fetch!", - __PRETTY_FUNCTION__]; - return nil; - } - - return [self fetchFields: _fields fromFolder: folder - from: _startDate to: _endDate - title: title - component: _component]; -} - - (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) _startDate to: (NSCalendarDate *) _endDate { @@ -1524,15 +1596,27 @@ static NSNumber *sharedYes = nil; infos = [[NSArray alloc] initWithObjects: @"c_partmails", @"c_partstates", @"c_isopaque", @"c_status", nil]; - return [self fetchFields: infos from: _startDate to: _endDate + return [self fetchFields: infos + from: _startDate to: _endDate title: nil - component: @"vevent"]; + component: @"vevent" + additionalFilters: nil]; } - (NSArray *) fetchCoreInfosFrom: (NSCalendarDate *) _startDate to: (NSCalendarDate *) _endDate title: (NSString *) title component: (id) _component +{ + return [self fetchCoreInfosFrom: _startDate to: _endDate title: title + component: _component additionalFilters: nil]; +} + +- (NSArray *) fetchCoreInfosFrom: (NSCalendarDate *) _startDate + to: (NSCalendarDate *) _endDate + title: (NSString *) title + component: (id) _component + additionalFilters: (NSString *) filters { static NSArray *infos = nil; // TODO: move to a plist file @@ -1543,11 +1627,12 @@ static NSNumber *sharedYes = nil; @"c_status", @"c_classification", @"c_isallday", @"c_isopaque", @"c_participants", @"c_partmails", - @"c_partstates", @"c_sequence", @"c_priority", @"c_cycleinfo", - nil]; + @"c_partstates", @"c_sequence", @"c_priority", + @"c_cycleinfo", nil]; return [self fetchFields: infos from: _startDate to: _endDate title: title - component: _component]; + component: _component + additionalFilters: filters]; } /* URL generation */ @@ -1702,21 +1787,27 @@ static NSNumber *sharedYes = nil; if ([_uids count] == 0) return nil; objs = [NSMutableArray arrayWithCapacity:16]; e = [_uids objectEnumerator]; - while ((uid = [e nextObject])) { - id obj; + while ((uid = [e nextObject])) + { + id obj; - obj = [self lookupHomeFolderForUID:uid inContext:nil]; - if ([obj isNotNull]) { - obj = [obj lookupName:@"freebusy.ifb" inContext:nil acquire:NO]; - if ([obj isKindOfClass:[NSException class]]) - obj = nil; - } - if (![obj isNotNull]) - [self logWithFormat:@"Note: did not find freebusy.ifb for uid: '%@'", uid]; + obj = [self lookupHomeFolderForUID:uid inContext:nil]; + if ([obj isNotNull]) + { + obj = [obj lookupName: @"freebusy.ifb" inContext: nil acquire: NO]; + if ([obj isKindOfClass: [NSException class]]) + obj = nil; + } + if (![obj isNotNull]) + [self logWithFormat: @"Note: did not find freebusy.ifb for uid: '%@'", + uid]; - /* Note: intentionally add 'null' folders to allow a mapping */ - [objs addObject:obj ? obj : [NSNull null]]; - } + /* Note: intentionally add 'null' folders to allow a mapping */ + if (!obj) + obj = [NSNull null]; + [objs addObject: obj]; + } + return objs; } @@ -1734,21 +1825,24 @@ static NSNumber *sharedYes = nil; uids = [NSMutableArray arrayWithCapacity:count + 1]; um = [LDAPUserManager sharedUserManager]; - for (i = 0; i < count; i++) { - iCalPerson *person; - NSString *email; - NSString *uid; + for (i = 0; i < count; i++) + { + iCalPerson *person; + NSString *email; + NSString *uid; - person = [_persons objectAtIndex:i]; - email = [person rfc822Email]; - if ([email isNotNull]) { - uid = [um getUIDForEmail:email]; + person = [_persons objectAtIndex:i]; + email = [person rfc822Email]; + if ([email isNotNull]) + uid = [um getUIDForEmail:email]; + else + uid = nil; + + if (!uid) + uid = (NSString *) [NSNull null]; + [uids addObject: uid]; } - else - uid = nil; - - [uids addObject:(uid != nil ? uid : (id)[NSNull null])]; - } + return uids; } @@ -1925,7 +2019,9 @@ static NSNumber *sharedYes = nil; cNameField = [[NSArray alloc] initWithObjects: @"c_name", nil]; return [[self fetchFields: cNameField from: nil to: nil - title: nil component: nil] objectsForKey: @"c_name"]; + title: nil component: nil + additionalFilters: nil] + objectsForKey: @"c_name"]; } /* folder type */ diff --git a/SoObjects/SOGo/LDAPSource.m b/SoObjects/SOGo/LDAPSource.m index 8a87147d..0163c691 100644 --- a/SoObjects/SOGo/LDAPSource.m +++ b/SoObjects/SOGo/LDAPSource.m @@ -249,14 +249,11 @@ static int sizeLimit; NSString *currentField; qs = [NSMutableString string]; + fields = [[bindFields componentsSeparatedByString: @","] objectEnumerator]; - currentField = [fields nextObject]; - while (currentField) - { - [qs appendFormat: @"OR (%@='%@')", currentField, uid]; - currentField = [fields nextObject]; - } - [qs deleteCharactersInRange: NSMakeRange (0, 3)]; + while ((currentField = [fields nextObject])) + [qs appendFormat: @" OR (%@='%@')", currentField, uid]; + [qs deleteCharactersInRange: NSMakeRange (0, 4)]; return [EOQualifier qualifierWithQualifierFormat: qs]; } diff --git a/UI/Contacts/UIxContactFoldersView.m b/UI/Contacts/UIxContactFoldersView.m index 97d143f3..ed7a4e19 100644 --- a/UI/Contacts/UIxContactFoldersView.m +++ b/UI/Contacts/UIxContactFoldersView.m @@ -91,11 +91,6 @@ return [self _selectActionForApplication: @"view"]; } -- (id) newAction -{ - return [self _selectActionForApplication: @"new"]; -} - - (id) selectForMailerAction { return [self _selectActionForApplication: @"mailer-contacts"]; diff --git a/UI/Contacts/product.plist b/UI/Contacts/product.plist index 1cebeb68..2d50fd20 100644 --- a/UI/Contacts/product.plist +++ b/UI/Contacts/product.plist @@ -1,4 +1,4 @@ -{ /* -*-javascript-*- */ +{ /* -*-java-*- */ requires = ( MAIN, MainUI, CommonUI, Contacts ); publicResources = (); @@ -12,11 +12,6 @@ protectedBy = "View"; pageName = "UIxContactFoldersView"; }; - new = { - protectedBy = "View"; - pageName = "UIxContactFoldersView"; - actionName = "new"; - }; mailer-contacts = { protectedBy = "View"; pageName = "UIxContactFoldersView"; diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index 3416324f..b7cfe1e0 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -450,9 +450,9 @@ function openMailbox(mailbox, reload, idx) { messageContent.update(); lastClickedRow = -1; // from generic.js } - + var currentMessage; - + if (!idx) { currentMessage = Mailer.currentMessages[mailbox]; if (currentMessage) { @@ -1033,13 +1033,13 @@ function newContactFromEmail(event) { var email = extractEmailAddress(mailto); var c_name = extractEmailName(mailto); - if (email.length > 0) - { - var url = UserFolderURL + "Contacts/new?contactEmail=" + email; - if (c_name) - url += "&contactFN=" + c_name; - openContactWindow(url); - } + if (email.length > 0) { + var url = (UserFolderURL + "Contacts/personal/newcontact?contactEmail=" + + encodeURI(email)); + if (c_name) + url += "&contactFN=" + c_name; + openContactWindow(url); + } return false; /* stop following the link */ } -- 2.39.5