From 4e9bc8238828de311840e0ce7361ee511d0165ff Mon Sep 17 00:00:00 2001 From: francis Date: Thu, 11 Oct 2007 16:33:27 +0000 Subject: [PATCH] git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1185 d1b88da0-ebda-0310-925b-ed51d893ca5b --- ChangeLog | 73 +++++++- GNUmakefile | 1 + Main/SOGo.m | 3 - NEWS | 6 +- .../NGCards/iCalMonthlyRecurrenceCalculator.m | 7 +- SOPE/NGCards/iCalRecurrenceCalculator.m | 4 +- .../Appointments/SOGoAppointmentFolder.m | 34 ++-- .../Appointments/SOGoAptMailNotification.m | 2 +- SoObjects/Contacts/SOGoContactGCSFolder.m | 171 +++++++++++++++++- SoObjects/Mailer/SOGoDraftObject.m | 11 +- SoObjects/SOGo/LDAPSource.h | 2 + SoObjects/SOGo/LDAPSource.m | 21 ++- SoObjects/SOGo/LDAPUserManager.h | 1 + SoObjects/SOGo/LDAPUserManager.m | 40 ++-- SoObjects/SOGo/NSString+Utilities.m | 13 +- SoObjects/SOGo/SOGoUser.m | 29 ++- UI/Common/English.lproj/Localizable.strings | 4 +- UI/Common/French.lproj/Localizable.strings | 2 +- UI/Common/UIxFolderActions.m | 30 ++- UI/Common/UIxPageFrame.m | 1 + UI/MailPartViewers/UIxMailPartTextViewer.m | 2 - UI/MailerUI/English.lproj/Localizable.strings | 1 + UI/MailerUI/French.lproj/Localizable.strings | 1 + UI/MailerUI/German.lproj/Localizable.strings | 1 + UI/MailerUI/UIxMailEditor.m | 2 +- UI/MainUI/English.lproj/Localizable.strings | 2 + UI/MainUI/French.lproj/Localizable.strings | 2 + UI/MainUI/SOGoUserHomePage.m | 2 - UI/SOGoUI/UIxComponent.m | 3 + .../English.lproj/Localizable.strings | 2 +- UI/Scheduler/French.lproj/Localizable.strings | 2 +- UI/Scheduler/UIxAppointmentEditor.h | 1 + UI/Scheduler/UIxAppointmentEditor.m | 78 +++++++- UI/Scheduler/UIxCalListingActions.m | 38 ++-- UI/Scheduler/UIxCalMonthOverview.h | 2 +- UI/Scheduler/UIxComponentEditor.m | 13 +- .../ContactsUI/UIxContactsListView.wox | 17 +- UI/Templates/MailerUI/UIxMailListView.wox | 33 ++-- UI/Templates/MainUI/SOGoRootPage.wox | 4 +- UI/Templates/SchedulerUI/UIxCalMainView.wox | 15 +- .../SchedulerUI/UIxCalendarSelector.wox | 2 +- .../SchedulerUI/UIxComponentEditor.wox | 5 + UI/Templates/UIxPageFrame.wox | 10 +- UI/WebServerResources/ContactsUI.css | 30 +-- UI/WebServerResources/ContactsUI.js | 58 +++--- UI/WebServerResources/HTMLElement.js | 25 +++ UI/WebServerResources/HTMLTableElement.js | 22 --- UI/WebServerResources/MailerUI.css | 33 ++-- UI/WebServerResources/MailerUI.js | 121 ++++++++----- UI/WebServerResources/SOGoRootPage.css | 4 + UI/WebServerResources/SchedulerUI.css | 25 ++- UI/WebServerResources/SchedulerUI.js | 110 ++++++----- UI/WebServerResources/UIxAclEditor.css | 15 +- UI/WebServerResources/UIxAclEditor.js | 2 +- .../UIxCalUserRightsEditor.js | 4 +- .../UIxContactsUserFolders.js | 8 +- .../UIxContactsUserRightsEditor.js | 5 +- UI/WebServerResources/UIxMailEditor.css | 3 +- UI/WebServerResources/UIxMailEditor.js | 23 ++- .../UIxMailUserRightsEditor.js | 2 +- UI/WebServerResources/generic.css | 27 ++- UI/WebServerResources/generic.js | 98 ++++++---- 62 files changed, 910 insertions(+), 398 deletions(-) diff --git a/ChangeLog b/ChangeLog index ac0d9909..1c09f87e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,74 @@ +2007-10-10 Ludovic Marcotte + + * UI/Scheduler/UIxComponentEditor.m + Implemented event/task priority support. + + * SoObjects/Contacts/SOGoContactGCSFolder.m + Added CardDAV support. + + * SoObjects/SOGo/LDAPUserManager.m and SOGoUser.m + Implemented From: based on LDAP results based on + the MailFieldNames attribute (an array) specified + in every LDAP-based authentication sources. + + * UI/MailPartViewers/UIxMailPartTextViewer.m and + UI/WebServerResources/MailerUI.css + We avoid replacing "\r\n" and "\n" with
and + rather use CSS capabilities for proper formatting. + This is _WAY_ faster on very large mails. + +2007-10-10 Francis Lachapelle + + * UI/Scheduler/UIxComponentEditor.m + ([UIxComponentEditor -componentCalendar]): returns the calendar + object of the current event. + +2007-10-05 Ludovic Marcotte + + * UI/WebServerResources/MailerUI.js + We check if at least one message is selected + before performing a Reply/Reply All/Forward + + * SoObjects/Appointments/SOGoAppointmentFolder.m + and others - implemented support for recurring + events (with some known limitations right now, + all soon to be fixed). + +2007-10-04 Francis Lachapelle + + * Main/SOGo.m ([SOGo -isUserName:_keyinContext:_ctx]): removed + the constraint that a username can't start with a digit. + +2007-10-02 Francis Lachapelle + + * Moved SOPE/sope-gdl1/GDLContentStore from the default trunk + repository to Inverse's branch. + +2007-09-28 Francis Lachapelle + + * SoObjects/Mailer/SOGoDraftObject.m + ([SOGoDraftObject -isValidAttachmentName:_name]): removed + constraint on space in file name. + ([SOGoDraftObject -saveAttachment:_attachwithMetadata:metadata]): + now removes from file name all characters preceding a backslash. + This happens with IE7 because the complete attachment file path + is sent. + +2007-09-25 Francis Lachapelle + + * SoObjects/Appointments/SOGoAptMailNotification.m + ([SOGoAptMailNotification -appointmentURL]): set personal as the + default calendar where to add the event. + + * UI/MainUI/SOGoUserHomePage.m ([SOGoUserHomePage +initialize]): + activate the SOGoUIxDefaultModule user defaults. + +2007-09-21 Francis Lachapelle + + * UI/SOGoUI/UIxComponent.m + ([UIxComponent -shortUserNameForDisplay]): returns the string + "wrongusernamepassword" when authentication failed. + 2007-09-17 Wolfgang Sourdeau * UI/MailPartViewers/UIxMailPartICalViewer.m @@ -3598,7 +3669,7 @@ 2006-09-13 Wolfgang Sourdeau * UI/Contacts/UIxContactView.m: added many wrapper methods to - display blocks of data à la Thunderbird Addressbook. If data is + display blocks of data à la Thunderbird Addressbook. If data is available, those wrappers (around the NGVCard methods) will enclose the results in a proper HTML output with the correct label (if present), otherwise it will return an empty string. diff --git a/GNUmakefile b/GNUmakefile index fa15ad0d..2877399d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -5,6 +5,7 @@ include $(GNUSTEP_MAKEFILES)/common.make SUBPROJECTS = \ SOPE/NGCards \ + SOPE/sope-gdl1/GDLContentStore \ OGoContentStore \ SoObjects \ Main \ diff --git a/Main/SOGo.m b/Main/SOGo.m index 3bc17f59..15b568dd 100644 --- a/Main/SOGo.m +++ b/Main/SOGo.m @@ -254,9 +254,6 @@ static BOOL debugObjectAllocation = NO; if ([_key length] < 1) return NO; - if (isdigit([_key characterAtIndex:0])) - return NO; - return YES; } diff --git a/NEWS b/NEWS index 8947cccf..a61bbec9 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ - implemented cookie-based identification in the web interface; - fixed a bug where a false positive happening whenever a wrong user login was given during an indirect bind; +- remove the constraint that a username can't begin with a digit; - deleting a message no longer expunges its parent folder; - implemented support for multiple calendars; - it is now possible to rename folders; @@ -10,8 +11,9 @@ - added tooltips for toolbar buttons (English and French); - added checkmarks in live search options popup menus; - added browser detection with recommanded alternatives; -- initial support for resizable columns in tables; -- improved IE7 and Safari support: attendees selector; +- support for resizable columns in tables; +- improved support for multiple selection in tables and lists; +- improved IE7 and Safari support: attendees selector, email file attachments; - countless bugfixes; 0.9.0-20070824 diff --git a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m index 2516534a..e8a23631 100644 --- a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m +++ b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m @@ -262,10 +262,9 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet, interval = [self->rrule repeatInterval]; until = [self lastInstanceStartDate]; // TODO: maybe replace byMonthDay = [self->rrule byMonthDay]; - - /* check whether the range to be processed is beyond the 'until' date */ - + + /* check whether the range to be processed is beyond the 'until' date */ if (until != nil) { if ([until compare:rStart] == NSOrderedAscending) /* until before start */ return nil; @@ -314,7 +313,7 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet, continue; /* first check whether we are in the interval */ - + if ((monthIdxInRecurrence % interval) != 0) continue; diff --git a/SOPE/NGCards/iCalRecurrenceCalculator.m b/SOPE/NGCards/iCalRecurrenceCalculator.m index a56eaef3..4923639c 100644 --- a/SOPE/NGCards/iCalRecurrenceCalculator.m +++ b/SOPE/NGCards/iCalRecurrenceCalculator.m @@ -100,9 +100,10 @@ static Class yearlyCalcClass = Nil; rule = [_rRules objectAtIndex:i]; if (![rule isKindOfClass:iCalRecurrenceRuleClass]) rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule]; - + calc = [self recurrenceCalculatorForRecurrenceRule:rule withFirstInstanceCalendarDateRange:_fir]; + rs = [calc recurrenceRangesWithinCalendarDateRange:_r]; [ranges addObjectsFromArray:rs]; } @@ -158,6 +159,7 @@ static Class yearlyCalcClass = Nil; unsigned k; exDate = [exDates objectAtIndex:i]; + for (k = 0; k < rCount; k++) { unsigned rIdx; diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index a517d18d..a2306fba 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -221,6 +221,7 @@ static NSNumber *sharedYes = nil; return filterData; } +#warning filters is leaked here - (NSArray *) _parseCalendarFilters: (id ) parentNode { NSEnumerator *children; @@ -258,6 +259,7 @@ static NSNumber *sharedYes = nil; max = [filters count]; for (count = 0; count < max; count++) { +#warning huh? why not objectAtIndex: count? currentFilter = [filters objectAtIndex: 0]; apts = [self fetchCoreInfosFrom: [currentFilter objectForKey: @"start"] to: [currentFilter objectForKey: @"end"] @@ -568,13 +570,16 @@ static NSNumber *sharedYes = nil; md = [[_record mutableCopy] autorelease]; - /* cycle is in _r */ + /* cycle is in _r. We also have to override the c_startdate/c_enddate with the date values of + the reccurence since we use those when displaying events in SOGo Web */ tmp = [_r startDate]; [tmp setTimeZone: timeZone]; [md setObject:tmp forKey:@"startDate"]; + [md setObject: [NSNumber numberWithInt: [tmp timeIntervalSince1970]] forKey: @"c_startdate"]; tmp = [_r endDate]; [tmp setTimeZone: timeZone]; [md setObject:tmp forKey:@"endDate"]; + [md setObject: [NSNumber numberWithInt: [tmp timeIntervalSince1970]] forKey: @"c_enddate"]; return md; } @@ -633,20 +638,24 @@ static NSNumber *sharedYes = nil; rules = [cycleinfo objectForKey:@"rules"]; exRules = [cycleinfo objectForKey:@"exRules"]; exDates = [cycleinfo objectForKey:@"exDates"]; - + ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange:_r firstInstanceCalendarDateRange:fir recurrenceRules:rules exceptionRules:exRules exceptionDates:exDates]; count = [ranges count]; + for (i = 0; i < count; i++) { NGCalendarDateRange *rRange; id fixedRow; rRange = [ranges objectAtIndex:i]; fixedRow = [self fixupCycleRecord:row cycleRange:rRange]; - if (fixedRow != nil) [_ma addObject:fixedRow]; + if (fixedRow != nil) + { + [_ma addObject:fixedRow]; + } } } @@ -845,21 +854,20 @@ static NSNumber *sharedYes = nil; ma = [NSMutableArray arrayWithArray: records]; } - /* fetch recurrent apts now */ - sql = [NSString stringWithFormat: @"(c_iscycle = 1)%@%@%@", - dateSqlString, componentSqlString, privacySqlString]; - qualifier = [EOQualifier qualifierWithQualifierFormat: sql]; + /* 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)%@%@", componentSqlString, privacySqlString]; - [fields addObject: @"c_cycleinfo"]; + qualifier = [EOQualifier qualifierWithQualifierFormat: sql]; records = [_folder fetchFields: fields matchingQualifier: qualifier]; + if (records) { - if (logger) - [self debugWithFormat: @"fetched %i cyclic records: %@", - [records count], records]; - if (r) + if (r) { records = [self fixupCyclicRecords: records fetchRange: r]; + } if (!ma) ma = [NSMutableArray arrayWithCapacity: [records count]]; @@ -926,7 +934,7 @@ static NSNumber *sharedYes = nil; @"c_status", @"c_classification", @"c_isallday", @"c_isopaque", @"c_participants", @"c_partmails", - @"c_partstates", @"c_sequence", @"c_priority", + @"c_partstates", @"c_sequence", @"c_priority", @"c_cycleinfo", nil]; return [self fetchFields: infos from: _startDate to: _endDate diff --git a/SoObjects/Appointments/SOGoAptMailNotification.m b/SoObjects/Appointments/SOGoAptMailNotification.m index 5c6b2c4f..912c3a0e 100644 --- a/SoObjects/Appointments/SOGoAptMailNotification.m +++ b/SoObjects/Appointments/SOGoAptMailNotification.m @@ -90,7 +90,7 @@ static NSTimeZone *EST = nil; NSString *aptUID; aptUID = [[self newApt] uid]; - return [NSString stringWithFormat:@"%@/Calendar/%@/edit?mail-invitation=yes", + return [NSString stringWithFormat:@"%@/Calendar/personal/%@/edit?mail-invitation=yes", [self homePageURL], aptUID]; } diff --git a/SoObjects/Contacts/SOGoContactGCSFolder.m b/SoObjects/Contacts/SOGoContactGCSFolder.m index b8856acd..1a58723d 100644 --- a/SoObjects/Contacts/SOGoContactGCSFolder.m +++ b/SoObjects/Contacts/SOGoContactGCSFolder.m @@ -30,6 +30,9 @@ #import #import #import +#import +#import +#import #import #import "SOGoContactGCSEntry.h" @@ -100,6 +103,7 @@ if (filter && [filter length] > 0) { +#warning why we do not use %%%@%% everywhere? qs = [NSString stringWithFormat: @"(c_sn isCaseInsensitiveLike: '%@%%') OR " @"(c_givenname isCaseInsensitiveLike: '%@%%') OR " @@ -169,6 +173,141 @@ return newRecords; } +- (BOOL) _isValidFilter: (NSString *) theString +{ + if ([theString caseInsensitiveCompare: @"sn"] == NSOrderedSame) + return YES; + + if ([theString caseInsensitiveCompare: @"givenname"] == NSOrderedSame) + return YES; + + if ([theString caseInsensitiveCompare: @"mail"] == NSOrderedSame) + return YES; + + if ([theString caseInsensitiveCompare: @"telephonenumber"] == NSOrderedSame) + return YES; + + return NO; +} + +- (NSDictionary *) _parseContactFilter: (id ) filterElement +{ + NSMutableDictionary *filterData; + id parentNode; + id ranges; + NSString *componentName; + + parentNode = [filterElement parentNode]; + + if ([[parentNode tagName] isEqualToString: @"filter"] && + [self _isValidFilter: [filterElement attribute: @"name"]]) + { + ranges = [filterElement getElementsByTagName: @"text-match"]; + + if ([ranges count] && [[[ranges objectAtIndex: 0] childNodes] count]) + { + filterData = [NSMutableDictionary new]; + [filterData autorelease]; + [filterData setObject: [[[[ranges objectAtIndex: 0] childNodes] lastObject] data] + forKey: [filterElement attribute: @"name"]]; + } + } + else + filterData = nil; + + return filterData; +} + +#warning filters is leaked here +- (NSArray *) _parseContactFilters: (id ) parentNode +{ + NSEnumerator *children; + id node; + NSMutableArray *filters; + NSDictionary *filter; + + filters = [NSMutableArray new]; + + children = [[parentNode getElementsByTagName: @"prop-filter"] + objectEnumerator]; + + node = [children nextObject]; + + while (node) + { + filter = [self _parseContactFilter: node]; + if (filter) + [filters addObject: filter]; + node = [children nextObject]; + } + + return filters; +} + +- (void) _appendComponentsMatchingFilters: (NSArray *) filters + toResponse: (WOResponse *) response +{ + unsigned int count, max; + NSDictionary *currentFilter, *contact; + NSEnumerator *contacts; + NSString *baseURL; + + baseURL = [self baseURLInContext: context]; + + max = [filters count]; + for (count = 0; count < max; count++) + { + currentFilter = [filters objectAtIndex: count]; + contacts = [[self lookupContactsWithFilter: [[currentFilter allValues] lastObject] + sortBy: @"c_givenname" + ordering: NSOrderedDescending] + objectEnumerator]; + + while ((contact = [contacts nextObject])) + { + [self appendObject: contact + withBaseURL: baseURL + toREPORTResponse: response]; + } + } +} + +- (void) appendObject: (NSDictionary *) object + withBaseURL: (NSString *) baseURL + toREPORTResponse: (WOResponse *) r +{ + SOGoContactGCSEntry *component; + Class componentClass; + NSString *name, *etagLine, *contactString; + + name = [object objectForKey: @"c_name"]; + componentClass = [SOGoContactGCSEntry class]; + + component = [componentClass objectWithName: name inContainer: self]; + + [r appendContentString: @" \r\n"]; + [r appendContentString: @" "]; + [r appendContentString: baseURL]; + if (![baseURL hasSuffix: @"/"]) + [r appendContentString: @"/"]; + [r appendContentString: name]; + [r appendContentString: @"\r\n"]; + + [r appendContentString: @" \r\n"]; + [r appendContentString: @" \r\n"]; + etagLine = [NSString stringWithFormat: @" %@\r\n", + [component davEntityTag]]; + [r appendContentString: etagLine]; + [r appendContentString: @" \r\n"]; + [r appendContentString: @" HTTP/1.1 200 OK\r\n"]; + [r appendContentString: @" \r\n"]; + [r appendContentString: @" "]; + contactString = [[component contentAsString] stringByEscapingXMLString]; + [r appendContentString: contactString]; + [r appendContentString: @"\r\n"]; + [r appendContentString: @" \r\n"]; +} + - (NSArray *) lookupContactsWithFilter: (NSString *) filter sortBy: (NSString *) sortKey ordering: (NSComparisonResult) sortOrdering @@ -177,13 +316,11 @@ EOQualifier *qualifier; EOSortOrdering *ordering; -// NSLog (@"fetching records matching '%@', sorted by '%@' in order %d", -// filter, sortKey, sortOrdering); - fields = folderListingFields; qualifier = [self _qualifierForFilter: filter]; dbRecords = [[self ocsFolder] fetchFields: fields matchingQualifier: qualifier]; + if ([dbRecords count] > 0) { records = [self _flattenedRecords: dbRecords]; @@ -201,7 +338,7 @@ // else // [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__]; - //[self debugWithFormat:@"fetched %i records.", [records count]]; + [self debugWithFormat:@"fetched %i records.", [records count]]; return records; } @@ -210,6 +347,32 @@ return [NSArray arrayWithObject: @"urn:ietf:params:xml:ns:carddav"]; } +- (id) davAddressbookQuery: (id) queryContext +{ + WOResponse *r; + NSArray *filters; + id document; + + r = [context response]; + [r setStatus: 207]; + [r setContentEncoding: NSUTF8StringEncoding]; + [r setHeader: @"text/xml; charset=\"utf-8\"" forKey: @"content-type"]; + [r setHeader: @"no-cache" forKey: @"pragma"]; + [r setHeader: @"no-cache" forKey: @"cache-control"]; + [r appendContentString:@"\r\n"]; + [r appendContentString: @"\r\n"]; + + document = [[context request] contentAsDOMDocument]; + filters = [self _parseContactFilters: [document documentElement]]; + + [self _appendComponentsMatchingFilters: filters + toResponse: r]; + [r appendContentString:@"\r\n"]; + + return r; +} + - (NSArray *) davComplianceClassesInContext: (id)_ctx { NSMutableArray *classes; diff --git a/SoObjects/Mailer/SOGoDraftObject.m b/SoObjects/Mailer/SOGoDraftObject.m index 173e62d0..3aa25f15 100644 --- a/SoObjects/Mailer/SOGoDraftObject.m +++ b/SoObjects/Mailer/SOGoDraftObject.m @@ -578,7 +578,7 @@ static BOOL showTextAttachmentsInline = NO; - (BOOL) isValidAttachmentName: (NSString *) _name { - static NSString *sescape[] = { @"/", @"..", @"~", @"\"", @"'", @" ", nil }; + static NSString *sescape[] = { @"/", @"..", @"~", @"\"", @"'", nil }; unsigned i; NSRange r; @@ -611,7 +611,8 @@ static BOOL showTextAttachmentsInline = NO; withMetadata: (NSDictionary *) metadata { NSString *p, *name, *mimeType; - + NSRange r; + if (![_attach isNotNull]) { return [NSException exceptionWithHTTPStatus:400 /* Bad Request */ reason: @"Missing attachment content!"]; @@ -621,7 +622,13 @@ static BOOL showTextAttachmentsInline = NO; return [NSException exceptionWithHTTPStatus:500 /* Server Error */ reason: @"Could not create folder for draft!"]; } + name = [metadata objectForKey: @"filename"]; + r = [name rangeOfString: @"\\" + options: NSBackwardsSearch]; + if (r.length > 0) + name = [name substringFromIndex: r.location + 1]; + if (![self isValidAttachmentName: name]) return [self invalidAttachmentNameError: name]; diff --git a/SoObjects/SOGo/LDAPSource.h b/SoObjects/SOGo/LDAPSource.h index 3e8a3c7b..201e16b8 100644 --- a/SoObjects/SOGo/LDAPSource.h +++ b/SoObjects/SOGo/LDAPSource.h @@ -31,6 +31,7 @@ @interface LDAPSource : NSObject { + NSString *sourceID; NSString *bindDN; NSString *hostname; unsigned int port; @@ -67,6 +68,7 @@ - (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID; - (NSArray *) allEntryIDs; - (NSArray *) fetchContactsMatching: (NSString *) filter; +- (NSString *) sourceID; @end diff --git a/SoObjects/SOGo/LDAPSource.m b/SoObjects/SOGo/LDAPSource.m index c2350e44..28475ad1 100644 --- a/SoObjects/SOGo/LDAPSource.m +++ b/SoObjects/SOGo/LDAPSource.m @@ -30,6 +30,7 @@ #import #import "LDAPSource.h" +#import "LDAPUserManager.h" static NSArray *commonSearchFields; static int timeLimit; @@ -114,8 +115,9 @@ static int sizeLimit; @"locality", @"birthyear", @"serialNumber", - @"calFBURL", + @"calFBURL", @"proxyAddresses", nil]; + [commonSearchFields retain]; } } @@ -138,6 +140,7 @@ static int sizeLimit; hostname = nil; port = 389; password = nil; + sourceID = nil; baseDN = nil; IDField = @"cn"; /* the first part of a user DN */ @@ -163,6 +166,7 @@ static int sizeLimit; [UIDField release]; [bindFields release]; [ldapConnection release]; + [sourceID release]; [super dealloc]; } @@ -170,6 +174,8 @@ static int sizeLimit; { self = [self init]; + ASSIGN(sourceID, [udSource objectForKey: @"id"]); + [self setBindDN: [udSource objectForKey: @"bindDN"] hostname: [udSource objectForKey: @"hostname"] port: [udSource objectForKey: @"port"] @@ -340,6 +346,8 @@ static int sizeLimit; - (NSArray *) _searchAttributes { + NSArray *attrs; + if (!searchAttributes) { searchAttributes = [NSMutableArray new]; @@ -350,6 +358,12 @@ static int sizeLimit; [searchAttributes addObjectsFromArray: commonSearchFields]; } + // We also include our MailFieldNames in the search + if ((attrs = [[[LDAPUserManager sharedUserManager] metadataForSourceID: sourceID] objectForKey: @"MailFieldNames"])) + { + [searchAttributes addObjectsFromArray: attrs]; + } + return searchAttributes; } @@ -493,4 +507,9 @@ static int sizeLimit; return contactEntry; } +- (NSString *) sourceID +{ + return sourceID; +} + @end diff --git a/SoObjects/SOGo/LDAPUserManager.h b/SoObjects/SOGo/LDAPUserManager.h index 6a3c6510..5ab95c92 100644 --- a/SoObjects/SOGo/LDAPUserManager.h +++ b/SoObjects/SOGo/LDAPUserManager.h @@ -44,6 +44,7 @@ + (id) sharedUserManager; - (NSArray *) sourceIDs; +- (NSDictionary *) metadataForSourceID: (NSString *) sourceID; - (NSArray *) authenticationSourceIDs; - (NSArray *) addressBookSourceIDs; diff --git a/SoObjects/SOGo/LDAPUserManager.m b/SoObjects/SOGo/LDAPUserManager.m index 01ab01a3..76e18108 100644 --- a/SoObjects/SOGo/LDAPUserManager.m +++ b/SoObjects/SOGo/LDAPUserManager.m @@ -75,6 +75,9 @@ static NSString *defaultMailDomain = nil; value = [udSource objectForKey: @"displayName"]; if (value) [metadata setObject: value forKey: @"displayName"]; + value = [udSource objectForKey: @"MailFieldNames"]; + if (value) + [metadata setObject: value forKey: @"MailFieldNames"]; [sourcesMetadata setObject: metadata forKey: sourceID]; } @@ -151,6 +154,11 @@ static NSString *defaultMailDomain = nil; return sourceIDs; } +- (NSDictionary *) metadataForSourceID: (NSString *) sourceID +{ + return [sourcesMetadata objectForKey: sourceID]; +} + - (NSArray *) authenticationSourceIDs { return [self _sourcesOfType: @"canAuthenticate"]; @@ -295,7 +303,8 @@ static NSString *defaultMailDomain = nil; NSEnumerator *ldapSources; LDAPSource *currentSource; NSString *cn, *email, *c_uid; - + NSArray *attrs; + emails = [NSMutableArray array]; cn = nil; c_uid = nil; @@ -311,15 +320,18 @@ static NSString *defaultMailDomain = nil; cn = [userEntry objectForKey: @"c_cn"]; if (!c_uid) c_uid = [userEntry objectForKey: @"c_uid"]; - email = [userEntry objectForKey: @"mail"]; - if (email && ![emails containsObject: email]) - [emails addObject: email]; - email = [userEntry objectForKey: @"mozillaSecondEmail"]; - if (email && ![emails containsObject: email]) - [emails addObject: email]; - email = [userEntry objectForKey: @"xmozillasecondemail"]; - if (email && ![emails containsObject: email]) - [emails addObject: email]; + + if ((attrs = [[sourcesMetadata objectForKey: [currentSource sourceID]] objectForKey: @"MailFieldNames"])) + { + int i; + + for (i = 0; i < [attrs count]; i++) + { + email = [userEntry objectForKey: [attrs objectAtIndex: i]]; + if (email && ![emails containsObject: email]) + [emails addObject: email]; + } + } } currentSource = [ldapSources nextObject]; } @@ -332,7 +344,13 @@ static NSString *defaultMailDomain = nil; [currentUser setObject: emails forKey: @"emails"]; [currentUser setObject: cn forKey: @"cn"]; [currentUser setObject: c_uid forKey: @"c_uid"]; - [self _fillContactMailRecords: currentUser]; + + // If our LDAP queries gave us nothing, we add at least one default + // email address based on the default domain. + if ([emails count] == 0) + { + [self _fillContactMailRecords: currentUser]; + } } - (void) _retainUser: (NSDictionary *) newUser diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m index e5d67de7..1192ccd7 100644 --- a/SoObjects/SOGo/NSString+Utilities.m +++ b/SoObjects/SOGo/NSString+Utilities.m @@ -1,6 +1,6 @@ /* NSString+Utilities.m - this file is part of SOGo * - * Copyright (C) 2006 Inverse group conseil + * Copyright (C) 2006 Inverse groupe conseil * * Author: Wolfgang Sourdeau * @@ -155,7 +155,7 @@ static NSMutableCharacterSet *urlAfterEndingChars = nil; if (!urlAfterEndingChars) { urlAfterEndingChars = [NSMutableCharacterSet new]; - [urlAfterEndingChars addCharactersInString: @"\t \r\n"]; + [urlAfterEndingChars addCharactersInString: @"[]\t \r\n"]; } start = refRange.location; @@ -165,7 +165,7 @@ static NSMutableCharacterSet *urlAfterEndingChars = nil; start--; start++; length = [self length] - start; - workRange = NSMakeRange (start, length); + workRange = NSMakeRange(start, length); workRange = [self rangeOfCharacterFromSet: urlAfterEndingChars options: NSLiteralSearch range: workRange]; if (workRange.location != NSNotFound) @@ -193,13 +193,15 @@ static NSMutableCharacterSet *urlAfterEndingChars = nil; while (httpRange.location != NSNotFound) { if ([ranges hasRangeIntersection: httpRange]) - rest.location = NSMaxRange (httpRange); + rest.location = NSMaxRange(httpRange); else { currentURL = [selfCopy _rangeOfURLInRange: httpRange]; urlText = [selfCopy substringFromRange: currentURL]; if ([urlText length] > matchLength) { + if ([urlText hasPrefix: prefix]) prefix = @""; + newUrlText = [NSString stringWithFormat: @"%@", prefix, urlText, urlText]; [selfCopy replaceCharactersInRange: currentURL @@ -208,8 +210,9 @@ static NSMutableCharacterSet *urlAfterEndingChars = nil; = NSMakeRange (currentURL.location, [newUrlText length]); [ranges addRange: currentURL]; } - rest.location = NSMaxRange (currentURL); + rest.location = NSMaxRange(currentURL); } + length = [selfCopy length]; rest.length = length - rest.location; httpRange = [selfCopy rangeOfString: match diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index 9dedfae4..0197ca93 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -365,22 +365,31 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek"; if (!mailAccounts) { + NSArray *mails; + int i; + mailAccount = [NSMutableDictionary dictionary]; name = [NSString stringWithFormat: @"%@@%@", login, fallbackIMAP4Server]; [mailAccount setObject: login forKey: @"userName"]; [mailAccount setObject: fallbackIMAP4Server forKey: @"serverName"]; [mailAccount setObject: name forKey: @"name"]; - identity = [NSMutableDictionary dictionary]; - fullName = [self cn]; - if (![fullName length]) - fullName = login; - [identity setObject: fullName forKey: @"fullName"]; - [identity setObject: [self systemEmail] forKey: @"email"]; - [identity setObject: [NSNumber numberWithBool: YES] forKey: @"isDefault"]; - identities = [NSMutableArray array]; - [identities addObject: identity]; + mails = [self allEmails]; + + for (i = 0; i < [mails count]; i++) + { + identity = [NSMutableDictionary dictionary]; + fullName = [self cn]; + if (![fullName length]) + fullName = login; + [identity setObject: fullName forKey: @"fullName"]; + [identity setObject: [mails objectAtIndex: i] forKey: @"email"]; + + if (i == 0) [identity setObject: [NSNumber numberWithBool: YES] forKey: @"isDefault"]; + [identities addObject: identity]; + } + [mailAccount setObject: identities forKey: @"identities"]; mailAccounts = [NSMutableArray new]; @@ -499,7 +508,7 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek"; [(WOContext *)_ctx setObject: ((folder) ? folder - : [NSNull null]) + : (id)[NSNull null]) forKey: @"ActiveUserHomeFolder"]; return folder; } diff --git a/UI/Common/English.lproj/Localizable.strings b/UI/Common/English.lproj/Localizable.strings index 6d453e13..dec4c8c7 100644 --- a/UI/Common/English.lproj/Localizable.strings +++ b/UI/Common/English.lproj/Localizable.strings @@ -10,7 +10,7 @@ "Address Book" = "Address Book"; "Mail" = "Mail"; "Preferences" = "Preferences"; -"Logoff" = "Logoff"; +"Sign Out" = "Sign Out"; "Right Administration" = "Right Administration"; "Log Console (dev.)" = "Log Console (dev.)"; @@ -27,7 +27,7 @@ "Sorry, the user rights can not be configured for that object." = "Sorry, the user rights can not be configured for that object."; -"browserNotCompatible" = "We've detected that your browser version is currently not supported on this site. Our recommendation is to use Firefox. Link to download the most current version of this browser is provided bellow:"; +"browserNotCompatible" = "We've detected that your browser version is currently not supported on this site. Our recommendation is to use Firefox. Click on the link bellow to download the most current version of this browser."; "alternativeBrowsers" = "Alternatively, you can also use the following compatible browsers"; "alternativeBrowserSafari" = "Alternatively, you can also use Safari."; "Download" = "Download"; diff --git a/UI/Common/French.lproj/Localizable.strings b/UI/Common/French.lproj/Localizable.strings index 7cd854ba..5e1e6ce0 100644 --- a/UI/Common/French.lproj/Localizable.strings +++ b/UI/Common/French.lproj/Localizable.strings @@ -8,7 +8,7 @@ "Address Book" = "Carnet d'adresses"; "Mail" = "Courrier"; "Preferences" = "Préférences"; -"Logoff" = "Quitter"; +"Sign Out" = "Quitter"; "Right Administration" = "Partage"; "Log Console (dev.)" = "Journal (dév.)"; diff --git a/UI/Common/UIxFolderActions.m b/UI/Common/UIxFolderActions.m index 943fbafe..1c2d59b0 100644 --- a/UI/Common/UIxFolderActions.m +++ b/UI/Common/UIxFolderActions.m @@ -31,6 +31,7 @@ #import #import #import +#import #import #import @@ -146,7 +147,34 @@ - (WOResponse *) canAccessContentAction { - return [self responseWith204]; +#warning IMPROVEMENTS REQUIRED! + NSArray *acls; +// NSEnumerator *userAcls; +// NSString *currentAcl; + + [self _setupContext]; + +// NSLog(@"canAccessContentAction %@, owner %@", subscriptionPointer, owner); + + if ([login isEqualToString: owner] || [owner isEqualToString: @"nobody"]) { + return [self responseWith204]; + } + else { + acls = [clientObject aclsForUser: login]; +// userAcls = [acls objectEnumerator]; +// currentAcl = [userAcls nextObject]; +// while (currentAcl) { +// NSLog(@"ACL login %@, owner %@, folder %@: %@", +// login, owner, baseFolder, currentAcl); +// currentAcl = [userAcls nextObject]; +// } + if (([[clientObject folderType] isEqualToString: @"Contact"] && [acls containsObject: SOGoRole_ObjectReader]) || + ([[clientObject folderType] isEqualToString: @"Appointment"] && [acls containsObject: SOGoRole_AuthorizedSubscriber])) { + return [self responseWith204]; + } + } + + return [self responseWithStatus: 403]; } - (WOResponse *) _realFolderActivation: (BOOL) makeActive diff --git a/UI/Common/UIxPageFrame.m b/UI/Common/UIxPageFrame.m index 193781ed..a5e6989a 100644 --- a/UI/Common/UIxPageFrame.m +++ b/UI/Common/UIxPageFrame.m @@ -274,6 +274,7 @@ ([[cc userAgentType] isEqualToString: @"IE"] && [cc majorVersion] >= 7) || ([[cc userAgentType] isEqualToString: @"Mozilla"] && [cc majorVersion] >= 5) || ([[cc userAgentType] isEqualToString: @"Safari"] && [cc majorVersion] >= 4) + // ([[cc userAgentType] isEqualToString: @"Konqueror"]) ); } diff --git a/UI/MailPartViewers/UIxMailPartTextViewer.m b/UI/MailPartViewers/UIxMailPartTextViewer.m index 450c1421..22d41a38 100644 --- a/UI/MailPartViewers/UIxMailPartTextViewer.m +++ b/UI/MailPartViewers/UIxMailPartTextViewer.m @@ -44,8 +44,6 @@ content = [NSMutableString string]; superContent = [[super flatContentAsString] stringByEscapingHTMLString]; [content appendString: [superContent stringByDetectingURLs]]; - [content replaceString: @"\r\n" withString: @"
"]; - [content replaceString: @"\n" withString: @"
"]; return content; } diff --git a/UI/MailerUI/English.lproj/Localizable.strings b/UI/MailerUI/English.lproj/Localizable.strings index b058b07a..b8d4e8b9 100644 --- a/UI/MailerUI/English.lproj/Localizable.strings +++ b/UI/MailerUI/English.lproj/Localizable.strings @@ -153,5 +153,6 @@ "quotasFormat" = "Quotas: %{0} used on %{1} Kb; %{2}%"; +"Please select a message." = "Please select a message."; "Please select a message to print." = "Please select a message to print."; "Please select only one message to print." = "Please select only one message to print."; diff --git a/UI/MailerUI/French.lproj/Localizable.strings b/UI/MailerUI/French.lproj/Localizable.strings index cf34cac3..3fed423b 100644 --- a/UI/MailerUI/French.lproj/Localizable.strings +++ b/UI/MailerUI/French.lproj/Localizable.strings @@ -203,5 +203,6 @@ "quotasFormat" = "Quotas: %{0} Ko utilisés sur %{1}; %{2}%"; +"Please select a message." = "Veuillez sélectionner un message."; "Please select a message to print." = "Veuillez sélectionner un message à imprimer."; "Please select only one message to print." = "Veuillez ne sélectionner qu'un seul message à imprimer."; diff --git a/UI/MailerUI/German.lproj/Localizable.strings b/UI/MailerUI/German.lproj/Localizable.strings index 9f5b86c3..ad9ec372 100644 --- a/UI/MailerUI/German.lproj/Localizable.strings +++ b/UI/MailerUI/German.lproj/Localizable.strings @@ -186,5 +186,6 @@ "quotasFormat" = "Quota: %{0} von %{1} KB verwendet; %{2}%"; +"Please select a message." = "Sie müssen eine Nachricht auswählen."; "Please select a message to print." = "Sie müssen eine Nachricht zum Drucken auswählen."; "Please select only one message to print." = "Bitte wählen Sie nur eine Nachricht zum Drucken aus."; diff --git a/UI/MailerUI/UIxMailEditor.m b/UI/MailerUI/UIxMailEditor.m index d09189a6..a2eb9ee0 100644 --- a/UI/MailerUI/UIxMailEditor.m +++ b/UI/MailerUI/UIxMailEditor.m @@ -442,7 +442,7 @@ static NSArray *infoKeys = nil; { result = [[self clientObject] sendMail]; if (!result) - result = [self jsCloseWithRefreshMethod: nil]; + result = [self jsCloseWithRefreshMethod: @"refreshFolderByType(\"sent\")"]; } else result = [self failedToSaveFormResponse]; diff --git a/UI/MainUI/English.lproj/Localizable.strings b/UI/MainUI/English.lproj/Localizable.strings index 932c4219..9cc6c319 100644 --- a/UI/MainUI/English.lproj/Localizable.strings +++ b/UI/MainUI/English.lproj/Localizable.strings @@ -6,3 +6,5 @@ "Password:" = "Password:"; "Connect" = "Connect"; + +"Wrong username or password." = "Wrong username or password."; \ No newline at end of file diff --git a/UI/MainUI/French.lproj/Localizable.strings b/UI/MainUI/French.lproj/Localizable.strings index dbdc05ac..2cd2ec06 100644 --- a/UI/MainUI/French.lproj/Localizable.strings +++ b/UI/MainUI/French.lproj/Localizable.strings @@ -6,3 +6,5 @@ "Password:" = "Mot de passe :"; "Connect" = "Connexion"; + +"Wrong username or password." = "Mauvais nom d'utilisateur ou mot de passe."; \ No newline at end of file diff --git a/UI/MainUI/SOGoUserHomePage.m b/UI/MainUI/SOGoUserHomePage.m index 032a615f..22c6a295 100644 --- a/UI/MainUI/SOGoUserHomePage.m +++ b/UI/MainUI/SOGoUserHomePage.m @@ -64,8 +64,6 @@ static NSString *defaultModule = nil; @"'Calendar', 'Contacts' or Mail)", defaultModule]; defaultModule = @"Calendar"; } - else - defaultModule = @"Calendar"; } else defaultModule = @"Calendar"; diff --git a/UI/SOGoUI/UIxComponent.m b/UI/SOGoUI/UIxComponent.m index 643dca56..273d3e20 100644 --- a/UI/SOGoUI/UIxComponent.m +++ b/UI/SOGoUI/UIxComponent.m @@ -423,6 +423,9 @@ static BOOL uixDebugEnabled = NO; - (NSString *) shortUserNameForDisplay { + if ([context activeUser] == nil) + return @"wrongusernamepassword"; + return [[context activeUser] login]; } diff --git a/UI/Scheduler/English.lproj/Localizable.strings b/UI/Scheduler/English.lproj/Localizable.strings index fde04128..69afbd28 100644 --- a/UI/Scheduler/English.lproj/Localizable.strings +++ b/UI/Scheduler/English.lproj/Localizable.strings @@ -410,5 +410,5 @@ validate_endbeforestart = "Enddate is before startdate!"; "Location" = "Location"; "(Private Event)" = "(Private Event)"; -"closeThisWindowMessage" = "Thank you! You may now close this window."; +"closeThisWindowMessage" = "Thank you! You may now close this window or view your "; "Multicolumn Day View" = "Multicolumn Day View"; diff --git a/UI/Scheduler/French.lproj/Localizable.strings b/UI/Scheduler/French.lproj/Localizable.strings index ce110725..3adda5cf 100644 --- a/UI/Scheduler/French.lproj/Localizable.strings +++ b/UI/Scheduler/French.lproj/Localizable.strings @@ -409,5 +409,5 @@ validate_endbeforestart = "La date de fin est avant la date de début !"; "Location" = "Lieu"; "(Private Event)" = "(Événement privé)"; -"closeThisWindowMessage" = "Merci! Vous pouvez maintenant fermer cette fenêtre."; +"closeThisWindowMessage" = "Merci! Vous pouvez maintenant fermer cette fenêtre ou consulter votre "; "Multicolumn Day View" = "Multicolonne"; diff --git a/UI/Scheduler/UIxAppointmentEditor.h b/UI/Scheduler/UIxAppointmentEditor.h index e9074550..c3ead685 100644 --- a/UI/Scheduler/UIxAppointmentEditor.h +++ b/UI/Scheduler/UIxAppointmentEditor.h @@ -35,6 +35,7 @@ NSCalendarDate *aptStartDate; NSCalendarDate *aptEndDate; NSString *item; + NSString *repeat; } /* template values */ diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index a88b3f38..4f4fb0bb 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -20,6 +20,8 @@ * Boston, MA 02111-1307, USA. */ +#warning WE LEAK IVARS LIKE CRAZY HERE + #include #import @@ -29,6 +31,7 @@ #import #import +#import #import #import @@ -48,12 +51,19 @@ aptEndDate = nil; item = nil; event = nil; + repeat = nil; isAllDay = NO; } return self; } +- (void) dealloc +{ + RELEASE(repeat); + [super dealloc]; +} + /* template values */ - (iCalEvent *) event { @@ -132,6 +142,8 @@ else text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]]; + NSLog(@"itemRepeatText: %@", text); + return text; } @@ -198,11 +210,12 @@ - (NSString *) repeat { - return @""; + return repeat; } - (void) setRepeat: (NSString *) newRepeat { + ASSIGN(repeat, newRepeat); } - (NSString *) reminder @@ -276,8 +289,32 @@ ASSIGN (aptStartDate, startDate); ASSIGN (aptEndDate, endDate); - - /* here comes the code for initializing repeat, reminder and isAllDay... */ + // We initialize our repeat ivars + if ([event hasRecurrenceRules]) + { + iCalRecurrenceRule *rule; + + repeat = @"CUSTOM"; + + rule = [[event recurrenceRules] lastObject]; + + if ([rule frequency] == iCalRecurrenceFrequenceWeekly) + { + if ([rule repeatInterval] == 1) repeat = @"WEEKLY"; + else if ([rule repeatInterval] == 2) repeat = @"BI-WEEKLY"; + } + else if ([rule frequency] == iCalRecurrenceFrequenceDaily) + { + if ([rule byDayMask] == (iCalWeekDayMonday|iCalWeekDayTuesday|iCalWeekDayWednesday|iCalWeekDayThursday|iCalWeekDayFriday)) repeat = @"EVERY WEEKDAY"; + else if (![rule byDayMask]) repeat = @"DAILY"; + } + else if ([rule frequency] == iCalRecurrenceFrequenceMonthly && [rule repeatInterval] == 1) repeat = @"MONTHLY"; + else if ([rule frequency] == iCalRecurrenceFrequenceYearly && [rule repeatInterval] == 1) repeat = @"YEARLY"; + } + else + { + DESTROY(repeat); + } return self; } @@ -310,7 +347,11 @@ NSString *iCalString; clientObject = [self clientObject]; + NSLog(@"saveAction, clientObject = %@", clientObject); + iCalString = [[clientObject calendar: NO] versitString]; + + NSLog(@"saveAction, iCalString = %@", iCalString); [clientObject saveContentString: iCalString]; return [self jsCloseWithRefreshMethod: @"refreshEventsAndDisplay()"]; @@ -352,6 +393,37 @@ } if ([clientObject isNew]) [event setTransparency: @"OPAQUE"]; + + // We remove any repeat rules + if (!repeat && [event hasRecurrenceRules]) + { + [event removeAllRecurrenceRules]; + } + else if (!([repeat caseInsensitiveCompare: @"-"] == NSOrderedSame || [repeat caseInsensitiveCompare: @"CUSTOM"] == NSOrderedSame)) + { + iCalRecurrenceRule *rule; + + rule = [[iCalRecurrenceRule alloc] init]; + + if ([repeat caseInsensitiveCompare: @"BI-WEEKLY"] == NSOrderedSame) + { + [rule setFrequency: iCalRecurrenceFrequenceWeekly]; + [rule setInterval: @"2"]; + } + else if ([repeat caseInsensitiveCompare: @"EVERY WEEKDAY"] == NSOrderedSame) + { + [rule setByDayMask: (iCalWeekDayMonday|iCalWeekDayTuesday|iCalWeekDayWednesday|iCalWeekDayThursday|iCalWeekDayFriday)]; + [rule setFrequency: iCalRecurrenceFrequenceDaily]; + [rule setInterval: @"1"]; + } + else + { + [rule setFrequency: (iCalRecurrenceFrequency)[rule valueForFrequency: repeat]]; + [rule setInterval: @"1"]; + } + [event setRecurrenceRules: [NSArray arrayWithObject: rule]]; + RELEASE(rule); + } } // TODO: add tentatively diff --git a/UI/Scheduler/UIxCalListingActions.m b/UI/Scheduler/UIxCalListingActions.m index b036060f..56a60829 100644 --- a/UI/Scheduler/UIxCalListingActions.m +++ b/UI/Scheduler/UIxCalListingActions.m @@ -221,50 +221,42 @@ { NSEnumerator *folders, *currentInfos; SOGoAppointmentFolder *currentFolder; - NSMutableDictionary *infos, *currentInfo, *newInfo; - NSString *owner, *uid; + NSMutableDictionary *newInfo; + NSMutableArray *infos; NSNull *marker; SOGoAppointmentFolders *clientObject; marker = [NSNull null]; - infos = [NSMutableDictionary dictionary]; - clientObject = [self clientObject]; + clientObject = [self clientObject]; folders = [[clientObject subFolders] objectEnumerator]; currentFolder = [folders nextObject]; + + infos = [NSMutableArray array]; while (currentFolder) { if ([currentFolder isActive]) { - owner = [currentFolder ownerInContext: context]; currentInfos = [[currentFolder fetchCoreInfosFrom: startDate to: endDate component: component] objectEnumerator]; - newInfo = [currentInfos nextObject]; - while (newInfo) + + while ((newInfo = [currentInfos nextObject])) { - uid = [newInfo objectForKey: @"c_uid"]; - currentInfo = [infos objectForKey: uid]; - if (!currentInfo - || [owner isEqualToString: userLogin]) - { - [self _updatePrivacyInComponent: newInfo - fromFolder: currentFolder]; - [newInfo setObject: [currentFolder nameInContainer] - forKey: @"c_folder"]; - // [newInfo setObject: owner forKey: @"c_owner"]; - [infos setObject: [newInfo objectsForKeys: fields - notFoundMarker: marker] - forKey: uid]; - } - newInfo = [currentInfos nextObject]; + [self _updatePrivacyInComponent: newInfo + fromFolder: currentFolder]; + [newInfo setObject: [currentFolder nameInContainer] + forKey: @"c_folder"]; + + [infos addObject: [newInfo objectsForKeys: fields + notFoundMarker: marker]]; } } currentFolder = [folders nextObject]; } - return [infos allValues]; + return infos; } - (WOResponse *) _responseWithData: (NSArray *) data diff --git a/UI/Scheduler/UIxCalMonthOverview.h b/UI/Scheduler/UIxCalMonthOverview.h index f265d43d..511d0819 100644 --- a/UI/Scheduler/UIxCalMonthOverview.h +++ b/UI/Scheduler/UIxCalMonthOverview.h @@ -18,7 +18,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ +// $Id: UIxCalMonthOverview.h 181 2004-08-11 15:13:25Z helge $ #import "UIxCalMonthViewOld.h" diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 9046b322..a972885d 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -365,7 +365,11 @@ - (NSString *) componentCalendar { - return @"/"; + SOGoAppointmentFolder *calendar; + + calendar = [[self clientObject] container]; + + return calendar; } /* priorities */ @@ -373,14 +377,15 @@ - (NSArray *) priorities { /* 0 == undefined - 5 == normal + 9 == low + 5 == medium 1 == high */ static NSArray *priorities = nil; if (!priorities) { - priorities = [NSArray arrayWithObjects: @"0", @"5", @"1", nil]; + priorities = [NSArray arrayWithObjects: @"9", @"5", @"1", nil]; [priorities retain]; } @@ -856,8 +861,8 @@ [component setUid: [clientObject nameInContainer]]; [component setCreated: now]; [component setTimeStampAsDate: now]; - [component setPriority: @"0"]; } + [component setPriority: priority]; [component setLastModified: now]; } diff --git a/UI/Templates/ContactsUI/UIxContactsListView.wox b/UI/Templates/ContactsUI/UIxContactsListView.wox index 950cfade..d98db7d2 100644 --- a/UI/Templates/ContactsUI/UIxContactsListView.wox +++ b/UI/Templates/ContactsUI/UIxContactsListView.wox @@ -10,22 +10,23 @@ selectorComponentClass="selectorComponentClass" title="name"> - + - - + +
- + \ No newline at end of file diff --git a/UI/Templates/MailerUI/UIxMailListView.wox b/UI/Templates/MailerUI/UIxMailListView.wox index f77b3198..09dbd6b6 100644 --- a/UI/Templates/MailerUI/UIxMailListView.wox +++ b/UI/Templates/MailerUI/UIxMailListView.wox @@ -1,6 +1,6 @@ - | - - - - - - | - + 0 + + + + + + + + | + + diff --git a/UI/Templates/MainUI/SOGoRootPage.wox b/UI/Templates/MainUI/SOGoRootPage.wox index af0bc6bc..78353a75 100644 --- a/UI/Templates/MainUI/SOGoRootPage.wox +++ b/UI/Templates/MainUI/SOGoRootPage.wox @@ -11,7 +11,9 @@


-
- - - - - - + + + + + + + + +
diff --git a/UI/Templates/SchedulerUI/UIxCalendarSelector.wox b/UI/Templates/SchedulerUI/UIxCalendarSelector.wox index ae36b74f..6340a725 100644 --- a/UI/Templates/SchedulerUI/UIxCalendarSelector.wox +++ b/UI/Templates/SchedulerUI/UIxCalendarSelector.wox @@ -27,7 +27,7 @@ label:title="Remove the selected Calendar" /> -