2006-06-15 21:34:10 +02:00
|
|
|
/*
|
2011-01-14 03:54:33 +01:00
|
|
|
Copyright (C) 2007-2011 Inverse inc.
|
2006-06-15 21:34:10 +02:00
|
|
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
|
|
|
|
|
|
|
This file is part of OpenGroupware.org.
|
|
|
|
|
2009-04-30 23:17:55 +02:00
|
|
|
SOGo is free software; you can redistribute it and/or modify it under
|
2006-06-15 21:34:10 +02:00
|
|
|
the terms of the GNU Lesser General Public License as published by the
|
|
|
|
Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
later version.
|
|
|
|
|
2009-04-30 23:17:55 +02:00
|
|
|
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
2006-06-15 21:34:10 +02:00
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
|
|
License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with OGo; see the file COPYING. If not, write to the
|
|
|
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2008-07-05 00:25:27 +02:00
|
|
|
#import <Foundation/NSCalendarDate.h>
|
2008-07-04 18:06:09 +02:00
|
|
|
#import <Foundation/NSDictionary.h>
|
|
|
|
#import <Foundation/NSEnumerator.h>
|
2010-03-12 21:24:59 +01:00
|
|
|
#import <Foundation/NSTimeZone.h>
|
2010-04-21 16:35:58 +02:00
|
|
|
#import <Foundation/NSValue.h>
|
2007-09-06 22:51:59 +02:00
|
|
|
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <NGObjWeb/NSException+HTTP.h>
|
2007-11-18 11:16:25 +01:00
|
|
|
#import <NGObjWeb/WOContext+SoObjects.h>
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <NGExtensions/NSNull+misc.h>
|
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
2006-10-11 20:58:16 +02:00
|
|
|
#import <NGCards/iCalCalendar.h>
|
2010-08-11 16:52:11 +02:00
|
|
|
#import <NGCards/iCalDateTime.h>
|
2006-10-11 20:58:16 +02:00
|
|
|
#import <NGCards/iCalEvent.h>
|
2006-12-14 22:20:13 +01:00
|
|
|
#import <NGCards/iCalEventChanges.h>
|
|
|
|
#import <NGCards/iCalPerson.h>
|
2009-08-10 22:59:49 +02:00
|
|
|
#import <NGCards/NSCalendarDate+NGCards.h>
|
2008-07-05 00:25:27 +02:00
|
|
|
#import <SaxObjC/XMLNamespaces.h>
|
2006-10-31 19:54:56 +01:00
|
|
|
|
2009-09-10 20:31:20 +02:00
|
|
|
#import <SOPE/NGCards/NSString+NGCards.h>
|
|
|
|
|
2010-02-02 22:42:17 +01:00
|
|
|
#import <SOGo/SOGoUserManager.h>
|
|
|
|
#import <SOGo/NSArray+Utilities.h>
|
|
|
|
#import <SOGo/NSObject+DAV.h>
|
|
|
|
#import <SOGo/SOGoObject.h>
|
|
|
|
#import <SOGo/SOGoPermissions.h>
|
|
|
|
#import <SOGo/SOGoGroup.h>
|
|
|
|
#import <SOGo/SOGoUser.h>
|
2010-04-20 21:45:16 +02:00
|
|
|
#import <SOGo/SOGoDomainDefaults.h>
|
2010-02-02 22:42:17 +01:00
|
|
|
#import <SOGo/SOGoWebDAVValue.h>
|
|
|
|
#import <SOGo/WORequest+SOGo.h>
|
2006-10-31 19:54:56 +01:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
#import "iCalEventChanges+SOGo.h"
|
|
|
|
#import "iCalEntityObject+SOGo.h"
|
|
|
|
#import "iCalPerson+SOGo.h"
|
2008-07-17 23:12:43 +02:00
|
|
|
#import "NSArray+Appointments.h"
|
|
|
|
#import "SOGoAppointmentFolder.h"
|
|
|
|
#import "SOGoAppointmentOccurence.h"
|
2008-11-22 08:20:22 +01:00
|
|
|
#import "SOGoCalendarComponent.h"
|
2007-09-15 00:01:02 +02:00
|
|
|
|
2007-08-07 20:37:31 +02:00
|
|
|
#import "SOGoAppointmentObject.h"
|
2006-06-15 21:34:10 +02:00
|
|
|
|
|
|
|
@implementation SOGoAppointmentObject
|
|
|
|
|
2007-02-15 21:59:02 +01:00
|
|
|
- (NSString *) componentTag
|
2006-11-07 19:15:42 +01:00
|
|
|
{
|
2007-02-15 21:59:02 +01:00
|
|
|
return @"vevent";
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2008-07-17 23:12:43 +02:00
|
|
|
- (SOGoComponentOccurence *) occurence: (iCalRepeatableEntityObject *) occ
|
|
|
|
{
|
2009-03-16 22:08:19 +01:00
|
|
|
NSArray *allEvents;
|
|
|
|
|
|
|
|
allEvents = [[occ parent] events];
|
|
|
|
|
|
|
|
return [SOGoAppointmentOccurence
|
|
|
|
occurenceWithComponent: occ
|
|
|
|
withMasterComponent: [allEvents objectAtIndex: 0]
|
|
|
|
inContainer: self];
|
2008-07-17 23:12:43 +02:00
|
|
|
}
|
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
/**
|
|
|
|
* Return a new exception in a the recurrent event.
|
|
|
|
* @param theRecurrenceID the ID of the occurence.
|
|
|
|
* @return a new occurence.
|
|
|
|
*/
|
|
|
|
- (iCalRepeatableEntityObject *) newOccurenceWithID: (NSString *) theRecurrenceID
|
2008-07-17 23:12:43 +02:00
|
|
|
{
|
2010-03-12 21:24:59 +01:00
|
|
|
iCalEvent *newOccurence, *master;
|
|
|
|
NSCalendarDate *date, *firstDate;
|
2008-12-30 17:57:46 +01:00
|
|
|
unsigned int interval, nbrDays;
|
2010-03-12 21:24:59 +01:00
|
|
|
SOGoUserDefaults *ud;
|
|
|
|
NSTimeZone *timeZone;
|
|
|
|
|
|
|
|
ud = [[SOGoUser userWithLogin: owner] userDefaults];
|
|
|
|
timeZone = [ud timeZone];
|
2008-07-17 23:12:43 +02:00
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
newOccurence = (iCalEvent *) [super newOccurenceWithID: theRecurrenceID];
|
2008-07-17 23:12:43 +02:00
|
|
|
date = [newOccurence recurrenceId];
|
2010-03-12 21:24:59 +01:00
|
|
|
|
|
|
|
master = [self component: NO secure: NO];
|
|
|
|
firstDate = [master startDate];
|
|
|
|
|
|
|
|
interval = [[master endDate]
|
|
|
|
timeIntervalSinceDate: firstDate];
|
2008-12-30 17:57:46 +01:00
|
|
|
if ([newOccurence isAllDay])
|
|
|
|
{
|
|
|
|
nbrDays = ((float) abs (interval) / 86400) + 1;
|
|
|
|
[newOccurence setAllDayWithStartDate: date
|
|
|
|
duration: nbrDays];
|
|
|
|
}
|
|
|
|
else
|
2010-03-12 21:24:59 +01:00
|
|
|
{
|
|
|
|
[newOccurence setStartDate: date];
|
|
|
|
[newOccurence setEndDate: [date addYear: 0
|
|
|
|
month: 0
|
|
|
|
day: 0
|
|
|
|
hour: 0
|
|
|
|
minute: 0
|
|
|
|
second: interval]];
|
|
|
|
}
|
2008-07-17 23:12:43 +02:00
|
|
|
|
|
|
|
return newOccurence;
|
|
|
|
}
|
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
- (SOGoAppointmentObject *) _lookupEvent: (NSString *) eventUID
|
|
|
|
forUID: (NSString *) uid
|
2007-01-31 21:15:28 +01:00
|
|
|
{
|
2007-11-18 11:16:25 +01:00
|
|
|
SOGoAppointmentFolder *folder;
|
|
|
|
SOGoAppointmentObject *object;
|
2009-03-23 22:19:55 +01:00
|
|
|
NSArray *folders;
|
|
|
|
NSEnumerator *e;
|
2007-11-18 11:16:25 +01:00
|
|
|
NSString *possibleName;
|
|
|
|
|
2009-03-23 22:19:55 +01:00
|
|
|
object = nil;
|
|
|
|
folders = [container lookupCalendarFoldersForUID: uid];
|
|
|
|
e = [folders objectEnumerator];
|
|
|
|
while ( object == nil && (folder = [e nextObject]) )
|
2007-02-15 21:59:02 +01:00
|
|
|
{
|
2009-03-23 22:19:55 +01:00
|
|
|
object = [folder lookupName: nameInContainer
|
|
|
|
inContext: context
|
|
|
|
acquire: NO];
|
|
|
|
if ([object isKindOfClass: [NSException class]])
|
2007-11-18 11:16:25 +01:00
|
|
|
{
|
2009-03-23 22:19:55 +01:00
|
|
|
possibleName = [folder resourceNameForEventUID: eventUID];
|
|
|
|
if (possibleName)
|
|
|
|
{
|
|
|
|
object = [folder lookupName: possibleName
|
|
|
|
inContext: context acquire: NO];
|
|
|
|
if ([object isKindOfClass: [NSException class]])
|
|
|
|
object = nil;
|
|
|
|
}
|
|
|
|
else
|
2007-11-18 11:16:25 +01:00
|
|
|
object = nil;
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
2007-02-15 21:59:02 +01:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
if (!object)
|
2008-07-14 18:47:10 +02:00
|
|
|
{
|
2009-05-06 23:57:21 +02:00
|
|
|
// Create the event in the user's personal calendar.
|
2010-07-15 19:05:29 +02:00
|
|
|
folder = [[SOGoUser userWithLogin: uid]
|
|
|
|
personalCalendarFolderInContext: context];
|
2008-07-14 18:47:10 +02:00
|
|
|
object = [SOGoAppointmentObject objectWithName: nameInContainer
|
|
|
|
inContainer: folder];
|
|
|
|
[object setIsNew: YES];
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
return object;
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2008-11-26 13:20:26 +01:00
|
|
|
- (void) _addOrUpdateEvent: (iCalEvent *) theEvent
|
|
|
|
forUID: (NSString *) theUID
|
|
|
|
owner: (NSString *) theOwner
|
2007-08-24 00:11:19 +02:00
|
|
|
{
|
2008-11-26 13:20:26 +01:00
|
|
|
if (![theUID isEqualToString: theOwner])
|
2007-11-08 00:35:26 +01:00
|
|
|
{
|
2009-06-02 23:51:17 +02:00
|
|
|
SOGoAppointmentObject *attendeeObject;
|
2008-11-26 13:20:26 +01:00
|
|
|
NSString *iCalString;
|
|
|
|
|
2009-06-02 23:51:17 +02:00
|
|
|
attendeeObject = [self _lookupEvent: [theEvent uid] forUID: theUID];
|
2008-12-20 00:04:26 +01:00
|
|
|
|
|
|
|
// We must add an occurence to a non-existing event. We have
|
|
|
|
// to handle this with care, as in the postCalDAVEventRequestTo:from:
|
2009-06-02 23:51:17 +02:00
|
|
|
if ([attendeeObject isNew] && [theEvent recurrenceId])
|
2008-12-20 00:04:26 +01:00
|
|
|
{
|
2009-06-02 23:51:17 +02:00
|
|
|
SOGoAppointmentObject *ownerObject;
|
2008-12-20 00:04:26 +01:00
|
|
|
NSArray *attendees;
|
2009-06-02 23:51:17 +02:00
|
|
|
iCalEvent *ownerEvent;
|
2008-12-20 00:04:26 +01:00
|
|
|
iCalPerson *person;
|
|
|
|
SOGoUser *user;
|
|
|
|
BOOL found;
|
|
|
|
int i;
|
|
|
|
|
2009-06-02 23:51:17 +02:00
|
|
|
// We check if the attendee that was added to a single occurence is
|
|
|
|
// present in the master component. If not, we add it with a participation
|
|
|
|
// status set to "DECLINED".
|
|
|
|
|
2009-08-25 23:28:24 +02:00
|
|
|
user = [SOGoUser userWithLogin: theUID];
|
2008-12-20 00:04:26 +01:00
|
|
|
person = [iCalPerson elementWithTag: @"attendee"];
|
|
|
|
[person setCn: [user cn]];
|
|
|
|
[person setEmail: [[user allEmails] objectAtIndex: 0]];
|
|
|
|
[person setParticipationStatus: iCalPersonPartStatDeclined];
|
|
|
|
[person setRsvp: @"TRUE"];
|
|
|
|
[person setRole: @"REQ-PARTICIPANT"];
|
|
|
|
|
2009-06-02 23:51:17 +02:00
|
|
|
ownerObject = [self _lookupEvent: [theEvent uid] forUID: theOwner];
|
|
|
|
ownerEvent = [[[theEvent parent] events] objectAtIndex: 0];
|
|
|
|
attendees = [ownerEvent attendees];
|
2008-12-20 00:04:26 +01:00
|
|
|
found = NO;
|
|
|
|
|
|
|
|
for (i = 0; i < [attendees count]; i++)
|
|
|
|
{
|
|
|
|
if ([[attendees objectAtIndex: i] hasSameEmailAddress: person])
|
|
|
|
{
|
|
|
|
found = YES;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
2009-06-02 23:51:17 +02:00
|
|
|
// Update the master event in the owner's calendar with the
|
|
|
|
// status of the new attendee set as "DECLINED".
|
|
|
|
[ownerEvent addToAttendees: person];
|
|
|
|
iCalString = [[ownerEvent parent] versitString];
|
|
|
|
[ownerObject saveContentString: iCalString];
|
2008-12-20 00:04:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-08-11 04:06:27 +02:00
|
|
|
// TODO : if [theEvent recurrenceId], only update this occurrence
|
|
|
|
// in attendee's calendar
|
|
|
|
|
|
|
|
// TODO : when updating the master event, handle exception dates
|
|
|
|
// in attendee's calendar (add exception dates and remove matching
|
|
|
|
// occurrences) -- see _updateRecurrenceIDsWithEvent:
|
|
|
|
|
2008-12-20 00:04:26 +01:00
|
|
|
iCalString = [[theEvent parent] versitString];
|
|
|
|
}
|
|
|
|
|
2009-06-02 23:51:17 +02:00
|
|
|
// Save the event in the attendee's calendar
|
|
|
|
[attendeeObject saveContentString: iCalString];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
}
|
2007-01-31 21:15:28 +01:00
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2008-11-26 13:20:26 +01:00
|
|
|
- (void) _removeEventFromUID: (NSString *) theUID
|
|
|
|
owner: (NSString *) theOwner
|
2008-12-04 00:08:37 +01:00
|
|
|
withRecurrenceId: (NSCalendarDate *) recurrenceId
|
2007-11-07 16:58:43 +01:00
|
|
|
{
|
2008-11-26 13:20:26 +01:00
|
|
|
if (![theUID isEqualToString: theOwner])
|
2007-11-07 16:58:43 +01:00
|
|
|
{
|
2008-11-26 13:20:26 +01:00
|
|
|
SOGoAppointmentFolder *folder;
|
|
|
|
SOGoAppointmentObject *object;
|
2008-12-05 17:11:41 +01:00
|
|
|
iCalEntityObject *currentOccurence;
|
2008-12-04 00:08:37 +01:00
|
|
|
iCalRepeatableEntityObject *event;
|
|
|
|
iCalCalendar *calendar;
|
2008-12-05 17:11:41 +01:00
|
|
|
NSCalendarDate *currentId;
|
|
|
|
NSString *calendarContent;
|
2009-04-01 15:49:24 +02:00
|
|
|
NSArray *occurences;
|
2008-12-05 17:11:41 +01:00
|
|
|
int max, count;
|
2009-03-23 22:19:55 +01:00
|
|
|
|
|
|
|
// Invitations are always written to the personal folder; it's not necessay
|
|
|
|
// to look into all folders of the user
|
2010-07-15 19:05:29 +02:00
|
|
|
folder = [[SOGoUser userWithLogin: theUID]
|
|
|
|
personalCalendarFolderInContext: context];
|
2007-11-18 11:16:25 +01:00
|
|
|
object = [folder lookupName: nameInContainer
|
|
|
|
inContext: context acquire: NO];
|
|
|
|
if (![object isKindOfClass: [NSException class]])
|
2008-12-04 00:08:37 +01:00
|
|
|
{
|
|
|
|
if (recurrenceId == nil)
|
|
|
|
[object delete];
|
|
|
|
else
|
|
|
|
{
|
2008-12-05 17:11:41 +01:00
|
|
|
calendar = [object calendar: NO secure: NO];
|
2009-03-23 22:19:55 +01:00
|
|
|
|
2008-12-05 17:11:41 +01:00
|
|
|
// If recurrenceId is defined, remove the occurence from
|
|
|
|
// the repeating event.
|
|
|
|
occurences = [calendar events];
|
|
|
|
max = [occurences count];
|
|
|
|
count = 1;
|
|
|
|
while (count < max)
|
2008-12-04 00:08:37 +01:00
|
|
|
{
|
2008-12-05 17:11:41 +01:00
|
|
|
currentOccurence = [occurences objectAtIndex: count];
|
|
|
|
currentId = [currentOccurence recurrenceId];
|
|
|
|
if ([currentId compare: recurrenceId] == NSOrderedSame)
|
|
|
|
{
|
|
|
|
[[calendar children] removeObject: currentOccurence];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
count++;
|
2008-12-04 00:08:37 +01:00
|
|
|
}
|
|
|
|
|
2008-12-05 17:11:41 +01:00
|
|
|
// Add an date exception.
|
2008-12-04 00:08:37 +01:00
|
|
|
event = (iCalRepeatableEntityObject*)[calendar firstChildWithTag: [object componentTag]];
|
|
|
|
[event addToExceptionDates: recurrenceId];
|
2009-03-23 22:19:55 +01:00
|
|
|
|
2008-12-05 17:11:41 +01:00
|
|
|
[event increaseSequence];
|
2009-03-23 22:19:55 +01:00
|
|
|
|
2008-12-04 00:08:37 +01:00
|
|
|
// We generate the updated iCalendar file and we save it
|
|
|
|
// in the database.
|
|
|
|
calendarContent = [calendar versitString];
|
|
|
|
[object saveContentString: calendarContent];
|
|
|
|
}
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2007-11-18 11:16:25 +01:00
|
|
|
- (void) _handleRemovedUsers: (NSArray *) attendees
|
2008-12-04 00:08:37 +01:00
|
|
|
withRecurrenceId: (NSCalendarDate *) recurrenceId
|
2007-09-06 22:51:59 +02:00
|
|
|
{
|
2007-11-18 11:16:25 +01:00
|
|
|
NSEnumerator *enumerator;
|
|
|
|
iCalPerson *currentAttendee;
|
|
|
|
NSString *currentUID;
|
2007-09-06 22:51:59 +02:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
enumerator = [attendees objectEnumerator];
|
|
|
|
while ((currentAttendee = [enumerator nextObject]))
|
|
|
|
{
|
|
|
|
currentUID = [currentAttendee uid];
|
|
|
|
if (currentUID)
|
2008-11-26 13:20:26 +01:00
|
|
|
[self _removeEventFromUID: currentUID
|
2008-12-04 00:08:37 +01:00
|
|
|
owner: owner
|
|
|
|
withRecurrenceId: recurrenceId];
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
2007-09-06 22:51:59 +02:00
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2010-07-16 17:03:16 +02:00
|
|
|
- (void) _removeDelegationChain: (iCalPerson *) delegate
|
|
|
|
inEvent: (iCalEvent *) event
|
2006-09-28 19:23:39 +02:00
|
|
|
{
|
2010-07-16 17:03:16 +02:00
|
|
|
NSString *delegatedTo, *mailTo;
|
|
|
|
|
|
|
|
delegatedTo = [delegate delegatedTo];
|
|
|
|
if ([delegatedTo length] > 0)
|
|
|
|
{
|
|
|
|
mailTo = [delegatedTo rfc822Email];
|
|
|
|
delegate = [event findAttendeeWithEmail: mailTo];
|
|
|
|
if (delegate)
|
|
|
|
{
|
|
|
|
[self _removeDelegationChain: delegate
|
|
|
|
inEvent: event];
|
|
|
|
[event removeFromAttendees: delegate];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[self errorWithFormat:
|
|
|
|
@"broken chain: delegate with email '%@' was not found",
|
|
|
|
mailTo];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
//
|
|
|
|
// This method returns YES when any attendee has been removed
|
|
|
|
// and NO otherwise.
|
|
|
|
//
|
2010-07-16 17:03:16 +02:00
|
|
|
- (BOOL) _requireResponseFromAttendees: (iCalEvent *) event
|
|
|
|
{
|
|
|
|
NSArray *attendees;
|
2007-11-18 11:16:25 +01:00
|
|
|
iCalPerson *currentAttendee;
|
2010-07-16 17:03:16 +02:00
|
|
|
BOOL listHasChanged;
|
|
|
|
int count, max;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2010-07-16 17:03:16 +02:00
|
|
|
attendees = [event attendees];
|
|
|
|
max = [attendees count];
|
|
|
|
|
|
|
|
for (count = 0; count < max; count++)
|
2007-11-18 11:16:25 +01:00
|
|
|
{
|
2010-07-16 17:03:16 +02:00
|
|
|
currentAttendee = [attendees objectAtIndex: count];
|
|
|
|
if ([[currentAttendee delegatedTo] length] > 0)
|
|
|
|
{
|
|
|
|
[self _removeDelegationChain: currentAttendee
|
|
|
|
inEvent: event];
|
|
|
|
[currentAttendee setDelegatedTo: nil];
|
|
|
|
listHasChanged = YES;
|
|
|
|
}
|
2007-11-18 11:16:25 +01:00
|
|
|
[currentAttendee setRsvp: @"TRUE"];
|
|
|
|
[currentAttendee setParticipationStatus: iCalPersonPartStatNeedsAction];
|
|
|
|
}
|
2010-07-16 17:03:16 +02:00
|
|
|
|
|
|
|
return listHasChanged;
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
2007-11-08 20:56:18 +01:00
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2007-11-18 11:16:25 +01:00
|
|
|
- (void) _handleSequenceUpdateInEvent: (iCalEvent *) newEvent
|
|
|
|
ignoringAttendees: (NSArray *) attendees
|
|
|
|
fromOldEvent: (iCalEvent *) oldEvent
|
|
|
|
{
|
|
|
|
NSMutableArray *updateAttendees, *updateUIDs;
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
iCalPerson *currentAttendee;
|
|
|
|
NSString *currentUID;
|
2007-11-08 20:56:18 +01:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
updateAttendees = [NSMutableArray arrayWithArray: [newEvent attendees]];
|
|
|
|
[updateAttendees removeObjectsInArray: attendees];
|
2007-11-08 20:56:18 +01:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
updateUIDs = [NSMutableArray arrayWithCapacity: [updateAttendees count]];
|
|
|
|
enumerator = [updateAttendees objectEnumerator];
|
|
|
|
while ((currentAttendee = [enumerator nextObject]))
|
|
|
|
{
|
|
|
|
currentUID = [currentAttendee uid];
|
|
|
|
if (currentUID)
|
|
|
|
[self _addOrUpdateEvent: newEvent
|
2009-09-10 20:31:20 +02:00
|
|
|
forUID: currentUID
|
|
|
|
owner: owner];
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-11-18 01:06:37 +01:00
|
|
|
[self sendEMailUsingTemplateNamed: @"Update"
|
2008-10-01 21:32:14 +02:00
|
|
|
forObject: [newEvent itipEntryWithMethod: @"request"]
|
2008-11-18 01:06:37 +01:00
|
|
|
previousObject: oldEvent
|
2007-11-18 11:16:25 +01:00
|
|
|
toAttendees: updateAttendees];
|
2009-08-25 23:28:24 +02:00
|
|
|
[self sendReceiptEmailUsingTemplateNamed: @"Update"
|
|
|
|
forObject: newEvent to: updateAttendees];
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2009-05-06 23:57:21 +02:00
|
|
|
- (void) _handleAddedUsers: (NSArray *) attendees
|
2007-11-18 11:16:25 +01:00
|
|
|
fromEvent: (iCalEvent *) newEvent
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
iCalPerson *currentAttendee;
|
|
|
|
NSString *currentUID;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
enumerator = [attendees objectEnumerator];
|
|
|
|
while ((currentAttendee = [enumerator nextObject]))
|
|
|
|
{
|
2009-05-06 23:57:21 +02:00
|
|
|
currentUID = [currentAttendee uid];
|
|
|
|
if (currentUID)
|
2007-11-18 11:16:25 +01:00
|
|
|
[self _addOrUpdateEvent: newEvent
|
2009-09-10 20:31:20 +02:00
|
|
|
forUID: currentUID
|
|
|
|
owner: owner];
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2009-04-30 23:17:55 +02:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2007-11-18 11:16:25 +01:00
|
|
|
- (void) _handleUpdatedEvent: (iCalEvent *) newEvent
|
|
|
|
fromOldEvent: (iCalEvent *) oldEvent
|
|
|
|
{
|
|
|
|
NSArray *attendees;
|
|
|
|
iCalEventChanges *changes;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
changes = [newEvent getChangesRelativeToEvent: oldEvent];
|
2010-07-16 17:03:16 +02:00
|
|
|
if ([changes sequenceShouldBeIncreased])
|
|
|
|
{
|
|
|
|
// Set new attendees status to "needs action" and recompute changes when
|
|
|
|
// the list of attendees has changed.
|
|
|
|
if ([self _requireResponseFromAttendees: newEvent])
|
|
|
|
changes = [newEvent getChangesRelativeToEvent: oldEvent];
|
|
|
|
}
|
2007-11-18 11:16:25 +01:00
|
|
|
attendees = [changes deletedAttendees];
|
|
|
|
if ([attendees count])
|
|
|
|
{
|
2008-12-04 00:08:37 +01:00
|
|
|
[self _handleRemovedUsers: attendees
|
|
|
|
withRecurrenceId: [newEvent recurrenceId]];
|
2007-11-18 11:16:25 +01:00
|
|
|
[self sendEMailUsingTemplateNamed: @"Deletion"
|
2008-10-01 21:32:14 +02:00
|
|
|
forObject: [newEvent itipEntryWithMethod: @"cancel"]
|
2008-11-18 01:06:37 +01:00
|
|
|
previousObject: oldEvent
|
2007-11-18 11:16:25 +01:00
|
|
|
toAttendees: attendees];
|
2009-08-25 23:28:24 +02:00
|
|
|
[self sendReceiptEmailUsingTemplateNamed: @"Deletion"
|
|
|
|
forObject: newEvent to: attendees];
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
attendees = [changes insertedAttendees];
|
|
|
|
if ([changes sequenceShouldBeIncreased])
|
|
|
|
{
|
|
|
|
[newEvent increaseSequence];
|
2008-12-09 16:29:39 +01:00
|
|
|
// Update attendees calendars and send them an update
|
|
|
|
// notification by email
|
2007-11-18 11:16:25 +01:00
|
|
|
[self _handleSequenceUpdateInEvent: newEvent
|
|
|
|
ignoringAttendees: attendees
|
|
|
|
fromOldEvent: oldEvent];
|
|
|
|
}
|
|
|
|
else
|
2008-11-29 00:10:41 +01:00
|
|
|
{
|
|
|
|
// If other attributes have changed, update the event
|
|
|
|
// in each attendee's calendar
|
|
|
|
if ([[changes updatedProperties] count])
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
iCalPerson *currentAttendee;
|
|
|
|
NSString *currentUID;
|
2009-08-25 23:28:24 +02:00
|
|
|
NSArray *updatedAttendees;
|
2008-11-29 00:10:41 +01:00
|
|
|
|
2009-08-25 23:28:24 +02:00
|
|
|
updatedAttendees = [newEvent attendees];
|
|
|
|
enumerator = [updatedAttendees objectEnumerator];
|
2008-11-29 00:10:41 +01:00
|
|
|
while ((currentAttendee = [enumerator nextObject]))
|
|
|
|
{
|
|
|
|
currentUID = [currentAttendee uid];
|
|
|
|
if (currentUID)
|
|
|
|
[self _addOrUpdateEvent: newEvent
|
2009-09-10 20:31:20 +02:00
|
|
|
forUID: currentUID
|
|
|
|
owner: owner];
|
2008-11-29 00:10:41 +01:00
|
|
|
}
|
2009-08-25 23:28:24 +02:00
|
|
|
|
|
|
|
[self sendReceiptEmailUsingTemplateNamed: @"Update"
|
|
|
|
forObject: newEvent
|
|
|
|
to: updatedAttendees];
|
2008-11-29 00:10:41 +01:00
|
|
|
}
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
if ([attendees count])
|
|
|
|
{
|
2008-11-29 00:10:41 +01:00
|
|
|
// Send an invitation to new attendees
|
2009-05-06 23:57:21 +02:00
|
|
|
[self _handleAddedUsers: attendees fromEvent: newEvent];
|
2008-11-29 00:10:41 +01:00
|
|
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
2008-10-01 21:32:14 +02:00
|
|
|
forObject: [newEvent itipEntryWithMethod: @"request"]
|
2008-11-18 01:06:37 +01:00
|
|
|
previousObject: oldEvent
|
2007-11-18 11:16:25 +01:00
|
|
|
toAttendees: attendees];
|
2009-08-25 23:28:24 +02:00
|
|
|
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
|
|
|
forObject: newEvent to: attendees];
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2010-08-11 16:52:11 +02:00
|
|
|
//
|
|
|
|
// Workflow : +----------------------+
|
|
|
|
// | |
|
|
|
|
// [saveComponent:]---> _handleAddedUsers:fromEvent: <-+ |
|
|
|
|
// | | v
|
|
|
|
// +------------> _handleUpdatedEvent:fromOldEvent: ---> _addOrUpdateEvent:forUID:owner: <-----------+
|
|
|
|
// | | ^ |
|
|
|
|
// v v | |
|
|
|
|
// _handleRemoveUsers:withRecurrenceId: _handleSequenceUpdateInEvent:ignoringAttendees:fromOldEvent: |
|
|
|
|
// | |
|
|
|
|
// | [DELETEAction:] |
|
|
|
|
// | | {_handleAdded/Updated...}<--+ |
|
|
|
|
// | v | |
|
|
|
|
// | [prepareDeleteOccurence:] [PUTAction:] |
|
|
|
|
// | | | | |
|
|
|
|
// v v v v |
|
|
|
|
// _removeEventFromUID:owner:withRecurrenceId: [changeParticipationStatus:withDelegate:forRecurrenceId:] |
|
|
|
|
// | | |
|
|
|
|
// | v |
|
|
|
|
// +------------------------> _handleAttendee:withDelegate:ownerUser:statusChange:inEvent: ---> [sendResponseToOrganizer:from:]
|
|
|
|
// |
|
|
|
|
// v
|
|
|
|
// _updateAttendee:withDelegate:ownerUser:forEventUID:withRecurrenceId:withSequence:forUID:shouldAddSentBy:
|
|
|
|
//
|
|
|
|
//
|
2007-11-18 11:16:25 +01:00
|
|
|
- (void) saveComponent: (iCalEvent *) newEvent
|
|
|
|
{
|
2009-08-25 23:28:24 +02:00
|
|
|
iCalEvent *oldEvent, *oldMasterEvent;
|
2007-11-18 11:16:25 +01:00
|
|
|
NSArray *attendees;
|
2008-12-03 17:18:12 +01:00
|
|
|
NSCalendarDate *recurrenceId;
|
|
|
|
NSString *recurrenceTime;
|
2008-08-14 00:30:55 +02:00
|
|
|
SOGoUser *ownerUser;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
[[newEvent parent] setMethod: @""];
|
2009-08-25 23:28:24 +02:00
|
|
|
ownerUser = [SOGoUser userWithLogin: owner];
|
2008-12-17 16:35:53 +01:00
|
|
|
|
2009-05-06 23:57:21 +02:00
|
|
|
[self expandGroupsInEvent: newEvent];
|
|
|
|
|
2011-03-30 01:25:40 +02:00
|
|
|
// We first update the event. It is important to this initially
|
|
|
|
// as the event's UID might get modified.
|
|
|
|
[super updateComponent: newEvent];
|
2008-11-26 17:26:32 +01:00
|
|
|
|
2009-08-11 04:06:27 +02:00
|
|
|
if ([self isNew])
|
2007-11-18 11:16:25 +01:00
|
|
|
{
|
2009-08-11 04:06:27 +02:00
|
|
|
// New event -- send invitation to all attendees
|
|
|
|
attendees = [newEvent attendeesWithoutUser: ownerUser];
|
|
|
|
if ([attendees count])
|
2007-11-08 20:56:18 +01:00
|
|
|
{
|
2009-08-11 04:06:27 +02:00
|
|
|
[self _handleAddedUsers: attendees fromEvent: newEvent];
|
|
|
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
|
|
|
forObject: [newEvent itipEntryWithMethod: @"request"]
|
|
|
|
previousObject: nil
|
|
|
|
toAttendees: attendees];
|
2009-08-25 23:28:24 +02:00
|
|
|
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
|
|
|
forObject: newEvent to: attendees];
|
2007-11-08 20:56:18 +01:00
|
|
|
}
|
2009-08-11 04:06:27 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-19 14:56:52 +02:00
|
|
|
BOOL hasOrganizer;
|
2009-08-11 04:06:27 +02:00
|
|
|
// Event is modified -- sent update status to all attendees
|
|
|
|
// and modify their calendars.
|
|
|
|
recurrenceId = [newEvent recurrenceId];
|
|
|
|
if (recurrenceId == nil)
|
|
|
|
oldEvent = [self component: NO secure: NO];
|
2008-11-28 20:54:51 +01:00
|
|
|
else
|
|
|
|
{
|
2009-08-11 04:06:27 +02:00
|
|
|
// If recurrenceId is defined, find the specified occurence
|
|
|
|
// within the repeating vEvent.
|
|
|
|
recurrenceTime = [NSString stringWithFormat: @"%f", [recurrenceId timeIntervalSince1970]];
|
|
|
|
oldEvent = (iCalEvent*)[self lookupOccurence: recurrenceTime];
|
|
|
|
if (oldEvent == nil)
|
|
|
|
// If no occurence found, create one
|
2011-04-01 20:55:02 +02:00
|
|
|
oldEvent = (iCalEvent *)[self newOccurenceWithID: recurrenceTime];
|
2009-08-11 04:06:27 +02:00
|
|
|
}
|
2009-08-25 23:28:24 +02:00
|
|
|
|
2009-10-19 14:56:52 +02:00
|
|
|
oldMasterEvent = (iCalEvent *) [[oldEvent parent] firstChildWithTag: [self componentTag]];
|
|
|
|
hasOrganizer = [[[oldMasterEvent organizer] email] length];
|
|
|
|
|
|
|
|
if (!hasOrganizer || [oldMasterEvent userIsOrganizer: ownerUser])
|
2011-03-30 01:25:40 +02:00
|
|
|
// The owner is the organizer of the event; handle the modifications
|
|
|
|
[self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent];
|
2007-01-31 21:15:28 +01:00
|
|
|
}
|
2011-02-24 21:18:21 +01:00
|
|
|
|
2011-03-30 01:25:40 +02:00
|
|
|
[super saveComponent: newEvent];
|
|
|
|
|
2011-02-24 21:18:21 +01:00
|
|
|
[fullCalendar release];
|
|
|
|
fullCalendar = nil;
|
|
|
|
[safeCalendar release];
|
|
|
|
safeCalendar = nil;
|
|
|
|
[originalCalendar release];
|
|
|
|
originalCalendar = nil;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2008-11-10 16:38:05 +01:00
|
|
|
//
|
|
|
|
// This method is used to update the status of an attendee.
|
|
|
|
//
|
|
|
|
// - theOwnerUser is owner of the calendar where the attendee
|
|
|
|
// participation state has changed.
|
|
|
|
// - uid is the actual UID of the user for whom we must
|
|
|
|
// update the calendar event (with the participation change)
|
2010-08-19 19:40:28 +02:00
|
|
|
// - delegate is the delegate attendee if any
|
2008-11-10 16:38:05 +01:00
|
|
|
//
|
|
|
|
// This method is called multiple times, in order to update the
|
|
|
|
// status of the attendee in calendars for the particular event UID.
|
|
|
|
//
|
2007-11-18 11:16:25 +01:00
|
|
|
- (NSException *) _updateAttendee: (iCalPerson *) attendee
|
2009-08-27 18:20:41 +02:00
|
|
|
withDelegate: (iCalPerson *) delegate
|
2008-11-05 22:04:16 +01:00
|
|
|
ownerUser: (SOGoUser *) theOwnerUser
|
2007-11-18 11:16:25 +01:00
|
|
|
forEventUID: (NSString *) eventUID
|
2008-11-22 08:20:22 +01:00
|
|
|
withRecurrenceId: (NSCalendarDate *) recurrenceId
|
2007-11-18 11:16:25 +01:00
|
|
|
withSequence: (NSNumber *) sequence
|
|
|
|
forUID: (NSString *) uid
|
2008-11-05 22:04:16 +01:00
|
|
|
shouldAddSentBy: (BOOL) b
|
2007-11-08 20:56:18 +01:00
|
|
|
{
|
2007-11-18 11:16:25 +01:00
|
|
|
SOGoAppointmentObject *eventObject;
|
2008-11-22 08:20:22 +01:00
|
|
|
iCalCalendar *calendar;
|
|
|
|
iCalEntityObject *event;
|
2009-08-27 18:20:41 +02:00
|
|
|
iCalPerson *otherAttendee, *otherDelegate;
|
|
|
|
NSString *iCalString, *recurrenceTime, *delegateEmail;
|
2007-11-08 20:56:18 +01:00
|
|
|
NSException *error;
|
2009-08-27 18:20:41 +02:00
|
|
|
BOOL addDelegate, removeDelegate;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
error = nil;
|
|
|
|
|
|
|
|
eventObject = [self _lookupEvent: eventUID forUID: uid];
|
|
|
|
if (![eventObject isNew])
|
2007-11-08 20:56:18 +01:00
|
|
|
{
|
2008-11-22 08:20:22 +01:00
|
|
|
if (recurrenceId == nil)
|
|
|
|
{
|
|
|
|
// We must update main event and all its occurences (if any).
|
|
|
|
calendar = [eventObject calendar: NO secure: NO];
|
2008-12-03 17:18:12 +01:00
|
|
|
event = (iCalEntityObject*)[calendar firstChildWithTag: [self componentTag]];
|
2008-11-22 08:20:22 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If recurrenceId is defined, find the specified occurence
|
|
|
|
// within the repeating vEvent.
|
|
|
|
recurrenceTime = [NSString stringWithFormat: @"%f", [recurrenceId timeIntervalSince1970]];
|
|
|
|
event = [eventObject lookupOccurence: recurrenceTime];
|
|
|
|
|
|
|
|
if (event == nil)
|
2008-12-01 17:24:15 +01:00
|
|
|
// If no occurence found, create one
|
2008-11-22 08:20:22 +01:00
|
|
|
event = [eventObject newOccurenceWithID: recurrenceTime];
|
|
|
|
}
|
2010-08-11 16:52:11 +02:00
|
|
|
|
|
|
|
if ([[event sequence] intValue] <= [sequence intValue])
|
2007-11-18 11:16:25 +01:00
|
|
|
{
|
2008-11-05 22:04:16 +01:00
|
|
|
SOGoUser *currentUser;
|
2008-11-22 08:20:22 +01:00
|
|
|
|
2008-12-02 04:35:34 +01:00
|
|
|
currentUser = [context activeUser];
|
2010-05-05 15:56:19 +02:00
|
|
|
otherAttendee = [event userAsAttendee: theOwnerUser];
|
2009-08-27 18:20:41 +02:00
|
|
|
|
|
|
|
delegateEmail = [otherAttendee delegatedTo];
|
|
|
|
if ([delegateEmail length])
|
2009-09-10 20:31:20 +02:00
|
|
|
delegateEmail = [delegateEmail rfc822Email];
|
2009-08-27 18:20:41 +02:00
|
|
|
if ([delegateEmail length])
|
2010-05-05 15:56:19 +02:00
|
|
|
otherDelegate = [event findAttendeeWithEmail: delegateEmail];
|
2009-08-27 18:20:41 +02:00
|
|
|
else
|
|
|
|
otherDelegate = NO;
|
|
|
|
|
2010-08-19 19:40:28 +02:00
|
|
|
/* we handle the addition/deletion of delegate users */
|
2009-08-27 18:20:41 +02:00
|
|
|
addDelegate = NO;
|
|
|
|
removeDelegate = NO;
|
|
|
|
if (delegate)
|
|
|
|
{
|
|
|
|
if (otherDelegate)
|
|
|
|
{
|
|
|
|
if (![delegate hasSameEmailAddress: otherDelegate])
|
|
|
|
{
|
|
|
|
removeDelegate = YES;
|
|
|
|
addDelegate = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
addDelegate = YES;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (otherDelegate)
|
|
|
|
removeDelegate = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (removeDelegate)
|
2009-09-10 20:31:20 +02:00
|
|
|
{
|
|
|
|
while (otherDelegate)
|
|
|
|
{
|
|
|
|
[event removeFromAttendees: otherDelegate];
|
|
|
|
|
2010-08-19 19:40:28 +02:00
|
|
|
// Verify if the delegate was already delegate
|
2009-09-10 20:31:20 +02:00
|
|
|
delegateEmail = [otherDelegate delegatedTo];
|
|
|
|
if ([delegateEmail length])
|
|
|
|
delegateEmail = [delegateEmail rfc822Email];
|
|
|
|
|
|
|
|
if ([delegateEmail length])
|
2010-05-05 15:56:19 +02:00
|
|
|
otherDelegate = [event findAttendeeWithEmail: delegateEmail];
|
2009-09-10 20:31:20 +02:00
|
|
|
else
|
|
|
|
otherDelegate = NO;
|
|
|
|
}
|
|
|
|
}
|
2009-08-27 18:20:41 +02:00
|
|
|
if (addDelegate)
|
|
|
|
[event addToAttendees: delegate];
|
|
|
|
|
2008-12-09 16:29:39 +01:00
|
|
|
[otherAttendee setPartStat: [attendee partStat]];
|
2009-08-27 18:20:41 +02:00
|
|
|
[otherAttendee setDelegatedTo: [attendee delegatedTo]];
|
|
|
|
[otherAttendee setDelegatedFrom: [attendee delegatedFrom]];
|
|
|
|
|
2008-12-09 16:29:39 +01:00
|
|
|
// If one has accepted / declined an invitation on behalf of
|
|
|
|
// the attendee, we add the user to the SENT-BY attribute.
|
|
|
|
if (b && ![[currentUser login] isEqualToString: [theOwnerUser login]])
|
2008-11-13 14:41:43 +01:00
|
|
|
{
|
2009-08-11 18:52:10 +02:00
|
|
|
NSString *currentEmail, *quotedEmail;
|
2008-12-09 16:29:39 +01:00
|
|
|
currentEmail = [[currentUser allEmails] objectAtIndex: 0];
|
2009-08-11 18:52:10 +02:00
|
|
|
quotedEmail = [NSString stringWithFormat: @"\"MAILTO:%@\"",
|
|
|
|
currentEmail];
|
|
|
|
[otherAttendee setValue: 0 ofAttribute: @"SENT-BY"
|
|
|
|
to: quotedEmail];
|
2008-12-09 16:29:39 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// We must REMOVE any SENT-BY here. This is important since if A accepted
|
|
|
|
// the event for B and then, B changes by himself his participation status,
|
|
|
|
// we don't want to keep the previous SENT-BY attribute there.
|
|
|
|
[(NSMutableDictionary *)[otherAttendee attributes] removeObjectForKey: @"SENT-BY"];
|
2008-11-13 14:41:43 +01:00
|
|
|
}
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
2008-12-09 16:29:39 +01:00
|
|
|
|
|
|
|
// We generate the updated iCalendar file and we save it
|
|
|
|
// in the database.
|
|
|
|
iCalString = [[event parent] versitString];
|
|
|
|
error = [eventObject saveContentString: iCalString];
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
2008-12-09 16:29:39 +01:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2008-11-10 16:38:05 +01:00
|
|
|
|
|
|
|
//
|
2009-08-27 18:20:41 +02:00
|
|
|
// This method is invoked from the SOGo Web interface.
|
2008-11-10 16:38:05 +01:00
|
|
|
//
|
|
|
|
// - theOwnerUser is owner of the calendar where the attendee
|
|
|
|
// participation state has changed.
|
|
|
|
//
|
2007-11-18 11:16:25 +01:00
|
|
|
- (NSException *) _handleAttendee: (iCalPerson *) attendee
|
2009-08-27 18:20:41 +02:00
|
|
|
withDelegate: (iCalPerson *) delegate
|
2008-11-05 22:04:16 +01:00
|
|
|
ownerUser: (SOGoUser *) theOwnerUser
|
2007-11-18 11:16:25 +01:00
|
|
|
statusChange: (NSString *) newStatus
|
|
|
|
inEvent: (iCalEvent *) event
|
|
|
|
{
|
2008-11-18 01:06:37 +01:00
|
|
|
NSString *newContent, *currentStatus, *organizerUID;
|
|
|
|
SOGoUser *ownerUser, *currentUser;
|
2008-11-10 16:38:05 +01:00
|
|
|
NSException *ex;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
ex = nil;
|
|
|
|
|
|
|
|
currentStatus = [attendee partStat];
|
2009-09-10 20:31:20 +02:00
|
|
|
|
|
|
|
iCalPerson *otherAttendee, *otherDelegate;
|
|
|
|
NSString *delegateEmail;
|
|
|
|
BOOL addDelegate, removeDelegate;
|
|
|
|
|
|
|
|
otherAttendee = attendee;
|
|
|
|
|
|
|
|
delegateEmail = [otherAttendee delegatedTo];
|
|
|
|
if ([delegateEmail length])
|
|
|
|
delegateEmail = [delegateEmail rfc822Email];
|
|
|
|
|
|
|
|
if ([delegateEmail length])
|
2010-05-05 15:56:19 +02:00
|
|
|
otherDelegate = [event findAttendeeWithEmail: delegateEmail];
|
2009-09-10 20:31:20 +02:00
|
|
|
else
|
2010-08-19 19:40:28 +02:00
|
|
|
otherDelegate = nil;
|
2009-09-10 20:31:20 +02:00
|
|
|
|
2010-08-19 19:40:28 +02:00
|
|
|
/* We handle the addition/deletion of delegate users */
|
2009-09-10 20:31:20 +02:00
|
|
|
addDelegate = NO;
|
|
|
|
removeDelegate = NO;
|
|
|
|
if (delegate)
|
|
|
|
{
|
|
|
|
if (otherDelegate)
|
|
|
|
{
|
2010-08-19 19:40:28 +02:00
|
|
|
// There was already a delegate
|
2009-09-10 20:31:20 +02:00
|
|
|
if (![delegate hasSameEmailAddress: otherDelegate])
|
|
|
|
{
|
2010-08-19 19:40:28 +02:00
|
|
|
// The delegate has changed
|
2009-09-10 20:31:20 +02:00
|
|
|
removeDelegate = YES;
|
|
|
|
addDelegate = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2010-08-19 19:40:28 +02:00
|
|
|
// There was no previous delegate
|
2009-09-10 20:31:20 +02:00
|
|
|
addDelegate = YES;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (otherDelegate)
|
2010-08-19 19:40:28 +02:00
|
|
|
// The user has removed the delegate
|
2009-09-10 20:31:20 +02:00
|
|
|
removeDelegate = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addDelegate || removeDelegate
|
|
|
|
|| [currentStatus caseInsensitiveCompare: newStatus]
|
2007-11-18 11:16:25 +01:00
|
|
|
!= NSOrderedSame)
|
|
|
|
{
|
|
|
|
[attendee setPartStat: newStatus];
|
2008-11-05 22:04:16 +01:00
|
|
|
|
|
|
|
// If one has accepted / declined an invitation on behalf of
|
|
|
|
// the attendee, we add the user to the SENT-BY attribute.
|
|
|
|
currentUser = [context activeUser];
|
|
|
|
if (![[currentUser login] isEqualToString: [theOwnerUser login]])
|
|
|
|
{
|
2009-08-11 18:52:10 +02:00
|
|
|
NSString *currentEmail, *quotedEmail;
|
|
|
|
currentEmail = [[currentUser allEmails] objectAtIndex: 0];
|
|
|
|
quotedEmail = [NSString stringWithFormat: @"\"MAILTO:%@\"",
|
|
|
|
currentEmail];
|
|
|
|
[attendee setValue: 0 ofAttribute: @"SENT-BY"
|
|
|
|
to: quotedEmail];
|
2008-11-05 22:04:16 +01:00
|
|
|
}
|
2008-11-13 14:41:43 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// We must REMOVE any SENT-BY here. This is important since if A accepted
|
|
|
|
// the event for B and then, B changes by himself his participation status,
|
|
|
|
// we don't want to keep the previous SENT-BY attribute there.
|
|
|
|
[(NSMutableDictionary *)[attendee attributes] removeObjectForKey: @"SENT-BY"];
|
|
|
|
}
|
2009-09-10 20:31:20 +02:00
|
|
|
|
|
|
|
[attendee setDelegatedTo: [delegate email]];
|
|
|
|
|
2009-10-13 21:10:28 +02:00
|
|
|
NSString *delegatedUID = nil;
|
2009-09-10 20:31:20 +02:00
|
|
|
NSMutableArray *delegates;
|
2010-08-11 16:52:11 +02:00
|
|
|
|
2009-09-10 20:31:20 +02:00
|
|
|
if (removeDelegate)
|
|
|
|
{
|
2009-10-13 16:10:17 +02:00
|
|
|
delegates = [NSMutableArray array];
|
2009-09-10 20:31:20 +02:00
|
|
|
|
|
|
|
while (otherDelegate)
|
|
|
|
{
|
|
|
|
[delegates addObject: otherDelegate];
|
|
|
|
|
2009-10-28 18:48:22 +01:00
|
|
|
delegatedUID = [otherDelegate uid];
|
2009-09-10 20:31:20 +02:00
|
|
|
if (delegatedUID)
|
2010-08-19 19:40:28 +02:00
|
|
|
// Delegate attendee is a local user; remove event from his calendar
|
2009-09-10 20:31:20 +02:00
|
|
|
[self _removeEventFromUID: delegatedUID
|
|
|
|
owner: [theOwnerUser login]
|
|
|
|
withRecurrenceId: [event recurrenceId]];
|
|
|
|
|
|
|
|
[event removeFromAttendees: otherDelegate];
|
|
|
|
|
|
|
|
// Verify if the delegate was already delegated
|
|
|
|
delegateEmail = [otherDelegate delegatedTo];
|
|
|
|
if ([delegateEmail length])
|
|
|
|
delegateEmail = [delegateEmail rfc822Email];
|
|
|
|
|
|
|
|
if ([delegateEmail length])
|
2010-05-05 15:56:19 +02:00
|
|
|
otherDelegate = [event findAttendeeWithEmail: delegateEmail];
|
2009-09-10 20:31:20 +02:00
|
|
|
else
|
|
|
|
otherDelegate = NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
[self sendEMailUsingTemplateNamed: @"Deletion"
|
|
|
|
forObject: [event itipEntryWithMethod: @"cancel"]
|
|
|
|
previousObject: nil
|
|
|
|
toAttendees: delegates];
|
|
|
|
[self sendReceiptEmailUsingTemplateNamed: @"Deletion"
|
|
|
|
forObject: event
|
|
|
|
to: delegates];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addDelegate)
|
|
|
|
{
|
|
|
|
delegatedUID = [delegate uid];
|
|
|
|
delegates = [NSArray arrayWithObject: delegate];
|
|
|
|
[event addToAttendees: delegate];
|
|
|
|
|
|
|
|
if (delegatedUID)
|
2010-08-19 19:40:28 +02:00
|
|
|
// Delegate attendee is a local user; add event to his calendar
|
2009-09-10 20:31:20 +02:00
|
|
|
[self _addOrUpdateEvent: event
|
|
|
|
forUID: delegatedUID
|
|
|
|
owner: [theOwnerUser login]];
|
2008-11-05 22:04:16 +01:00
|
|
|
|
2009-09-10 20:31:20 +02:00
|
|
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
|
|
|
forObject: [event itipEntryWithMethod: @"request"]
|
|
|
|
previousObject: nil
|
|
|
|
toAttendees: delegates];
|
|
|
|
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
|
|
|
forObject: event to: delegates];
|
|
|
|
}
|
|
|
|
|
2010-08-11 16:52:11 +02:00
|
|
|
// We generate the updated iCalendar file and we save it in the database.
|
|
|
|
// We do this ONLY when using SOGo from the Web interface. Over DAV, it'll
|
|
|
|
// be handled directly in PUTAction:
|
|
|
|
if ([[context request] handledByDefaultHandler])
|
|
|
|
{
|
|
|
|
newContent = [[event parent] versitString];
|
|
|
|
ex = [self saveContentString: newContent];
|
|
|
|
}
|
2008-11-05 22:04:16 +01:00
|
|
|
|
2008-11-10 16:38:05 +01:00
|
|
|
// If the current user isn't the organizer of the event
|
|
|
|
// that has just been updated, we update the event and
|
|
|
|
// send a notification
|
2009-08-25 23:28:24 +02:00
|
|
|
ownerUser = [SOGoUser userWithLogin: owner];
|
2008-08-09 18:47:13 +02:00
|
|
|
if (!(ex || [event userIsOrganizer: ownerUser]))
|
2007-11-08 20:56:18 +01:00
|
|
|
{
|
2007-11-20 15:47:05 +01:00
|
|
|
if ([[attendee rsvp] isEqualToString: @"true"]
|
|
|
|
&& [event isStillRelevant])
|
2008-11-10 16:38:05 +01:00
|
|
|
[self sendResponseToOrganizer: event
|
|
|
|
from: ownerUser];
|
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
organizerUID = [[event organizer] uid];
|
2008-11-22 08:20:22 +01:00
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
// Event is an exception to a recurring event; retrieve organizer from master event
|
2008-11-22 08:20:22 +01:00
|
|
|
if (!organizerUID)
|
|
|
|
organizerUID = [[(iCalEntityObject*)[[event parent] firstChildWithTag: [self componentTag]] organizer] uid];
|
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
if (organizerUID)
|
2008-12-09 16:29:39 +01:00
|
|
|
// Update the attendee in organizer's calendar.
|
2007-11-18 11:16:25 +01:00
|
|
|
ex = [self _updateAttendee: attendee
|
2009-08-27 18:20:41 +02:00
|
|
|
withDelegate: delegate
|
|
|
|
ownerUser: theOwnerUser
|
|
|
|
forEventUID: [event uid]
|
|
|
|
withRecurrenceId: [event recurrenceId]
|
|
|
|
withSequence: [event sequence]
|
|
|
|
forUID: organizerUID
|
2008-11-05 22:04:16 +01:00
|
|
|
shouldAddSentBy: YES];
|
|
|
|
}
|
|
|
|
|
2010-05-05 15:56:19 +02:00
|
|
|
// We update the calendar of all attendees that are
|
2008-11-05 22:04:16 +01:00
|
|
|
// 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.
|
|
|
|
NSArray *attendees;
|
|
|
|
iCalPerson *att;
|
|
|
|
NSString *uid;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
attendees = [event attendees];
|
|
|
|
for (i = 0; i < [attendees count]; i++)
|
|
|
|
{
|
|
|
|
att = [attendees objectAtIndex: i];
|
2009-08-27 18:20:41 +02:00
|
|
|
uid = [att uid];
|
2009-09-10 20:31:20 +02:00
|
|
|
if (uid
|
|
|
|
&& att != attendee
|
|
|
|
&& ![uid isEqualToString: delegatedUID])
|
2009-08-27 18:20:41 +02:00
|
|
|
[self _updateAttendee: attendee
|
|
|
|
withDelegate: delegate
|
|
|
|
ownerUser: theOwnerUser
|
|
|
|
forEventUID: [event uid]
|
|
|
|
withRecurrenceId: [event recurrenceId]
|
|
|
|
withSequence: [event sequence]
|
|
|
|
forUID: uid
|
|
|
|
shouldAddSentBy: YES];
|
2007-11-08 20:56:18 +01:00
|
|
|
}
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return ex;
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-07-09 17:43:48 +02:00
|
|
|
- (NSDictionary *) _caldavSuccessCodeWithRecipient: (NSString *) recipient
|
|
|
|
{
|
|
|
|
NSMutableArray *element;
|
|
|
|
NSDictionary *code;
|
|
|
|
|
2009-10-13 16:10:17 +02:00
|
|
|
element = [NSMutableArray array];
|
2008-07-09 17:43:48 +02:00
|
|
|
[element addObject: davElementWithContent (@"recipient", XMLNS_CALDAV,
|
|
|
|
recipient)];
|
|
|
|
[element addObject: davElementWithContent (@"request-status",
|
|
|
|
XMLNS_CALDAV,
|
|
|
|
@"2.0;Success")];
|
|
|
|
code = davElementWithContent (@"response", XMLNS_CALDAV,
|
|
|
|
element);
|
|
|
|
|
|
|
|
return code;
|
|
|
|
}
|
|
|
|
|
2008-11-26 13:20:26 +01:00
|
|
|
//
|
2010-08-11 16:52:11 +02:00
|
|
|
// Old CalDAV scheduling (draft 4 and below) methods. We keep them since we still
|
|
|
|
// advertise for its support but we do everything within the calendar-auto-scheduling code
|
2008-11-26 13:20:26 +01:00
|
|
|
//
|
2008-07-05 00:25:27 +02:00
|
|
|
- (NSArray *) postCalDAVEventRequestTo: (NSArray *) recipients
|
2008-11-10 16:38:05 +01:00
|
|
|
from: (NSString *) originator
|
2008-07-05 00:25:27 +02:00
|
|
|
{
|
|
|
|
NSEnumerator *recipientsEnum;
|
2010-08-11 16:52:11 +02:00
|
|
|
NSMutableArray *elements;
|
|
|
|
NSString *recipient;
|
2008-11-18 21:59:08 +01:00
|
|
|
|
2008-07-05 00:25:27 +02:00
|
|
|
elements = [NSMutableArray array];
|
2009-08-25 23:28:24 +02:00
|
|
|
|
2008-07-05 00:25:27 +02:00
|
|
|
recipientsEnum = [recipients objectEnumerator];
|
2010-08-11 16:52:11 +02:00
|
|
|
|
2008-07-05 00:25:27 +02:00
|
|
|
while ((recipient = [recipientsEnum nextObject]))
|
2008-07-08 17:42:40 +02:00
|
|
|
if ([[recipient lowercaseString] hasPrefix: @"mailto:"])
|
|
|
|
{
|
2010-08-11 16:52:11 +02:00
|
|
|
[elements addObject: [self _caldavSuccessCodeWithRecipient: recipient]];
|
2008-07-09 17:43:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return elements;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) postCalDAVEventCancelTo: (NSArray *) recipients
|
2008-11-10 16:38:05 +01:00
|
|
|
from: (NSString *) originator
|
2008-07-09 17:43:48 +02:00
|
|
|
{
|
|
|
|
NSEnumerator *recipientsEnum;
|
2010-08-11 16:52:11 +02:00
|
|
|
NSMutableArray *elements;
|
|
|
|
|
|
|
|
NSString *recipient;
|
2008-07-09 17:43:48 +02:00
|
|
|
|
|
|
|
elements = [NSMutableArray array];
|
|
|
|
|
|
|
|
recipientsEnum = [recipients objectEnumerator];
|
2010-08-11 16:52:11 +02:00
|
|
|
|
2008-07-09 17:43:48 +02:00
|
|
|
while ((recipient = [recipientsEnum nextObject]))
|
|
|
|
if ([[recipient lowercaseString] hasPrefix: @"mailto:"])
|
|
|
|
{
|
2010-08-11 16:52:11 +02:00
|
|
|
[elements addObject: [self _caldavSuccessCodeWithRecipient: recipient]];
|
2008-07-08 17:42:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return elements;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) postCalDAVEventReplyTo: (NSArray *) recipients
|
2008-11-10 16:38:05 +01:00
|
|
|
from: (NSString *) originator
|
2008-07-08 17:42:40 +02:00
|
|
|
{
|
|
|
|
NSEnumerator *recipientsEnum;
|
2010-08-11 16:52:11 +02:00
|
|
|
NSMutableArray *elements;
|
|
|
|
NSString *recipient;
|
2008-07-08 17:42:40 +02:00
|
|
|
|
|
|
|
elements = [NSMutableArray array];
|
|
|
|
recipientsEnum = [recipients objectEnumerator];
|
2010-08-11 16:52:11 +02:00
|
|
|
|
2008-07-08 17:42:40 +02:00
|
|
|
while ((recipient = [recipientsEnum nextObject]))
|
|
|
|
if ([[recipient lowercaseString] hasPrefix: @"mailto:"])
|
|
|
|
{
|
2010-08-11 16:52:11 +02:00
|
|
|
[elements addObject: [self _caldavSuccessCodeWithRecipient: recipient]];
|
2008-07-08 17:42:40 +02:00
|
|
|
}
|
2008-07-05 00:25:27 +02:00
|
|
|
|
|
|
|
return elements;
|
|
|
|
}
|
|
|
|
|
2008-11-10 16:38:05 +01:00
|
|
|
//
|
2010-08-11 16:52:11 +02:00
|
|
|
//
|
2008-11-10 16:38:05 +01:00
|
|
|
//
|
2009-08-27 18:20:41 +02:00
|
|
|
- (NSException *) changeParticipationStatus: (NSString *) status
|
|
|
|
withDelegate: (iCalPerson *) delegate
|
2007-11-18 11:16:25 +01:00
|
|
|
{
|
2009-09-10 20:31:20 +02:00
|
|
|
return [self changeParticipationStatus: status
|
|
|
|
withDelegate: delegate
|
2009-08-27 18:20:41 +02:00
|
|
|
forRecurrenceId: nil];
|
2008-11-22 08:20:22 +01:00
|
|
|
}
|
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2009-08-11 18:52:10 +02:00
|
|
|
- (NSException *) changeParticipationStatus: (NSString *) _status
|
2009-08-27 18:20:41 +02:00
|
|
|
withDelegate: (iCalPerson *) delegate
|
2009-08-11 18:52:10 +02:00
|
|
|
forRecurrenceId: (NSCalendarDate *) _recurrenceId
|
2008-11-22 08:20:22 +01:00
|
|
|
{
|
|
|
|
iCalCalendar *calendar;
|
2007-11-18 11:16:25 +01:00
|
|
|
iCalEvent *event;
|
|
|
|
iCalPerson *attendee;
|
|
|
|
NSException *ex;
|
2009-10-28 18:48:22 +01:00
|
|
|
SOGoUser *ownerUser, *delegatedUser;
|
|
|
|
NSString *recurrenceTime, *delegatedUid;
|
2008-08-09 17:21:25 +02:00
|
|
|
|
2008-11-22 08:20:22 +01:00
|
|
|
event = nil;
|
2007-11-18 11:16:25 +01:00
|
|
|
ex = nil;
|
2009-10-28 18:48:22 +01:00
|
|
|
delegatedUser = nil;
|
2007-11-18 11:16:25 +01:00
|
|
|
|
2008-11-22 08:20:22 +01:00
|
|
|
calendar = [self calendar: NO secure: NO];
|
|
|
|
if (calendar)
|
|
|
|
{
|
|
|
|
if (_recurrenceId)
|
|
|
|
{
|
|
|
|
// If _recurrenceId is defined, find the specified occurence
|
|
|
|
// within the repeating vEvent.
|
|
|
|
recurrenceTime = [NSString stringWithFormat: @"%f", [_recurrenceId timeIntervalSince1970]];
|
2008-12-03 17:18:12 +01:00
|
|
|
event = (iCalEvent*)[self lookupOccurence: recurrenceTime];
|
2008-12-01 17:24:15 +01:00
|
|
|
|
|
|
|
if (event == nil)
|
|
|
|
// If no occurence found, create one
|
2008-12-03 17:18:12 +01:00
|
|
|
event = (iCalEvent*)[self newOccurenceWithID: recurrenceTime];
|
2008-11-22 08:20:22 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
// No specific occurence specified; return the first vEvent of
|
|
|
|
// the vCalendar.
|
2008-12-03 17:18:12 +01:00
|
|
|
event = (iCalEvent*)[calendar firstChildWithTag: [self componentTag]];
|
2008-11-22 08:20:22 +01:00
|
|
|
}
|
2007-11-18 11:16:25 +01:00
|
|
|
if (event)
|
|
|
|
{
|
2009-08-27 18:20:41 +02:00
|
|
|
// ownerUser will actually be the owner of the calendar
|
2009-09-10 20:31:20 +02:00
|
|
|
// where the participation change on the event occurs. The particpation
|
|
|
|
// change will be on the attendee corresponding to the ownerUser.
|
2009-08-25 23:28:24 +02:00
|
|
|
ownerUser = [SOGoUser userWithLogin: owner];
|
2009-08-27 18:20:41 +02:00
|
|
|
|
2010-05-05 15:56:19 +02:00
|
|
|
attendee = [event userAsAttendee: ownerUser];
|
2007-11-18 11:16:25 +01:00
|
|
|
if (attendee)
|
2009-09-10 20:31:20 +02:00
|
|
|
{
|
|
|
|
if (delegate
|
|
|
|
&& ![[delegate email] isEqualToString: [attendee delegatedTo]])
|
|
|
|
{
|
2009-10-28 18:48:22 +01:00
|
|
|
delegatedUid = [delegate uid];
|
|
|
|
if (delegatedUid)
|
|
|
|
delegatedUser = [SOGoUser userWithLogin: delegatedUid];
|
|
|
|
if (delegatedUser != nil && [event userIsOrganizer: delegatedUser])
|
|
|
|
ex = [NSException exceptionWithHTTPStatus: 403
|
|
|
|
reason: @"delegate is organizer"];
|
2010-05-05 15:56:19 +02:00
|
|
|
if ([event isAttendee: [[delegate email] rfc822Email]])
|
2009-09-10 20:31:20 +02:00
|
|
|
ex = [NSException exceptionWithHTTPStatus: 403
|
2010-05-05 15:56:19 +02:00
|
|
|
reason: @"delegate is a attendee"];
|
2009-11-29 05:19:32 +01:00
|
|
|
else if ([SOGoGroup groupWithEmail: [[delegate email] rfc822Email]
|
|
|
|
inDomain: [ownerUser domain]])
|
2009-09-10 20:31:20 +02:00
|
|
|
ex = [NSException exceptionWithHTTPStatus: 403
|
|
|
|
reason: @"delegate is a group"];
|
|
|
|
}
|
|
|
|
if (ex == nil)
|
|
|
|
ex = [self _handleAttendee: attendee
|
|
|
|
withDelegate: delegate
|
|
|
|
ownerUser: ownerUser
|
|
|
|
statusChange: _status
|
|
|
|
inEvent: event];
|
|
|
|
}
|
2007-11-18 11:16:25 +01:00
|
|
|
else
|
2008-11-22 08:20:22 +01:00
|
|
|
ex = [NSException exceptionWithHTTPStatus: 404 // Not Found
|
2009-09-10 20:31:20 +02:00
|
|
|
reason: @"user does not participate in this calendar event"];
|
2007-11-08 20:56:18 +01:00
|
|
|
}
|
|
|
|
else
|
2008-11-22 08:20:22 +01:00
|
|
|
ex = [NSException exceptionWithHTTPStatus: 500 // Server Error
|
2009-09-10 20:31:20 +02:00
|
|
|
reason: @"unable to parse event record"];
|
2008-11-22 08:20:22 +01:00
|
|
|
|
2007-11-18 11:16:25 +01:00
|
|
|
return ex;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2010-08-17 16:10:01 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
- (BOOL) _shouldScheduleEvent: (iCalPerson *) theOrganizer
|
|
|
|
{
|
|
|
|
NSString *v;
|
|
|
|
BOOL b;
|
|
|
|
|
|
|
|
b = YES;
|
|
|
|
|
|
|
|
if (theOrganizer && (v = [theOrganizer value: 0 ofAttribute: @"SCHEDULE-AGENT"]))
|
|
|
|
{
|
|
|
|
if ([v caseInsensitiveCompare: @"NONE"] == NSOrderedSame ||
|
|
|
|
[v caseInsensitiveCompare: @"CLIENT"] == NSOrderedSame)
|
|
|
|
b = NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-11 16:52:11 +02:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2008-07-17 23:12:43 +02:00
|
|
|
- (void) prepareDeleteOccurence: (iCalEvent *) occurence
|
2007-01-31 21:15:28 +01:00
|
|
|
{
|
2007-11-18 11:16:25 +01:00
|
|
|
iCalEvent *event;
|
2008-08-14 00:30:55 +02:00
|
|
|
SOGoUser *ownerUser, *currentUser;
|
2007-11-18 11:16:25 +01:00
|
|
|
NSArray *attendees;
|
2008-12-01 22:15:07 +01:00
|
|
|
NSCalendarDate *recurrenceId;
|
2010-08-11 16:52:11 +02:00
|
|
|
|
|
|
|
ownerUser = [SOGoUser userWithLogin: owner];
|
|
|
|
event = [self component: NO secure: NO];
|
|
|
|
|
2010-08-17 16:10:01 +02:00
|
|
|
if (![self _shouldScheduleEvent: [event organizer]])
|
|
|
|
return;
|
|
|
|
|
2010-08-11 16:52:11 +02:00
|
|
|
if (occurence == nil)
|
2007-11-18 11:16:25 +01:00
|
|
|
{
|
2010-08-11 16:52:11 +02:00
|
|
|
// No occurence specified; use the master event.
|
|
|
|
occurence = event;
|
|
|
|
recurrenceId = nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
// Retrieve this occurence ID.
|
|
|
|
recurrenceId = [occurence recurrenceId];
|
|
|
|
|
|
|
|
if ([event userIsOrganizer: ownerUser])
|
|
|
|
{
|
|
|
|
// The organizer deletes an occurence.
|
|
|
|
currentUser = [context activeUser];
|
|
|
|
attendees = [occurence attendeesWithoutUser: currentUser];
|
|
|
|
|
2008-12-04 00:08:37 +01:00
|
|
|
#warning Make sure this is correct ..
|
2010-08-11 16:52:11 +02:00
|
|
|
if (![attendees count] && event != occurence)
|
|
|
|
attendees = [event attendeesWithoutUser: currentUser];
|
|
|
|
|
|
|
|
if ([attendees count])
|
|
|
|
{
|
|
|
|
// Remove the event from all attendees calendars
|
|
|
|
// and send them an email.
|
|
|
|
[self _handleRemovedUsers: attendees
|
|
|
|
withRecurrenceId: recurrenceId];
|
|
|
|
[self sendEMailUsingTemplateNamed: @"Deletion"
|
|
|
|
forObject: [occurence itipEntryWithMethod: @"cancel"]
|
|
|
|
previousObject: nil
|
|
|
|
toAttendees: attendees];
|
|
|
|
[self sendReceiptEmailUsingTemplateNamed: @"Deletion"
|
|
|
|
forObject: occurence
|
|
|
|
to: attendees];
|
2007-11-18 11:16:25 +01:00
|
|
|
}
|
|
|
|
}
|
2010-08-11 16:52:11 +02:00
|
|
|
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
|
|
|
|
forRecurrenceId: recurrenceId];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
2006-10-31 19:54:56 +01:00
|
|
|
|
2010-01-22 17:33:35 +01:00
|
|
|
- (NSException *) prepareDelete
|
2008-07-17 23:12:43 +02:00
|
|
|
{
|
|
|
|
[self prepareDeleteOccurence: nil];
|
2010-01-22 17:33:35 +01:00
|
|
|
|
2010-08-19 19:40:28 +02:00
|
|
|
return [super prepareDelete];
|
2008-07-17 23:12:43 +02:00
|
|
|
}
|
|
|
|
|
2009-08-10 22:59:49 +02:00
|
|
|
- (NSDictionary *) _partStatsFromCalendar: (iCalCalendar *) calendar
|
2009-04-30 23:17:55 +02:00
|
|
|
{
|
2009-08-10 22:59:49 +02:00
|
|
|
NSMutableDictionary *partStats;
|
2009-04-30 23:17:55 +02:00
|
|
|
NSArray *allEvents;
|
2009-08-10 22:59:49 +02:00
|
|
|
int count, max;
|
|
|
|
iCalEvent *currentEvent;
|
2010-05-05 15:56:19 +02:00
|
|
|
iCalPerson *ownerAttendee;
|
2009-08-10 22:59:49 +02:00
|
|
|
NSString *key;
|
|
|
|
SOGoUser *ownerUser;
|
2009-05-01 13:35:02 +02:00
|
|
|
|
2009-08-25 23:28:24 +02:00
|
|
|
ownerUser = [SOGoUser userWithLogin: owner];
|
2009-04-30 23:17:55 +02:00
|
|
|
|
2009-08-10 22:59:49 +02:00
|
|
|
allEvents = [calendar events];
|
|
|
|
max = [allEvents count];
|
|
|
|
partStats = [NSMutableDictionary dictionaryWithCapacity: max];
|
|
|
|
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
currentEvent = [allEvents objectAtIndex: count];
|
2010-05-05 15:56:19 +02:00
|
|
|
ownerAttendee = [currentEvent userAsAttendee: ownerUser];
|
|
|
|
if (ownerAttendee)
|
2009-08-10 22:59:49 +02:00
|
|
|
{
|
|
|
|
if (count == 0)
|
|
|
|
key = @"master";
|
|
|
|
else
|
|
|
|
key = [[currentEvent recurrenceId] iCalFormattedDateTimeString];
|
2010-05-05 15:56:19 +02:00
|
|
|
[partStats setObject: ownerAttendee forKey: key];
|
2009-08-10 22:59:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return partStats;
|
|
|
|
}
|
|
|
|
|
2010-08-19 19:40:28 +02:00
|
|
|
#warning parseSingleFromSource is invoked far too many times: maybe we should use an additional ivar to store the new iCalendar
|
2009-08-10 22:59:49 +02:00
|
|
|
- (void) _setupResponseCalendarInRequest: (WORequest *) rq
|
|
|
|
{
|
|
|
|
iCalCalendar *calendar, *putCalendar;
|
|
|
|
NSData *newContent;
|
|
|
|
NSArray *keys;
|
|
|
|
NSDictionary *partStats, *newPartStats;
|
|
|
|
NSString *partStat, *key;
|
|
|
|
int count, max;
|
|
|
|
|
|
|
|
calendar = [self calendar: NO secure: NO];
|
|
|
|
partStats = [self _partStatsFromCalendar: calendar];
|
|
|
|
keys = [partStats allKeys];
|
|
|
|
max = [keys count];
|
|
|
|
if (max > 0)
|
|
|
|
{
|
|
|
|
putCalendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
|
|
|
|
newPartStats = [self _partStatsFromCalendar: putCalendar];
|
|
|
|
if ([keys isEqualToArray: [newPartStats allKeys]])
|
|
|
|
{
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
key = [keys objectAtIndex: count];
|
|
|
|
partStat = [[newPartStats objectForKey: key] partStat];
|
|
|
|
[[partStats objectForKey: key] setPartStat: partStat];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
newContent = [[calendar versitString]
|
|
|
|
dataUsingEncoding: [rq contentEncoding]];
|
|
|
|
[rq setContent: newContent];
|
|
|
|
}
|
2009-04-30 23:17:55 +02:00
|
|
|
|
2010-03-19 14:08:15 +01:00
|
|
|
- (void) _adjustTransparencyInRequest: (WORequest *) rq
|
|
|
|
{
|
|
|
|
iCalCalendar *calendar;
|
|
|
|
NSArray *allEvents;
|
|
|
|
iCalEvent *event;
|
|
|
|
int i;
|
|
|
|
BOOL modified;
|
|
|
|
|
|
|
|
calendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
|
|
|
|
allEvents = [calendar events];
|
|
|
|
modified = NO;
|
|
|
|
|
|
|
|
for (i = 0; i < [allEvents count]; i++)
|
|
|
|
{
|
|
|
|
event = [allEvents objectAtIndex: i];
|
|
|
|
|
|
|
|
if ([event isAllDay] && [event isOpaque])
|
|
|
|
{
|
|
|
|
[event setTransparency: @"TRANSPARENT"];
|
|
|
|
modified = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (modified)
|
|
|
|
[rq setContent: [[calendar versitString] dataUsingEncoding: [rq contentEncoding]]];
|
|
|
|
}
|
|
|
|
|
2009-08-10 22:59:49 +02:00
|
|
|
- (void) _decomposeGroupsInRequest: (WORequest *) rq
|
|
|
|
{
|
|
|
|
iCalCalendar *calendar;
|
|
|
|
NSArray *allEvents;
|
|
|
|
iCalEvent *event;
|
|
|
|
int i;
|
|
|
|
BOOL modified;
|
2009-05-01 13:35:02 +02:00
|
|
|
|
2009-08-10 22:59:49 +02:00
|
|
|
// If we decomposed at least one group, let's rewrite the content
|
|
|
|
// of the request. Otherwise, leave it as is in case this rewrite
|
|
|
|
// isn't totaly lossless.
|
|
|
|
calendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
|
2009-04-30 23:17:55 +02:00
|
|
|
|
2009-08-10 22:59:49 +02:00
|
|
|
// The algorithm is pretty straightforward:
|
2009-04-30 23:17:55 +02:00
|
|
|
//
|
|
|
|
// We get all events
|
|
|
|
// We get all attendees
|
|
|
|
// If some are groups, we decompose them
|
|
|
|
// We regenerate the iCalendar string
|
|
|
|
//
|
|
|
|
allEvents = [calendar events];
|
2009-08-10 22:59:49 +02:00
|
|
|
modified = NO;
|
2009-04-30 23:17:55 +02:00
|
|
|
|
|
|
|
for (i = 0; i < [allEvents count]; i++)
|
|
|
|
{
|
|
|
|
event = [allEvents objectAtIndex: i];
|
2009-08-10 22:59:49 +02:00
|
|
|
modified |= [self expandGroupsInEvent: event];
|
2009-04-30 23:17:55 +02:00
|
|
|
}
|
|
|
|
|
2009-05-01 13:35:02 +02:00
|
|
|
// If we decomposed at least one group, let's rewrite the content
|
|
|
|
// of the request. Otherwise, leave it as is in case this rewrite
|
|
|
|
// isn't totaly lossless.
|
2009-08-10 22:59:49 +02:00
|
|
|
if (modified)
|
2009-05-01 13:35:02 +02:00
|
|
|
[rq setContent: [[calendar versitString] dataUsingEncoding: [rq contentEncoding]]];
|
2009-08-10 22:59:49 +02:00
|
|
|
}
|
|
|
|
|
2010-08-11 16:52:11 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// If theRecurrenceId is nil, it returns immediately the
|
|
|
|
// first event that has a RECURRENCE-ID.
|
|
|
|
//
|
|
|
|
// Otherwise, it return values that matches.
|
|
|
|
//
|
|
|
|
- (iCalEvent *) _eventFromRecurrenceId: (NSCalendarDate *) theRecurrenceId
|
|
|
|
events: (NSArray *) allEvents
|
|
|
|
{
|
|
|
|
iCalEvent *event;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < [allEvents count]; i++)
|
|
|
|
{
|
|
|
|
event = [allEvents objectAtIndex: i];
|
|
|
|
|
|
|
|
if ([event recurrenceId] && !theRecurrenceId)
|
|
|
|
return event;
|
|
|
|
|
|
|
|
if ([event recurrenceId] && [[event recurrenceId] compare: theRecurrenceId] == NSOrderedSame)
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
- (NSCalendarDate *) _addedExDate: (iCalEvent *) oldEvent
|
|
|
|
newEvent: (iCalEvent *) newEvent
|
|
|
|
{
|
|
|
|
NSArray *oldExDates, *newExDates;
|
|
|
|
NSMutableArray *dates;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
dates = [NSMutableArray array];
|
|
|
|
|
|
|
|
newExDates = [newEvent childrenWithTag: @"exdate"];
|
|
|
|
for (i = 0; i < [newExDates count]; i++)
|
|
|
|
[dates addObject: [[newExDates objectAtIndex: i] dateTime]];
|
|
|
|
|
|
|
|
oldExDates = [oldEvent childrenWithTag: @"exdate"];
|
|
|
|
for (i = 0; i < [oldExDates count]; i++)
|
|
|
|
[dates removeObject: [[oldExDates objectAtIndex: i] dateTime]];
|
|
|
|
|
|
|
|
return [dates lastObject];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
- (id) DELETEAction: (WOContext *) _ctx
|
|
|
|
{
|
2010-08-19 19:40:28 +02:00
|
|
|
[self prepareDelete];
|
2010-08-11 16:52:11 +02:00
|
|
|
return [super DELETEAction: _ctx];
|
|
|
|
}
|
|
|
|
|
2009-08-10 22:59:49 +02:00
|
|
|
//
|
|
|
|
// If we see "X-SOGo: NoGroupsDecomposition" in the HTTP headers, we
|
|
|
|
// simply invoke super's PUTAction.
|
|
|
|
//
|
2010-03-19 14:08:15 +01:00
|
|
|
// We also check if we must force transparency on all day events
|
|
|
|
// from iPhone clients.
|
|
|
|
//
|
2009-08-10 22:59:49 +02:00
|
|
|
- (id) PUTAction: (WOContext *) _ctx
|
|
|
|
{
|
|
|
|
NSArray *roles;
|
2010-03-19 14:08:15 +01:00
|
|
|
WORequest *rq;
|
2010-08-11 16:52:11 +02:00
|
|
|
id response;
|
2010-08-19 19:40:28 +02:00
|
|
|
|
2009-08-10 22:59:49 +02:00
|
|
|
rq = [_ctx request];
|
2010-08-11 16:52:11 +02:00
|
|
|
roles = [[context activeUser] rolesForObject: self inContext: context];
|
2010-08-19 19:40:28 +02:00
|
|
|
|
2010-08-11 16:52:11 +02:00
|
|
|
//
|
|
|
|
// We check if we gave only the "Respond To" right and someone is actually
|
|
|
|
// responding to one of our invitation. In this case, _setupResponseCalendarInRequest
|
|
|
|
// will only take the new attendee status and actually discard any other modifications.
|
|
|
|
//
|
2009-08-10 22:59:49 +02:00
|
|
|
if ([roles containsObject: @"ComponentResponder"]
|
|
|
|
&& ![roles containsObject: @"ComponentModifier"])
|
|
|
|
[self _setupResponseCalendarInRequest: rq];
|
|
|
|
else
|
|
|
|
{
|
2010-03-19 14:08:15 +01:00
|
|
|
SOGoUser *user;
|
|
|
|
|
|
|
|
user = [SOGoUser userWithLogin: owner];
|
|
|
|
|
2009-08-10 22:59:49 +02:00
|
|
|
if (![[rq headersForKey: @"X-SOGo"]
|
|
|
|
containsObject: @"NoGroupsDecomposition"])
|
|
|
|
[self _decomposeGroupsInRequest: rq];
|
2010-03-19 14:08:15 +01:00
|
|
|
|
|
|
|
if ([[user domainDefaults] iPhoneForceAllDayTransparency]
|
|
|
|
&& [rq isIPhone])
|
|
|
|
{
|
|
|
|
[self _adjustTransparencyInRequest: rq];
|
|
|
|
}
|
2009-08-10 22:59:49 +02:00
|
|
|
}
|
2009-05-01 13:35:02 +02:00
|
|
|
|
2010-08-11 16:52:11 +02:00
|
|
|
//
|
|
|
|
// We first check if it's a new event
|
|
|
|
//
|
|
|
|
if ([self isNew])
|
|
|
|
{
|
|
|
|
iCalCalendar *calendar;
|
|
|
|
SOGoUser *ownerUser;
|
2010-08-17 16:10:01 +02:00
|
|
|
iCalEvent *event;
|
|
|
|
|
|
|
|
BOOL scheduling;
|
2010-08-11 16:52:11 +02:00
|
|
|
|
|
|
|
calendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
|
2010-08-19 19:40:28 +02:00
|
|
|
|
2010-08-11 16:52:11 +02:00
|
|
|
event = [[calendar events] objectAtIndex: 0];
|
|
|
|
ownerUser = [SOGoUser userWithLogin: owner];
|
2010-08-17 16:10:01 +02:00
|
|
|
scheduling = [self _shouldScheduleEvent: [event organizer]];
|
2010-08-17 16:30:09 +02:00
|
|
|
|
2010-08-11 16:52:11 +02:00
|
|
|
//
|
|
|
|
// New event and we're the organizer -- send invitation to all attendees
|
|
|
|
//
|
2010-08-17 16:10:01 +02:00
|
|
|
if (scheduling && [event userIsOrganizer: ownerUser])
|
2010-08-11 16:52:11 +02:00
|
|
|
{
|
|
|
|
NSArray *attendees;
|
|
|
|
|
|
|
|
attendees = [event attendeesWithoutUser: ownerUser];
|
|
|
|
if ([attendees count])
|
|
|
|
{
|
|
|
|
[self _handleAddedUsers: attendees fromEvent: event];
|
|
|
|
[self sendEMailUsingTemplateNamed: @"Invitation"
|
|
|
|
forObject: [event itipEntryWithMethod: @"request"]
|
|
|
|
previousObject: nil
|
|
|
|
toAttendees: attendees];
|
|
|
|
[self sendReceiptEmailUsingTemplateNamed: @"Invitation"
|
|
|
|
forObject: event to: attendees];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// We aren't the organizer but we're an attendee. That can happen when
|
|
|
|
// we receive an external invitation (IMIP/ITIP) and we accept it
|
|
|
|
// from a CUA - it gets added to a specific CalDAV calendar using a PUT
|
|
|
|
//
|
2010-08-17 16:10:01 +02:00
|
|
|
else if (scheduling && [event userIsAttendee: ownerUser])
|
2010-08-11 16:52:11 +02:00
|
|
|
{
|
|
|
|
[self sendIMIPReplyForEvent: event
|
|
|
|
from: ownerUser
|
|
|
|
to: [event organizer]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iCalCalendar *oldCalendar, *newCalendar;
|
|
|
|
iCalEvent *oldEvent, *newEvent;
|
|
|
|
iCalEventChanges *changes;
|
|
|
|
NSMutableArray *oldEvents, *newEvents;
|
|
|
|
NSCalendarDate *recurrenceId;
|
|
|
|
NSException *error;
|
|
|
|
BOOL master;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
//
|
|
|
|
// We must check for etag changes prior doing anything since an attendee could
|
|
|
|
// have changed its participation status and the organizer didn't get the
|
|
|
|
// copy and is trying to do a modification to the event.
|
|
|
|
//
|
|
|
|
error = [self matchesRequestConditionInContext: _ctx];
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
return (WOResponse *)error;
|
|
|
|
|
|
|
|
//
|
|
|
|
// We check what has changed in the event and react accordingly.
|
|
|
|
//
|
|
|
|
newCalendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
|
|
|
|
newEvents = [NSMutableArray arrayWithArray: [newCalendar events]];
|
|
|
|
|
|
|
|
oldCalendar = [self calendar: NO secure: NO];
|
|
|
|
oldEvents = [NSMutableArray arrayWithArray: [oldCalendar events]];
|
|
|
|
recurrenceId = nil;
|
|
|
|
master = NO;
|
|
|
|
|
|
|
|
for (i = [newEvents count]-1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
newEvent = [newEvents objectAtIndex: i];
|
|
|
|
|
|
|
|
if ([newEvent recurrenceId])
|
|
|
|
{
|
|
|
|
// Find the corresponding RECURRENCE-ID in the old calendar
|
|
|
|
// If not present, we assume it was created before the PUT
|
|
|
|
oldEvent = [self _eventFromRecurrenceId: [newEvent recurrenceId]
|
|
|
|
events: oldEvents];
|
2011-04-01 20:55:02 +02:00
|
|
|
|
|
|
|
if (oldEvent == nil)
|
|
|
|
{
|
|
|
|
NSString *recurrenceTime;
|
|
|
|
recurrenceTime = [NSString stringWithFormat: @"%f", [[newEvent recurrenceId] timeIntervalSince1970]];
|
|
|
|
oldEvent = (iCalEvent *)[self newOccurenceWithID: recurrenceTime];
|
|
|
|
}
|
2010-08-11 16:52:11 +02:00
|
|
|
|
|
|
|
// If present, we look for changes
|
|
|
|
changes = [iCalEventChanges changesFromEvent: oldEvent toEvent: newEvent];
|
|
|
|
|
|
|
|
if ([changes sequenceShouldBeIncreased] | [changes hasAttendeeChanges])
|
|
|
|
{
|
|
|
|
// We found a RECURRENCE-ID with changes, we consider it
|
|
|
|
recurrenceId = [newEvent recurrenceId];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[newEvents removeObject: oldEvent];
|
|
|
|
[oldEvents removeObject: newEvent];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
oldEvent = nil;
|
|
|
|
newEvent = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no changes were observed, let's see if we have any left overs
|
|
|
|
// in the oldEvents or in the newEvents array
|
|
|
|
if (!oldEvent && !newEvent)
|
|
|
|
{
|
|
|
|
// We check if we only have to deal with the MASTER event
|
|
|
|
if ([newEvents count] == [oldEvents count])
|
|
|
|
{
|
|
|
|
oldEvent = [oldEvents objectAtIndex: 0];
|
|
|
|
newEvent = [newEvents objectAtIndex: 0];
|
|
|
|
master = YES;
|
|
|
|
}
|
|
|
|
// A RECURRENCE-ID was added
|
|
|
|
else if ([newEvents count] > [oldEvents count])
|
|
|
|
{
|
|
|
|
oldEvent = nil;
|
|
|
|
newEvent = [self _eventFromRecurrenceId: nil events: newEvents];
|
|
|
|
recurrenceId = [newEvent recurrenceId];
|
|
|
|
}
|
|
|
|
// A RECURRENCE-ID was removed
|
|
|
|
else
|
|
|
|
{
|
|
|
|
oldEvent = [self _eventFromRecurrenceId: nil events: oldEvents];
|
|
|
|
newEvent = nil;
|
|
|
|
recurrenceId = [oldEvent recurrenceId];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We check if the PUT call is actually an PART-STATE change
|
|
|
|
// from one of the attendees - here's the logic :
|
|
|
|
//
|
|
|
|
// if owner == organizer
|
|
|
|
//
|
|
|
|
// if [context activeUser] == organizer
|
|
|
|
// [send the invitation update]
|
|
|
|
// else
|
|
|
|
// [react on SENT-BY as someone else is acting for the organizer]
|
|
|
|
//
|
|
|
|
//
|
|
|
|
if ([[newEvent attendees] count] || [[oldEvent attendees] count])
|
|
|
|
{
|
2011-03-23 21:14:33 +01:00
|
|
|
NSString *uid;
|
|
|
|
|
|
|
|
if (master)
|
|
|
|
uid = [[newEvent organizer] uid];
|
|
|
|
else
|
|
|
|
uid = [[[[[newEvent parent] events] objectAtIndex: 0] organizer] uid];
|
2011-04-01 20:55:02 +02:00
|
|
|
|
2011-03-23 21:14:33 +01:00
|
|
|
if ([uid caseInsensitiveCompare: owner] == NSOrderedSame)
|
2010-08-11 16:52:11 +02:00
|
|
|
{
|
|
|
|
[self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent];
|
|
|
|
|
|
|
|
// A RECURRENCE-ID was removed so there has to be a change in the master event
|
|
|
|
// We could also have an EXDATE added in the master component of the attendees
|
|
|
|
// so we always compare the MASTER event.
|
|
|
|
if (!master)
|
|
|
|
{
|
|
|
|
newEvent = [newEvents objectAtIndex: 0];
|
|
|
|
oldEvent = [oldEvents objectAtIndex: 0];
|
|
|
|
[self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// else => attendee is responding
|
|
|
|
//
|
|
|
|
// if [context activeUser] == attendee
|
|
|
|
// [we change the PART-STATE]
|
|
|
|
// else
|
|
|
|
// [react on SENT-BY as someone else is acting for the attendee]
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iCalPerson *attendee, *delegate;
|
|
|
|
NSString *delegateEmail;
|
|
|
|
|
|
|
|
attendee = [newEvent userAsAttendee: [SOGoUser userWithLogin: owner]];
|
|
|
|
|
|
|
|
delegate = nil;
|
|
|
|
delegateEmail = [attendee delegatedTo];
|
|
|
|
|
|
|
|
if ([delegateEmail length])
|
|
|
|
{
|
|
|
|
delegateEmail = [delegateEmail substringFromIndex: 7];
|
|
|
|
if ([delegateEmail length])
|
|
|
|
delegate = [newEvent findAttendeeWithEmail: delegateEmail];
|
|
|
|
}
|
|
|
|
|
|
|
|
changes = [iCalEventChanges changesFromEvent: oldEvent toEvent: newEvent];
|
|
|
|
|
|
|
|
// The current user deletes the occurence; let the organizer know that
|
|
|
|
// the user has declined this occurence.
|
|
|
|
if ([[changes updatedProperties] containsObject: @"exdate"])
|
|
|
|
{
|
2011-04-01 20:55:02 +02:00
|
|
|
[self changeParticipationStatus: @"DECLINED"
|
2011-03-23 21:14:33 +01:00
|
|
|
withDelegate: nil // FIXME (specify delegate?)
|
2010-08-11 16:52:11 +02:00
|
|
|
forRecurrenceId: [self _addedExDate: oldEvent newEvent: newEvent]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[self changeParticipationStatus: [attendee partStat]
|
2011-04-01 20:55:02 +02:00
|
|
|
withDelegate: delegate
|
|
|
|
forRecurrenceId: recurrenceId];
|
2010-08-11 16:52:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This will save the event into the database and also handle
|
|
|
|
// E-Tags properly, as well as content versioning.
|
|
|
|
response = [super PUTAction: _ctx];
|
|
|
|
|
|
|
|
return response;
|
2009-04-30 23:17:55 +02:00
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
@end /* SOGoAppointmentObject */
|