From 312ed2824fd1e94746209431dac6111de0030de9 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 5 May 2010 13:45:18 +0000 Subject: [PATCH 1/7] Monotone-Parent: fcf51dfbffeff460e370282e0f739875e3414767 Monotone-Revision: f2d1ff2e80e90f3c3d73fe6006e22ee1e9d39b01 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-05-05T13:45:18 Monotone-Branch: ca.inverse.sogo --- SOPE/NGCards/ChangeLog | 11 ++- SOPE/NGCards/iCalEntityObject.h | 7 +- SOPE/NGCards/iCalEntityObject.m | 125 ++++++++++++++++---------------- 3 files changed, 77 insertions(+), 66 deletions(-) diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index 9776cecca..ac57bddf2 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,3 +1,12 @@ +2010-05-05 Wolfgang Sourdeau + + * iCalEntityObject.m (-resources): removed useless method. + (-nonParticipants): new method returning ATTENDEE objects having + their ROLE attribute set to "NON-PARTICIPANT". + (-isAttendee:): new method. + (-findAttendeeWithEmail): new method replacing + "findParticipantWithEmail:". + 2010-04-28 Wolfgang Sourdeau * iCalRecurrenceRule.m (-iCalRepresentationForWeekDay:): made @@ -34,7 +43,7 @@ * iCalWeeklyRecurrenceCalculator.m (-recurrenceRangesWithinCalendarDateRange:): make use of the new - iCalByDayMask class. + iCalByDayMask class. (-lastInstanceStartDate): make use of the previous method when a BYxxx mask is defined in the rule. diff --git a/SOPE/NGCards/iCalEntityObject.h b/SOPE/NGCards/iCalEntityObject.h index ba62d1ce9..36491e206 100644 --- a/SOPE/NGCards/iCalEntityObject.h +++ b/SOPE/NGCards/iCalEntityObject.h @@ -109,15 +109,16 @@ typedef enum - (void) addToAttendees: (iCalPerson *) _person; - (NSArray *) attendees; - (void) setAttendees: (NSArray *) attendees; +- (BOOL) isAttendee: (id) _email; - (void) removeFromAttendees: (iCalPerson *) oldAttendee; - (void) removeAllAttendees; -/* categorize attendees into participants and resources */ +/* categorize attendees into participants and non-participants */ - (NSArray *) participants; -- (NSArray *) resources; +- (NSArray *) nonParticipants; - (BOOL) isParticipant: (id) _email; -- (iCalPerson *) findParticipantWithEmail: (id) _email; +- (iCalPerson *) findAttendeeWithEmail: (id) email; - (void) removeAllAlarms; - (void) addToAlarms: (id) _alarm; diff --git a/SOPE/NGCards/iCalEntityObject.m b/SOPE/NGCards/iCalEntityObject.m index 11d7f82dc..bbe7fa262 100644 --- a/SOPE/NGCards/iCalEntityObject.m +++ b/SOPE/NGCards/iCalEntityObject.m @@ -330,6 +330,40 @@ return [self childrenWithTag: @"attendee"]; } +- (BOOL) isAttendee: (id) _email +{ + NSArray *attEmails; + + _email = [_email lowercaseString]; + attEmails = [[self attendees] valueForKey:@"rfc822Email"]; + attEmails = [attEmails valueForKey: @"lowercaseString"]; + return [attEmails containsObject:_email]; +} + +- (iCalPerson *) findAttendeeWithEmail: (id) email +{ + NSArray *attendees; + unsigned int count, max; + NSString *lowerEmail, *currentEmail; + iCalPerson *attendee, *currentAttendee; + + attendee = nil; + + lowerEmail = [email lowercaseString]; + attendees = [self attendees]; + max = [attendees count]; + + for (count = 0; attendee == nil && count < max; count++) + { + currentAttendee = [attendees objectAtIndex: count]; + currentEmail = [[currentAttendee rfc822Email] lowercaseString]; + if ([currentEmail isEqualToString: lowerEmail]) + attendee = currentAttendee; + } + + return attendee; +} + - (void) removeAllAlarms { [children removeObjectsInArray: [self alarms]]; @@ -406,48 +440,6 @@ } /* stuff */ - -- (NSArray *) participants -{ - return [self _filteredAttendeesThinkingOfPersons: YES]; -} - -- (NSArray *) resources -{ - return [self _filteredAttendeesThinkingOfPersons: NO]; -} - -- (NSArray *) _filteredAttendeesThinkingOfPersons: (BOOL) _persons -{ - NSArray *list; - NSMutableArray *filtered; - unsigned count, max; - iCalPerson *person; - NSString *role; - - if (_persons) - { - list = [self attendees]; - max = [list count]; - filtered = [NSMutableArray arrayWithCapacity: max]; - for (count = 0; count < max; count++) - { - person = (iCalPerson *) [list objectAtIndex: count]; - role = [[person role] uppercaseString]; - if (![role hasPrefix: @"NON-PART"]) - [filtered addObject: person]; - } - - list = filtered; - } - else - list = [self childrenWithTag: @"attendee" - andAttribute: @"role" - havingValue: @"non-part"]; - - return list; -} - - (BOOL) isOrganizer: (id) _email { NSString *organizerMail; @@ -458,6 +450,35 @@ isEqualToString: [_email lowercaseString]]; } +- (NSArray *) participants +{ + NSArray *list; + NSMutableArray *filtered; + unsigned count, max; + iCalPerson *person; + NSString *role; + + list = [self attendees]; + max = [list count]; + filtered = [NSMutableArray arrayWithCapacity: max]; + for (count = 0; count < max; count++) + { + person = [list objectAtIndex: count]; + role = [[person role] uppercaseString]; + if (![role hasPrefix: @"NON-PARTICIPANT"]) + [filtered addObject: person]; + } + + return filtered; +} + +- (NSArray *) nonParticipants +{ + return [self childrenWithTag: @"attendee" + andAttribute: @"role" + havingValue: @"non-participant"]; +} + - (BOOL) isParticipant: (id) _email { NSArray *partEmails; @@ -468,26 +489,6 @@ return [partEmails containsObject:_email]; } -- (iCalPerson *) findParticipantWithEmail: (id) _email -{ - NSArray *ps; - unsigned i, count; - - _email = [_email lowercaseString]; - ps = [self participants]; - count = [ps count]; - - for (i = 0; i < count; i++) { - iCalPerson *p; - - p = [ps objectAtIndex:i]; - if ([[[p rfc822Email] lowercaseString] isEqualToString:_email]) - return p; - } - - return nil; /* not found */ -} - - (NSComparisonResult) _compareValue: (id) selfValue withValue: (id) otherValue { From 37cbdd43780c6fcfbc6c10e31dc97a4a212d0274 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 5 May 2010 13:46:58 +0000 Subject: [PATCH 2/7] Monotone-Parent: 915f4f176feb772bfa74b034b6b7ce28f66778f8 Monotone-Revision: 4fb71d76cac3b87ffc098133f9c93d0e753c5284 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-05-05T13:46:58 Monotone-Branch: ca.inverse.sogo --- SOPE/NGCards/versitCardsSaxDriver/ChangeLog | 5 +++++ .../NGCards/versitCardsSaxDriver/VSSaxDriver.m | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/SOPE/NGCards/versitCardsSaxDriver/ChangeLog b/SOPE/NGCards/versitCardsSaxDriver/ChangeLog index 27c495fd6..5afb1fde4 100644 --- a/SOPE/NGCards/versitCardsSaxDriver/ChangeLog +++ b/SOPE/NGCards/versitCardsSaxDriver/ChangeLog @@ -1,3 +1,8 @@ +2010-05-05 Wolfgang Sourdeau + + * VSSaxDriver.m (_endComponent:value:): avoid a crash occurring + when an inconsistency is found in the stack of containers. + 2009-12-22 Wolfgang Sourdeau * VSSaxDriver.m (_endComponent:value:): worked-around the lameness diff --git a/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m b/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m index 7da82eb50..4b6763941 100644 --- a/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m +++ b/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m @@ -31,6 +31,7 @@ #import "VSSaxDriver.h" #import #import +#import #import #import #import "common.h" @@ -653,6 +654,7 @@ static NSCharacterSet *whitespaceCharSet = nil; value: (NSString *) tagValue { NSString *mtName; + int max; mtName = [[self _mapTagName: tagValue] uppercaseString]; if ([cardStack count] > 0) @@ -692,11 +694,19 @@ static NSCharacterSet *whitespaceCharSet = nil; stringByAppendingString: mtName]]; } [self _endGroupElementTag: mtName]; - [cardStack removeLastObject]; - + + max = [cardStack count]; + if (max > 0) + { + [cardStack removeLastObject]; + max--; + } + else + [self errorWithFormat: @"serious inconsistency among begin/end tags"]; + /* report parsed elements */ - - if ([cardStack count] == 0) + + if (max == 0) [self reportQueuedTags]; } From 82a38c87fb72e388d7f59495a5bc456545afa677 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 5 May 2010 13:48:06 +0000 Subject: [PATCH 3/7] Monotone-Parent: 4fb71d76cac3b87ffc098133f9c93d0e753c5284 Monotone-Revision: de6d837f5c2b62b4ad465872fdc54602b3d1009c Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-05-05T13:48:06 Monotone-Branch: ca.inverse.sogo --- SOPE/NGCards/ChangeLog | 4 ++++ SOPE/NGCards/iCalPerson.h | 1 + SOPE/NGCards/iCalPerson.m | 7 ++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index ac57bddf2..20ec67b1f 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,5 +1,9 @@ 2010-05-05 Wolfgang Sourdeau + * iCalPerson.m (-setParticipationStatus:, -participationStatus): + added handling of the new partstat value + "iCalPersonPartStatUndefined". + * iCalEntityObject.m (-resources): removed useless method. (-nonParticipants): new method returning ATTENDEE objects having their ROLE attribute set to "NON-PARTICIPANT". diff --git a/SOPE/NGCards/iCalPerson.h b/SOPE/NGCards/iCalPerson.h index 6c7644673..4aac91d14 100644 --- a/SOPE/NGCards/iCalPerson.h +++ b/SOPE/NGCards/iCalPerson.h @@ -25,6 +25,7 @@ #import "CardElement.h" typedef enum { + iCalPersonPartStatUndefined = -1, /* empty/undefined */ iCalPersonPartStatNeedsAction = 0, /* NEEDS-ACTION (DEFAULT) */ iCalPersonPartStatAccepted = 1, /* ACCEPTED */ iCalPersonPartStatDeclined = 2, /* DECLINED */ diff --git a/SOPE/NGCards/iCalPerson.m b/SOPE/NGCards/iCalPerson.m index 971a0d101..449c1b012 100644 --- a/SOPE/NGCards/iCalPerson.m +++ b/SOPE/NGCards/iCalPerson.m @@ -133,6 +133,9 @@ NSString *stat; switch (_status) { + case iCalPersonPartStatUndefined: + stat = @""; + break; case iCalPersonPartStatAccepted: stat = @"ACCEPTED"; break; @@ -170,7 +173,9 @@ NSString *stat; stat = [[self partStat] uppercaseString]; - if (![stat length] || [stat isEqualToString:@"NEEDS-ACTION"]) + if (![stat length]) + return iCalPersonPartStatUndefined; + else if ([stat isEqualToString:@"NEEDS-ACTION"]) return iCalPersonPartStatNeedsAction; else if ([stat isEqualToString:@"ACCEPTED"]) return iCalPersonPartStatAccepted; From f7799b9cf8e491d8fab43e65ed0edfbe9bf189a8 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 5 May 2010 13:56:19 +0000 Subject: [PATCH 4/7] Monotone-Parent: de6d837f5c2b62b4ad465872fdc54602b3d1009c Monotone-Revision: 1ccd34fd9ea99e675935d745db7e70d19716428a Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-05-05T13:56:19 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 13 +++++ .../Appointments/SOGoAppointmentObject.m | 39 +++++++------- .../Appointments/SOGoCalendarComponent.m | 11 ++-- .../Appointments/iCalEntityObject+SOGo.h | 4 +- .../Appointments/iCalEntityObject+SOGo.m | 46 ++++++++-------- SoObjects/SOGo/GNUmakefile | 2 - SoObjects/SOGo/iCalEntityObject+Utilities.h | 37 ------------- SoObjects/SOGo/iCalEntityObject+Utilities.m | 53 ------------------- UI/MailPartViewers/UIxMailPartICalViewer.m | 13 +++-- 9 files changed, 68 insertions(+), 150 deletions(-) delete mode 100644 SoObjects/SOGo/iCalEntityObject+Utilities.h delete mode 100644 SoObjects/SOGo/iCalEntityObject+Utilities.m diff --git a/ChangeLog b/ChangeLog index cc4bf6cb1..ec184ffb3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2010-05-05 Wolfgang Sourdeau + + * SoObjects/Appointments/iCalEntityObject+SOGo.m + (-userIsParticipant:): renamed to "userIsAttendee:". We now + request the list of attendees rather than the list of + participants. + (-userAsParticipant:): renamed to "userAsAttendee:". Again, we + return the attendee matching the user, whether he/she is a + participant or not. + + * SoObjects/SOGo/iCalEntityObject+Utilities.[hm]: removed useless + module, since it implemented methods already found elsewhere. + 2010-05-04 Wolfgang Sourdeau * UI/WebServerResources/ContactsUI.js (initContacts): we must diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index a143f11ef..896c23d2e 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -39,7 +39,6 @@ #import -#import #import #import #import @@ -591,13 +590,13 @@ SOGoUser *currentUser; currentUser = [context activeUser]; - otherAttendee = [event findParticipant: theOwnerUser]; + otherAttendee = [event userAsAttendee: theOwnerUser]; delegateEmail = [otherAttendee delegatedTo]; if ([delegateEmail length]) delegateEmail = [delegateEmail rfc822Email]; if ([delegateEmail length]) - otherDelegate = [event findParticipantWithEmail: delegateEmail]; + otherDelegate = [event findAttendeeWithEmail: delegateEmail]; else otherDelegate = NO; @@ -635,7 +634,7 @@ delegateEmail = [delegateEmail rfc822Email]; if ([delegateEmail length]) - otherDelegate = [event findParticipantWithEmail: delegateEmail]; + otherDelegate = [event findAttendeeWithEmail: delegateEmail]; else otherDelegate = NO; } @@ -708,7 +707,7 @@ delegateEmail = [delegateEmail rfc822Email]; if ([delegateEmail length]) - otherDelegate = [event findParticipantWithEmail: delegateEmail]; + otherDelegate = [event findAttendeeWithEmail: delegateEmail]; else otherDelegate = NO; @@ -792,7 +791,7 @@ delegateEmail = [delegateEmail rfc822Email]; if ([delegateEmail length]) - otherDelegate = [event findParticipantWithEmail: delegateEmail]; + otherDelegate = [event findAttendeeWithEmail: delegateEmail]; else otherDelegate = NO; } @@ -860,7 +859,7 @@ shouldAddSentBy: YES]; } - // We update the calendar of all participants that are + // We update the calendar of all attendees that are // local to the system. This is useful in case user A accepts // invitation from organizer B and users C, D, E who are also // attendees need to verify if A has accepted. @@ -1075,7 +1074,7 @@ [self sendReceiptEmailUsingTemplateNamed: (isUpdate ? @"Update" : @"Invitation") forObject: emailEvent - to: [newEvent participants]]; + to: [newEvent attendees]]; return elements; } @@ -1120,7 +1119,7 @@ [self sendReceiptEmailUsingTemplateNamed: @"Deletion" forObject: event - to: [event participants]]; + to: [event attendees]]; return elements; } @@ -1161,7 +1160,7 @@ } // Find attendee within event - localAttendee = [event findParticipantWithEmail: [attendee rfc822Email]]; + localAttendee = [event findAttendeeWithEmail: [attendee rfc822Email]]; if (localAttendee) { // Update the attendee's status @@ -1230,7 +1229,7 @@ [[event parent] setMethod: @""]; ownerUser = [SOGoUser userWithLogin: [[SOGoUserManager sharedUserManager] getUIDForEmail: originator]]; - attendee = [event findParticipant: ownerUser]; + attendee = [event userAsAttendee: ownerUser]; eventUID = [event uid]; delegate = nil; @@ -1240,7 +1239,7 @@ delegateEmail = [delegateEmail substringFromIndex: 7]; if ([delegateEmail length]) delegate - = [event findParticipantWithEmail: delegateEmail]; + = [event findAttendeeWithEmail: delegateEmail]; } recipientsEnum = [recipients objectEnumerator]; @@ -1326,7 +1325,7 @@ // change will be on the attendee corresponding to the ownerUser. ownerUser = [SOGoUser userWithLogin: owner]; - attendee = [event findParticipant: ownerUser]; + attendee = [event userAsAttendee: ownerUser]; if (attendee) { if (delegate @@ -1338,9 +1337,9 @@ if (delegatedUser != nil && [event userIsOrganizer: delegatedUser]) ex = [NSException exceptionWithHTTPStatus: 403 reason: @"delegate is organizer"]; - if ([event isParticipant: [[delegate email] rfc822Email]]) + if ([event isAttendee: [[delegate email] rfc822Email]]) ex = [NSException exceptionWithHTTPStatus: 403 - reason: @"delegate is a participant"]; + reason: @"delegate is a attendee"]; else if ([SOGoGroup groupWithEmail: [[delegate email] rfc822Email] inDomain: [ownerUser domain]]) ex = [NSException exceptionWithHTTPStatus: 403 @@ -1411,7 +1410,7 @@ to: attendees]; } } - else if ([occurence userIsParticipant: ownerUser]) + else if ([occurence userIsAttendee: ownerUser]) // The current user deletes the occurence; let the organizer know that // the user has declined this occurence. [self changeParticipationStatus: @"DECLINED" withDelegate: nil @@ -1439,7 +1438,7 @@ NSArray *allEvents; int count, max; iCalEvent *currentEvent; - iCalPerson *ownerParticipant; + iCalPerson *ownerAttendee; NSString *key; SOGoUser *ownerUser; @@ -1452,14 +1451,14 @@ for (count = 0; count < max; count++) { currentEvent = [allEvents objectAtIndex: count]; - ownerParticipant = [currentEvent userAsParticipant: ownerUser]; - if (ownerParticipant) + ownerAttendee = [currentEvent userAsAttendee: ownerUser]; + if (ownerAttendee) { if (count == 0) key = @"master"; else key = [[currentEvent recurrenceId] iCalFormattedDateTimeString]; - [partStats setObject: ownerParticipant forKey: key]; + [partStats setObject: ownerAttendee forKey: key]; } } diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index b20668814..9f0b810e5 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -41,7 +41,6 @@ #import #import -#import #import #import #import @@ -825,7 +824,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, p = [app pageWithName: pageName inContext: context]; [p setApt: (iCalEvent *) event]; - attendee = [event findParticipant: from]; + attendee = [event userAsAttendee: from]; [p setAttendee: attendee]; /* construct message */ @@ -897,7 +896,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, if (![event userIsOrganizer: ownerUser]) { organizer = [event organizer]; - attendee = [event findParticipant: ownerUser]; + attendee = [event userAsAttendee: ownerUser]; [event setAttendees: [NSArray arrayWithObject: attendee]]; [self sendIMIPReplyForEvent: event from: from to: organizer]; } @@ -981,7 +980,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, user = [SOGoUser userWithLogin: uid]; component = [self component: NO secure: NO]; - return [component findParticipant: user]; + return [component userAsAttendee: user]; } - (iCalPerson *) iCalPersonWithUID: (NSString *) uid @@ -1061,7 +1060,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, ownerUser = [SOGoUser userWithLogin: owner]; if ([component userIsOrganizer: ownerUser]) role = SOGoCalendarRole_Organizer; - else if ([component userIsParticipant: ownerUser]) + else if ([component userIsAttendee: ownerUser]) role = SOGoCalendarRole_Participant; else role = SOGoRole_None; @@ -1119,7 +1118,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, aclUser = [SOGoUser userWithLogin: uid]; if ([component userIsOrganizer: aclUser]) [roles addObject: SOGoCalendarRole_Organizer]; - else if ([component userIsParticipant: aclUser]) + else if ([component userIsAttendee: aclUser]) [roles addObject: SOGoCalendarRole_Participant]; accessRole = [container roleForComponentsWithAccessClass: [component symbolicAccessClass] diff --git a/SoObjects/Appointments/iCalEntityObject+SOGo.h b/SoObjects/Appointments/iCalEntityObject+SOGo.h index 6d52d9e5d..6d1545dcc 100644 --- a/SoObjects/Appointments/iCalEntityObject+SOGo.h +++ b/SoObjects/Appointments/iCalEntityObject+SOGo.h @@ -34,10 +34,10 @@ extern NSNumber *iCalDistantFutureNumber; + (void) initializeSOGoExtensions; -- (BOOL) userIsParticipant: (SOGoUser *) user; +- (BOOL) userIsAttendee: (SOGoUser *) user; - (BOOL) userIsOrganizer: (SOGoUser *) user; -- (iCalPerson *) userAsParticipant: (SOGoUser *) user; +- (iCalPerson *) userAsAttendee: (SOGoUser *) user; - (NSArray *) attendeeUIDs; - (BOOL) isStillRelevant; diff --git a/SoObjects/Appointments/iCalEntityObject+SOGo.m b/SoObjects/Appointments/iCalEntityObject+SOGo.m index fe5fac74b..b5d21f6a4 100644 --- a/SoObjects/Appointments/iCalEntityObject+SOGo.m +++ b/SoObjects/Appointments/iCalEntityObject+SOGo.m @@ -57,40 +57,40 @@ NSNumber *iCalDistantFutureNumber = nil; } } -- (BOOL) userIsParticipant: (SOGoUser *) user +- (BOOL) userIsAttendee: (SOGoUser *) user { - NSEnumerator *participants; - iCalPerson *currentParticipant; - BOOL isParticipant; + NSEnumerator *attendees; + iCalPerson *currentAttendee; + BOOL isAttendee; - isParticipant = NO; + isAttendee = NO; - participants = [[self participants] objectEnumerator]; - currentParticipant = [participants nextObject]; - while (!isParticipant - && currentParticipant) - if ([user hasEmail: [currentParticipant rfc822Email]]) - isParticipant = YES; + attendees = [[self attendees] objectEnumerator]; + currentAttendee = [attendees nextObject]; + while (!isAttendee + && currentAttendee) + if ([user hasEmail: [currentAttendee rfc822Email]]) + isAttendee = YES; else - currentParticipant = [participants nextObject]; + currentAttendee = [attendees nextObject]; - return isParticipant; + return isAttendee; } -- (iCalPerson *) userAsParticipant: (SOGoUser *) user +- (iCalPerson *) userAsAttendee: (SOGoUser *) user { - NSEnumerator *participants; - iCalPerson *currentParticipant, *userParticipant; + NSEnumerator *attendees; + iCalPerson *currentAttendee, *userAttendee; - userParticipant = nil; + userAttendee = nil; - participants = [[self participants] objectEnumerator]; - while (!userParticipant - && (currentParticipant = [participants nextObject])) - if ([user hasEmail: [currentParticipant rfc822Email]]) - userParticipant = currentParticipant; + attendees = [[self attendees] objectEnumerator]; + while (!userAttendee + && (currentAttendee = [attendees nextObject])) + if ([user hasEmail: [currentAttendee rfc822Email]]) + userAttendee = currentAttendee; - return userParticipant; + return userAttendee; } - (BOOL) userIsOrganizer: (SOGoUser *) user diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile index ac5e0dcaa..58c0970c6 100644 --- a/SoObjects/SOGo/GNUmakefile +++ b/SoObjects/SOGo/GNUmakefile @@ -34,7 +34,6 @@ SOGo_HEADER_FILES = \ SOGoDateFormatter.h \ SOGoPermissions.h \ SOGoStartupLogger.h \ - iCalEntityObject+Utilities.h \ NSArray+DAV.h \ NSArray+Utilities.h \ NSCalendarDate+SOGo.h \ @@ -103,7 +102,6 @@ SOGo_OBJC_FILES = \ SQLSource.m \ SOGoUserProfile.m \ SOGoSQLUserProfile.m \ - iCalEntityObject+Utilities.m \ NSArray+DAV.m \ NSArray+Utilities.m \ NSCalendarDate+SOGo.m \ diff --git a/SoObjects/SOGo/iCalEntityObject+Utilities.h b/SoObjects/SOGo/iCalEntityObject+Utilities.h deleted file mode 100644 index c60441b59..000000000 --- a/SoObjects/SOGo/iCalEntityObject+Utilities.h +++ /dev/null @@ -1,37 +0,0 @@ -/* iCalEntityObject+Utilities.h - this file is part of SOGo - * - * Copyright (C) 2007 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. - */ - -#ifndef ICALENTITYOBJECT_UTILITIES_H -#define ICALENTITYOBJECT_UTILITIES_H - -#import - -@class iCalPerson; -@class SOGoUser; - -@interface iCalEntityObject (SOGoAddition) - -- (iCalPerson *) findParticipant: (SOGoUser *) user; - -@end - -#endif /* ICALENTITYOBJECT_UTILITIES_H */ diff --git a/SoObjects/SOGo/iCalEntityObject+Utilities.m b/SoObjects/SOGo/iCalEntityObject+Utilities.m deleted file mode 100644 index a23594ed7..000000000 --- a/SoObjects/SOGo/iCalEntityObject+Utilities.m +++ /dev/null @@ -1,53 +0,0 @@ -/* iCalEntityObject+Utilities.m - this file is part of SOGo - * - * Copyright (C) 2007 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. - */ - -#import -#import - -#import - -#import "SOGoUser.h" - -#import "iCalEntityObject+Utilities.h" - -#warning we should move this into Appointments. - -@implementation iCalEntityObject (SOGoAddition) - -- (iCalPerson *) findParticipant: (SOGoUser *) user -{ - iCalPerson *participant, *currentParticipant; - NSEnumerator *participants; - - participant = nil; - participants = [[self attendees] objectEnumerator]; - currentParticipant = [participants nextObject]; - while (currentParticipant && !participant) - if ([user hasEmail: [currentParticipant rfc822Email]]) - participant = currentParticipant; - else - currentParticipant = [participants nextObject]; - - return participant; -} - -@end diff --git a/UI/MailPartViewers/UIxMailPartICalViewer.m b/UI/MailPartViewers/UIxMailPartICalViewer.m index b842246fc..80f8e62d6 100644 --- a/UI/MailPartViewers/UIxMailPartICalViewer.m +++ b/UI/MailPartViewers/UIxMailPartICalViewer.m @@ -44,7 +44,6 @@ #import #import #import -#import #import #import #import @@ -378,7 +377,7 @@ - (BOOL) isLoggedInUserAnAttendee { - return [[self authorativeEvent] userIsParticipant: [context activeUser]]; + return [[self authorativeEvent] userIsAttendee: [context activeUser]]; } - (NSString *) currentAttendeeClass @@ -451,7 +450,7 @@ { iCalPerson *currentUser; - currentUser = [[self authorativeEvent] findParticipant: [context activeUser]]; + currentUser = [[self authorativeEvent] userAsAttendee: [context activeUser]]; return currentUser; } @@ -463,7 +462,7 @@ should translate the email to an internal uid and then retrieve all emails addresses for matching the participant. - Note: -findParticipantWithEmail: does not parse the email! + Note: -findAttendeeWithEmail: does not parse the email! */ iCalEvent *e; iCalPerson *p; @@ -473,9 +472,9 @@ e = [self storedEvent]; if (e) { - p = [e findParticipantWithEmail: [self replySenderBaseEMail]]; + p = [e findAttendeeWithEmail: [self replySenderBaseEMail]]; if (!p) - p = [e findParticipantWithEmail:[self replySenderEMail]]; + p = [e findAttendeeWithEmail:[self replySenderEMail]]; } return p; @@ -496,7 +495,7 @@ address = [[mailObject fromEnvelopeAddresses] objectAtIndex: 0]; emailFrom = [address baseEMail]; - return [event findParticipantWithEmail: emailFrom]; + return [event findAttendeeWithEmail: emailFrom]; } - (BOOL) hasSenderStatusChanged From 2bf4b7cf8b0e369a2af84f2377188a5c82172f19 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 5 May 2010 14:40:53 +0000 Subject: [PATCH 5/7] Monotone-Parent: 1ccd34fd9ea99e675935d745db7e70d19716428a Monotone-Revision: c40151185171e3ba8a257569b8ab5ec86930d393 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-05-05T14:40:53 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 23 +++ UI/MailPartViewers/UIxMailPartICalActions.h | 2 + UI/MailPartViewers/UIxMailPartICalActions.m | 9 +- UI/MailPartViewers/product.plist | 5 + .../Localizable.strings | 5 +- UI/Scheduler/Czech.lproj/Localizable.strings | 5 +- UI/Scheduler/Dutch.lproj/Localizable.strings | 5 +- .../English.lproj/Localizable.strings | 9 +- UI/Scheduler/French.lproj/Localizable.strings | 11 +- UI/Scheduler/German.lproj/Localizable.strings | 5 +- .../Hungarian.lproj/Localizable.strings | 5 +- .../Italian.lproj/Localizable.strings | 5 +- .../Russian.lproj/Localizable.strings | 5 +- .../Spanish.lproj/Localizable.strings | 5 +- .../Swedish.lproj/Localizable.strings | 5 +- UI/Scheduler/UIxAppointmentEditor.m | 28 ++- UI/Scheduler/UIxComponentEditor.m | 175 ++++++++++++----- UI/Scheduler/Welsh.lproj/Localizable.strings | 1 + UI/Scheduler/product.plist | 10 + .../MailPartViewers/UIxMailPartICalViewer.wox | 11 +- .../SchedulerUI/UIxAttendeesEditor.wox | 86 +++++---- .../SchedulerUI/UIxComponentEditor.wox | 22 ++- UI/WebServerResources/MailerUI.css | 34 ++-- UI/WebServerResources/SchedulerUI.css | 15 +- UI/WebServerResources/SchedulerUI.js | 4 +- .../UIxAppointmentEditor.css | 69 ++++--- UI/WebServerResources/UIxAppointmentEditor.js | 36 ++-- UI/WebServerResources/UIxAttendeesEditor.css | 103 ++++++---- UI/WebServerResources/UIxAttendeesEditor.js | 176 +++++++++++++----- UI/WebServerResources/UIxComponentEditor.js | 12 +- UI/WebServerResources/accepted.png | Bin 510 -> 0 bytes UI/WebServerResources/accepted.selected.png | Bin 511 -> 0 bytes UI/WebServerResources/attendee-partstats.png | Bin 0 -> 2091 bytes UI/WebServerResources/attendee-roles.png | Bin 0 -> 1933 bytes UI/WebServerResources/declined.png | Bin 419 -> 0 bytes UI/WebServerResources/declined.selected.png | Bin 354 -> 0 bytes UI/WebServerResources/delegated.png | Bin 540 -> 0 bytes UI/WebServerResources/delegated.selected.png | Bin 452 -> 0 bytes UI/WebServerResources/generic.js | 2 +- UI/WebServerResources/iefixes.css | 16 ++ UI/WebServerResources/needs-action.png | Bin 506 -> 0 bytes .../needs-action.selected.png | Bin 428 -> 0 bytes 42 files changed, 625 insertions(+), 279 deletions(-) delete mode 100644 UI/WebServerResources/accepted.png delete mode 100644 UI/WebServerResources/accepted.selected.png create mode 100644 UI/WebServerResources/attendee-partstats.png create mode 100644 UI/WebServerResources/attendee-roles.png delete mode 100644 UI/WebServerResources/declined.png delete mode 100644 UI/WebServerResources/declined.selected.png delete mode 100644 UI/WebServerResources/delegated.png delete mode 100644 UI/WebServerResources/delegated.selected.png delete mode 100644 UI/WebServerResources/needs-action.png delete mode 100644 UI/WebServerResources/needs-action.selected.png diff --git a/ChangeLog b/ChangeLog index ec184ffb3..2c2b2c9a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,28 @@ 2010-05-05 Wolfgang Sourdeau + * UI/Scheduler/UIxComponentEditor.m (-ownerLogin): new accessor + the differenciate between the type of users in the list of + attendees. + + * UI/WebServerResources/UIxAttendeesEditor.js + (performSearchCallback): differenciate between the organizer user + and other attendees, as in Lightning. + + * UI/WebServerResources/UIxAppointmentEditor.js + (setupAttendeeNode): removed useless calls to $(). + + * UI/Scheduler/UIxComponentEditor.m + (-ownerIsAttendee:andClientObject:) + (delegateIsAttendee:andClientObject:): handle the case where the + user is found but has no RSVP or one with "FALSE" as value. + (-userHasRSVP): renamed from "userIsAttendee", since we don't + enable users without a RSVP set as "TRUE" to repond to + invitations. + (-currentAttendeeClasses): new method. + + * UI/MailPartViewers/UIxMailPartICalActions.m (-tentativeAction): + new action method for the "TENTATIVE" partstat. + * SoObjects/Appointments/iCalEntityObject+SOGo.m (-userIsParticipant:): renamed to "userIsAttendee:". We now request the list of attendees rather than the list of diff --git a/UI/MailPartViewers/UIxMailPartICalActions.h b/UI/MailPartViewers/UIxMailPartICalActions.h index 4b254d62b..b90b921e0 100644 --- a/UI/MailPartViewers/UIxMailPartICalActions.h +++ b/UI/MailPartViewers/UIxMailPartICalActions.h @@ -33,6 +33,8 @@ - (WOResponse *) acceptAction; - (WOResponse *) declineAction; +- (WOResponse *) tentativeAction; +- (WOResponse *) delegateAction; - (WOResponse *) addToCalendarAction; - (WOResponse *) deleteFromCalendarAction; diff --git a/UI/MailPartViewers/UIxMailPartICalActions.m b/UI/MailPartViewers/UIxMailPartICalActions.m index c3a28625a..3805dc64c 100644 --- a/UI/MailPartViewers/UIxMailPartICalActions.m +++ b/UI/MailPartViewers/UIxMailPartICalActions.m @@ -48,7 +48,6 @@ #import #import #import -#import #import #import "UIxMailPartICalActions.h" @@ -261,6 +260,12 @@ withDelegate: nil]; } +- (WOResponse *) tentativeAction +{ + return [self _changePartStatusAction: @"TENTATIVE" + withDelegate: nil]; +} + - (WOResponse *) delegateAction { // BOOL receiveUpdates; @@ -369,7 +374,7 @@ address = [[mailObject fromEnvelopeAddresses] objectAtIndex: 0]; emailFrom = [address baseEMail]; - return [event findParticipantWithEmail: emailFrom]; + return [event findAttendeeWithEmail: emailFrom]; } - (BOOL) _updateParticipantStatusInEvent: (iCalEvent *) calendarEvent diff --git a/UI/MailPartViewers/product.plist b/UI/MailPartViewers/product.plist index f5c59c51a..dd749362d 100644 --- a/UI/MailPartViewers/product.plist +++ b/UI/MailPartViewers/product.plist @@ -28,6 +28,11 @@ actionClass = "UIxMailPartICalActions"; actionName = "decline"; }; + tentative = { + protectedBy = "View"; + actionClass = "UIxMailPartICalActions"; + actionName = "tentative"; + }; delegate = { protectedBy = "View"; actionClass = "UIxMailPartICalActions"; diff --git a/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings b/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings index d225c7b09..0a1611a13 100644 --- a/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings +++ b/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings @@ -460,8 +460,9 @@ validate_endbeforestart = "A data que você informou ocorre antes da data ini = "Você tem certeza que quer apagar o calendário \"%{0}\"?"; /* Legend */ -"Required participant" = "Participante Requerido"; -"Optional participant" = "Participante Opcional"; +"Participant" = "Participante"; +"Optional Participant" = "Participante Opcional"; +"Non Participant" = "Não Participante"; "Chair" = "Cadeira"; "Needs action" = "Ações necessárias"; diff --git a/UI/Scheduler/Czech.lproj/Localizable.strings b/UI/Scheduler/Czech.lproj/Localizable.strings index d336dac7a..0db47391d 100644 --- a/UI/Scheduler/Czech.lproj/Localizable.strings +++ b/UI/Scheduler/Czech.lproj/Localizable.strings @@ -460,8 +460,9 @@ validate_endbeforestart = "Zadané datum konce je před začátkem události. = "Opravdu chcete smazat kalendář \"%{0}\"?"; /* Legend */ -"Required participant" = "Vyžadovaný účastník"; -"Optional participant" = "Nepovinný účastník"; +"Participant" = "Účastník"; +"Optional Participant" = "Nepovinný účastník"; +"Non Participant" = "Non Participant"; "Chair" = "Židle"; "Needs action" = "Vyžaduje akci"; diff --git a/UI/Scheduler/Dutch.lproj/Localizable.strings b/UI/Scheduler/Dutch.lproj/Localizable.strings index 8f8bc3940..c12a962d0 100644 --- a/UI/Scheduler/Dutch.lproj/Localizable.strings +++ b/UI/Scheduler/Dutch.lproj/Localizable.strings @@ -460,8 +460,9 @@ validate_endbeforestart = "Het begin vindt plaats vóór het einde."; = "Weet u zeker dat u de agenda \"%{0}\" wilt verwijderen?"; /* Legend */ -"Required participant" = "Vereiste deelnemer"; -"Optional participant" = "Gewenste deelnemer"; +"Participant" = "Deelnemer"; +"Optional Participant" = "Gewenste deelnemer"; +"Non Participant" = "Non Participant"; "Chair" = "Voorzitter"; "Needs action" = "Actie vereist"; diff --git a/UI/Scheduler/English.lproj/Localizable.strings b/UI/Scheduler/English.lproj/Localizable.strings index 9c27aab21..75a35cc04 100644 --- a/UI/Scheduler/English.lproj/Localizable.strings +++ b/UI/Scheduler/English.lproj/Localizable.strings @@ -246,10 +246,10 @@ /* Appointments (participation state) */ -"partStat_NEEDS-ACTION" = "Needs action"; +"partStat_NEEDS-ACTION" = "I will confirm later"; "partStat_ACCEPTED" = "I will attend"; "partStat_DECLINED" = "I will not attend"; -"partStat_TENTATIVE" = "I will confirm later"; +"partStat_TENTATIVE" = "I might attend"; "partStat_DELEGATED" = "I delegate"; "partStat_OTHER" = "Other"; @@ -460,8 +460,9 @@ validate_endbeforestart = "The end date that you entered occurs before the st = "Are you sure you want to delete the calendar \"%{0}\"?"; /* Legend */ -"Required participant" = "Required participant"; -"Optional participant" = "Optional participant"; +"Participant" = "Participant"; +"Optional Participant" = "Optional Participant"; +"Non Participant" = "Non Participant"; "Chair" = "Chair"; "Needs action" = "Needs action"; diff --git a/UI/Scheduler/French.lproj/Localizable.strings b/UI/Scheduler/French.lproj/Localizable.strings index 9cdc2c7ec..1d44ae291 100644 --- a/UI/Scheduler/French.lproj/Localizable.strings +++ b/UI/Scheduler/French.lproj/Localizable.strings @@ -246,10 +246,10 @@ /* Appointments (participation state) */ -"partStat_NEEDS-ACTION" = "Décision attendue"; +"partStat_NEEDS-ACTION" = "Je confirmerai plus tard"; "partStat_ACCEPTED" = "Je participerai"; "partStat_DECLINED" = "Je ne participerai pas"; -"partStat_TENTATIVE" = "Je confirmerai plus tard"; +"partStat_TENTATIVE" = "Je participerai peut-être"; "partStat_DELEGATED" = "Je délègue"; "partStat_OTHER" = "???"; @@ -460,9 +460,10 @@ validate_endbeforestart = "La date de fin est avant la date de début."; = "Voulez-vous vraiment supprimer l'agenda «%{0}»?"; /* Legend */ -"Required participant" = "Participant obligatoire"; -"Optional participant" = "Participant facultatif"; -"Chair" = "Chaise"; +"Participant" = "Invité"; +"Optional Participant" = "Invité optionnel"; +"Non Participant" = "Non-invité"; +"Chair" = "Président"; "Needs action" = "En attente"; "Accepted" = "Accepté"; diff --git a/UI/Scheduler/German.lproj/Localizable.strings b/UI/Scheduler/German.lproj/Localizable.strings index ae4474590..f96487d1a 100644 --- a/UI/Scheduler/German.lproj/Localizable.strings +++ b/UI/Scheduler/German.lproj/Localizable.strings @@ -460,8 +460,9 @@ validate_endbeforestart = "Ihr Beginn ist nach dem Ende"; = "Wollen Sie diesen Kalender wirklich löschen \"%{0}\"?"; /* Legend */ -"Required participant" = "notwendiger Teilnehmer"; -"Optional participant" = "optionaler Teilnehmer"; +"Participant" = "Teilnehmer"; +"Optional Participant" = "optionaler Teilnehmer"; +"Non Participant" = "Non Participant"; "Chair" = "Vorsitz"; "Needs action" = "Benötigt Eingriff"; diff --git a/UI/Scheduler/Hungarian.lproj/Localizable.strings b/UI/Scheduler/Hungarian.lproj/Localizable.strings index 0d9bc3897..09823cbef 100644 --- a/UI/Scheduler/Hungarian.lproj/Localizable.strings +++ b/UI/Scheduler/Hungarian.lproj/Localizable.strings @@ -460,8 +460,9 @@ validate_endbeforestart = "A megadott befejező dátum korábbi, mint a kezd = "Biztosan törli ezt a naptárat: \"%{0}\"?"; /* Legend */ -"Required participant" = "Kötelező résztvevő"; -"Optional participant" = "Nem kötelező résztvevő"; +"Participant" = "Kötelező résztvevő"; +"Optional Participant" = "Nem kötelező résztvevő"; +"Non Participant" = "Non Participant"; "Chair" = "Szék"; "Needs action" = "Foglalkozni kell vele"; diff --git a/UI/Scheduler/Italian.lproj/Localizable.strings b/UI/Scheduler/Italian.lproj/Localizable.strings index b965bf248..6b5830275 100644 --- a/UI/Scheduler/Italian.lproj/Localizable.strings +++ b/UI/Scheduler/Italian.lproj/Localizable.strings @@ -460,8 +460,9 @@ validate_endbeforestart = "La data finale specificata è precedente alla data = "Sei sicuro di voler cancellare il calendario \"%{0}\"?"; /* Legend */ -"Required participant" = "Richiede partecipanti"; -"Optional participant" = "Partecipanti opzionali"; +"Participant" = "Partecipanti"; +"Optional Participant" = "Partecipanti opzionali"; +"Non Participant" = "Non Partecipanti"; "Chair" = "Sedia"; "Needs action" = "Richiede un'azione"; diff --git a/UI/Scheduler/Russian.lproj/Localizable.strings b/UI/Scheduler/Russian.lproj/Localizable.strings index f90977000..370af8a7c 100644 --- a/UI/Scheduler/Russian.lproj/Localizable.strings +++ b/UI/Scheduler/Russian.lproj/Localizable.strings @@ -460,8 +460,9 @@ validate_endbeforestart = "The end date that you entered occurs before the st = "Вы уверены что хотите удалить календарь \"%{0}\"?"; /* Legend */ -"Required participant" = "Required participant"; -"Optional participant" = "Optional participant"; +"Participant" = "Participant"; +"Optional Participant" = "Optional Participant"; +"Non Participant" = "Non Participant"; "Chair" = "Chair"; "Needs action" = "Needs action"; diff --git a/UI/Scheduler/Spanish.lproj/Localizable.strings b/UI/Scheduler/Spanish.lproj/Localizable.strings index 38245e2e0..a83166f5d 100644 --- a/UI/Scheduler/Spanish.lproj/Localizable.strings +++ b/UI/Scheduler/Spanish.lproj/Localizable.strings @@ -460,8 +460,9 @@ validate_endbeforestart = "Su fecha/hora de comienzo es posterio a la de fina = "¿Está seguro/a que desea borrar el calendario \"%{0}\"?"; /* Legend */ -"Required participant" = "Asistente obligatorio"; -"Optional participant" = "Asistentes opcionales"; +"Participant" = "Asistente"; +"Optional Participant" = "Asistentes opcionales"; +"Non Participant" = "Non Particpant"; "Chair" = "Presidente"; "Needs action" = "Requiere intervención"; diff --git a/UI/Scheduler/Swedish.lproj/Localizable.strings b/UI/Scheduler/Swedish.lproj/Localizable.strings index 978b39809..4258a297d 100644 --- a/UI/Scheduler/Swedish.lproj/Localizable.strings +++ b/UI/Scheduler/Swedish.lproj/Localizable.strings @@ -460,8 +460,9 @@ validate_endbeforestart = "Angivet slutdatumet inträffar före angivet start = "Är du säker på att du vill ta bort kalendern \"%{0}\"?"; /* Legend */ -"Required participant" = "Deltagande krävs"; -"Optional participant" = "Deltagande valfritt"; +"Participant" = "Deltagande krävs"; +"Optional Participant" = "Deltagande valfritt"; +"Non Participant" = "Non Participant"; "Chair" = "Stol"; "Needs action" = "Behöver åtgärd"; diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index 8873dd55c..e13d76644 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -522,22 +522,32 @@ [event setTransparency: (isTransparent? @"TRANSPARENT" : @"OPAQUE")]; } -// TODO: add tentatively +- (id) _statusChangeAction: (NSString *) newStatus +{ + [[self clientObject] changeParticipationStatus: newStatus + withDelegate: nil]; + + return [self responseWith204]; +} - (id) acceptAction { - [[self clientObject] changeParticipationStatus: @"ACCEPTED" - withDelegate: nil]; - - return self; + return [self _statusChangeAction: @"ACCEPTED"]; } - (id) declineAction { - [[self clientObject] changeParticipationStatus: @"DECLINED" - withDelegate: nil]; + return [self _statusChangeAction: @"DECLINED"]; +} - return self; +- (id) needsActionAction +{ + return [self _statusChangeAction: @"NEEDS-ACTION"]; +} + +- (id) tentativeAction +{ + return [self _statusChangeAction: @"TENTATIVE"]; } - (id) delegateAction @@ -584,7 +594,7 @@ reason: @"missing 'to' parameter"]; if (!response) - response = [self responseWithStatus: 200]; + response = [self responseWith204]; return response; } diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 63bee5845..25348ead5 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -54,7 +54,6 @@ #import #import #import -#import #import #import #import @@ -268,6 +267,8 @@ iRANGE(2); [currentAttendeeData setObject: [[currentAttendee partStat] lowercaseString] forKey: @"partstat"]; + [currentAttendeeData setObject: [[currentAttendee role] lowercaseString] + forKey: @"role"]; if ([[currentAttendee delegatedTo] length]) [currentAttendeeData setObject: [[currentAttendee delegatedTo] rfc822Email] @@ -587,7 +588,7 @@ iRANGE(2); um = [SOGoUserManager sharedUserManager]; owner = [componentCalendar ownerInContext: context]; ownerEmail = [um getEmailForUID: owner]; - ASSIGN (ownerAsAttendee, [component findParticipantWithEmail: (id)ownerEmail]); + ASSIGN (ownerAsAttendee, [component findAttendeeWithEmail: (id)ownerEmail]); } } // /* cycles */ @@ -990,14 +991,26 @@ iRANGE(2); { NSString *word; - if ([item intValue] == iCalPersonPartStatAccepted) - word = @"ACCEPTED"; - else if ([item intValue] == iCalPersonPartStatDeclined) - word = @"DECLINED"; - else if ([item intValue] == iCalPersonPartStatDelegated) - word = @"DELEGATED"; - else - word = @"UNKNOWN"; + switch ([item intValue]) + { + case iCalPersonPartStatAccepted: + word = @"ACCEPTED"; + break; + case iCalPersonPartStatDeclined: + word = @"DECLINED"; + break; + case iCalPersonPartStatNeedsAction: + word = @"NEEDS-ACTION"; + break; + case iCalPersonPartStatTentative: + word = @"TENTATIVE"; + break; + case iCalPersonPartStatDelegated: + word = @"DELEGATED"; + break; + default: + word = @"UNKNOWN"; + } return [self labelForKey: [NSString stringWithFormat: @"partStat_%@", word]]; } @@ -1005,8 +1018,10 @@ iRANGE(2); - (NSArray *) replyList { return [NSArray arrayWithObjects: - [NSNumber numberWithInt: iCalPersonPartStatAccepted], + [NSNumber numberWithInt: iCalPersonPartStatAccepted], [NSNumber numberWithInt: iCalPersonPartStatDeclined], + [NSNumber numberWithInt: iCalPersonPartStatNeedsAction], + [NSNumber numberWithInt: iCalPersonPartStatTentative], [NSNumber numberWithInt: iCalPersonPartStatDelegated], nil]; } @@ -1508,7 +1523,7 @@ RANGE(2); unsigned int count, max; NSString *currentEmail; iCalPerson *currentAttendee; - NSString *json; + NSString *json, *role, *partstat; NSDictionary *attendeesData; NSArray *attendees; NSDictionary *currentData; @@ -1529,17 +1544,33 @@ RANGE(2); { currentData = [attendees objectAtIndex: count]; currentEmail = [currentData objectForKey: @"email"]; - currentAttendee = [component findParticipantWithEmail: currentEmail]; + role = [[currentData objectForKey: @"role"] uppercaseString]; + if (!role) + role = @"REQ-PARTICIPANT"; + if ([role isEqualToString: @"NON-PARTICIPANT"]) + partstat = @""; + else + { + partstat = [[currentData objectForKey: @"partstat"] + uppercaseString]; + if (!partstat) + partstat = @"NEEDS-ACTION"; + } + currentAttendee = [component findAttendeeWithEmail: currentEmail]; if (!currentAttendee) { currentAttendee = [iCalPerson elementWithTag: @"attendee"]; [currentAttendee setCn: [currentData objectForKey: @"name"]]; [currentAttendee setEmail: currentEmail]; - [currentAttendee setRole: @"REQ-PARTICIPANT"]; - [currentAttendee setRsvp: @"TRUE"]; - [currentAttendee - setParticipationStatus: iCalPersonPartStatNeedsAction]; + // [currentAttendee + // setParticipationStatus: iCalPersonPartStatNeedsAction]; } + [currentAttendee + setRsvp: ([role isEqualToString: @"NON-PARTICIPANT"] + ? @"FALSE" + : @"TRUE")]; + [currentAttendee setRole: role]; + [currentAttendee setPartStat: partstat]; [newAttendees addObject: currentAttendee]; } [component setAttendees: newAttendees]; @@ -1965,8 +1996,7 @@ RANGE(2); isOrganizer = ![ownerUser hasEmail: [[component organizer] sentBy]]; if ([componentCalendar isKindOfClass: [SOGoWebAppointmentFolder class]] - || ([[component attendees] count] - && [component userIsParticipant: ownerUser] + || ([component userIsAttendee: ownerUser] && !isOrganizer // Lightning does not manage participation status within tasks, // so we also ignore the participation status of tasks in the @@ -1991,14 +2021,12 @@ RANGE(2); { SoSecurityManager *sm; NSString *toolbarFilename, *adminToolbar; - SOGoUser *currentUser; if ([clientObject isKindOfClass: [SOGoAppointmentObject class]]) adminToolbar = @"SOGoAppointmentObject.toolbar"; else adminToolbar = @"SOGoTaskObject.toolbar"; - currentUser = [context activeUser]; sm = [SoSecurityManager sharedSecurityManager]; if (![sm validatePermission: SOGoCalendarPerm_ModifyComponent @@ -2035,36 +2063,45 @@ RANGE(2); - (int) ownerIsAttendee: (SOGoUser *) ownerUser - andClientObject: (SOGoContentObject - *) clientObject + andClientObject: (SOGoContentObject + *) clientObject { BOOL isOrganizer; - int rc = 0; + iCalPerson *ownerAttendee; + int rc; + + rc = 0; isOrganizer = [component userIsOrganizer: ownerUser]; if (isOrganizer) isOrganizer = ![ownerUser hasEmail: [[component organizer] sentBy]]; - if ([[component attendees] count] - && [component userIsParticipant: ownerUser] - && !isOrganizer - && ![[component tag] isEqualToString: @"VTODO"]) - rc = 1; + if (!isOrganizer && ![[component tag] isEqualToString: @"VTODO"]) + { + ownerAttendee = [component userAsAttendee: ownerUser]; + if (ownerAttendee) + { + if ([[ownerAttendee rsvp] isEqualToString: @"true"]) + rc = 1; + else + rc = 2; + } + } return rc; } - (int) delegateIsAttendee: (SOGoUser *) ownerUser - andClientObject: (SOGoContentObject - *) clientObject + andClientObject: (SOGoContentObject + *) clientObject { SoSecurityManager *sm; - SOGoUser *currentUser; - int rc = 0; + iCalPerson *ownerAttendee; + int rc; + + rc = 0; - currentUser = [context activeUser]; sm = [SoSecurityManager sharedSecurityManager]; - if (![sm validatePermission: SOGoCalendarPerm_ModifyComponent onObject: clientObject inContext: context]) @@ -2072,11 +2109,15 @@ RANGE(2); andClientObject: clientObject]; else if (![sm validatePermission: SOGoCalendarPerm_RespondToComponent onObject: clientObject - inContext: context] - && [[component attendees] count] - && [component userIsParticipant: ownerUser] - && ![component userIsOrganizer: ownerUser]) - rc = 1; + inContext: context]) + { + ownerAttendee = [component userAsAttendee: ownerUser]; + if ([[ownerAttendee rsvp] isEqualToString: @"true"] + && ![component userIsOrganizer: ownerUser]) + rc = 1; + else + rc = 2; + } else rc = 2; // not invited, just RO @@ -2090,9 +2131,8 @@ RANGE(2); int rc; clientObject = [self clientObject]; - ownerUser = [SOGoUser userWithLogin: [clientObject ownerInContext: context] - roles: nil]; - + ownerUser + = [SOGoUser userWithLogin: [clientObject ownerInContext: context]]; if ([componentCalendar isKindOfClass: [SOGoWebAppointmentFolder class]]) rc = 2; else @@ -2113,9 +2153,54 @@ RANGE(2); return [self getEventRWType] != 0; } -- (BOOL) userIsAttendee +- (BOOL) userHasRSVP { - return [self getEventRWType] == 1; + return ([self getEventRWType] == 1); +} + +- (NSString *) currentAttendeeClasses +{ + NSMutableArray *classes; + iCalPerson *ownerAttendee; + SOGoUser *ownerUser; + NSString *role, *partStat; + SOGoCalendarComponent *co; + + classes = [NSMutableArray arrayWithCapacity: 5]; + + /* rsvp class */ + if (![[attendee rsvp] isEqualToString: @"true"]) + [classes addObject: @"not-rsvp"]; + + /* partstat class */ + partStat = [[attendee partStat] lowercaseString]; + if (![partStat length]) + partStat = @"no-partstat"; + [classes addObject: partStat]; + + /* role class */ + role = [[attendee role] lowercaseString]; + if (![partStat length]) + role = @"no-role"; + [classes addObject: role]; + + /* attendee class */ + if ([[attendee delegatedFrom] length] > 0) + [classes addObject: @"delegate"]; + + /* current attendee class */ + co = [self clientObject]; + ownerUser = [SOGoUser userWithLogin: [co ownerInContext: context]]; + ownerAttendee = [component userAsAttendee: ownerUser]; + if (attendee == ownerAttendee) + [classes addObject: @"attendeeUser"]; + + return [classes componentsJoinedByString: @" "]; +} + +- (NSString *) ownerLogin +{ + return [[self clientObject] ownerInContext: context]; } @end diff --git a/UI/Scheduler/Welsh.lproj/Localizable.strings b/UI/Scheduler/Welsh.lproj/Localizable.strings index ddfed3d86..d91595117 100644 --- a/UI/Scheduler/Welsh.lproj/Localizable.strings +++ b/UI/Scheduler/Welsh.lproj/Localizable.strings @@ -462,6 +462,7 @@ validate_endbeforestart = "Mae'r dyddiad gorffen sydd wedi'i roi yn digwydd c /* Legend */ "Required participant" = "Cyfranogwr gofynnol"; "Optional participant" = "Cyfranogwr opsiynol"; +"Non Participant" = "Non Participant"; "Chair" = "Cadair"; "Needs action" = "Angen gweithred"; diff --git a/UI/Scheduler/product.plist b/UI/Scheduler/product.plist index e3a88736e..63238ad16 100644 --- a/UI/Scheduler/product.plist +++ b/UI/Scheduler/product.plist @@ -235,6 +235,16 @@ pageName = "UIxAppointmentEditor"; actionName = "delegate"; }; + tentative = { + protectedBy = "RespondToComponent"; + pageName = "UIxAppointmentEditor"; + actionName = "tentative"; + }; + needsaction = { + protectedBy = "RespondToComponent"; + pageName = "UIxAppointmentEditor"; + actionName = "needsAction"; + }; adjust = { protectedBy = "ModifyComponent"; actionClass = "UIxAppointmentActions"; diff --git a/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox b/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox index ec747f7ab..b0e61dc8e 100644 --- a/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox +++ b/UI/Templates/MailPartViewers/UIxMailPartICalViewer.wox @@ -45,6 +45,7 @@

+ @@ -56,6 +57,11 @@ + + + + @@ -76,6 +82,7 @@ + @@ -223,7 +230,9 @@ : - +

( , )
diff --git a/UI/Templates/SchedulerUI/UIxAttendeesEditor.wox b/UI/Templates/SchedulerUI/UIxAttendeesEditor.wox index 90a02d789..f3f35da26 100644 --- a/UI/Templates/SchedulerUI/UIxAttendeesEditor.wox +++ b/UI/Templates/SchedulerUI/UIxAttendeesEditor.wox @@ -22,29 +22,23 @@
- + > + + checked="1" id="onlyOfficeHours" />
- +
+ + +
- - - -
+
@@ -52,25 +46,28 @@
- - - - -
+ +
+
+ +
- - - - -
+ + + + + @@ -78,27 +75,38 @@
-
    +
      +
    • +
    • +
    • +
    • +
    + +
    • - - + +
-

+ > + >
diff --git a/UI/Templates/SchedulerUI/UIxComponentEditor.wox b/UI/Templates/SchedulerUI/UIxComponentEditor.wox index 8fd1238b5..bb13b41a2 100644 --- a/UI/Templates/SchedulerUI/UIxComponentEditor.wox +++ b/UI/Templates/SchedulerUI/UIxComponentEditor.wox @@ -19,7 +19,8 @@ var activeComponent = '/'; var readOnly = truefalse; - var attendees = ; + var attendees = ; + var ownerLogin = ''; @@ -203,11 +204,9 @@ - +