2006-06-15 21:34:10 +02:00
|
|
|
/*
|
2011-01-14 03:54:33 +01:00
|
|
|
Copyright (C) 2007-2011 Inverse inc.
|
2008-12-30 20:48:33 +01:00
|
|
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
2006-06-15 21:34:10 +02:00
|
|
|
|
|
|
|
This file is part of OpenGroupware.org.
|
|
|
|
|
|
|
|
OGo is free software; you can redistribute it and/or modify it under
|
|
|
|
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.
|
|
|
|
|
|
|
|
OGo 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 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.
|
|
|
|
*/
|
|
|
|
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <Foundation/NSCalendarDate.h>
|
2008-07-04 18:06:09 +02:00
|
|
|
#import <Foundation/NSDictionary.h>
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <Foundation/NSEnumerator.h>
|
2008-12-30 15:47:58 +01:00
|
|
|
#import <Foundation/NSTimeZone.h>
|
2008-03-18 18:26:34 +01:00
|
|
|
#import <Foundation/NSURL.h>
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <Foundation/NSValue.h>
|
|
|
|
|
|
|
|
#import <NGObjWeb/NSException+HTTP.h>
|
|
|
|
#import <NGObjWeb/SoObject+SoDAV.h>
|
|
|
|
#import <NGObjWeb/WOContext+SoObjects.h>
|
2007-02-09 22:21:35 +01:00
|
|
|
#import <NGObjWeb/WOMessage.h>
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <NGObjWeb/WORequest.h>
|
|
|
|
#import <NGObjWeb/WOResponse.h>
|
|
|
|
#import <NGExtensions/NSString+misc.h>
|
|
|
|
#import <GDLContentStore/GCSFolder.h>
|
2009-06-18 22:58:46 +02:00
|
|
|
#import <DOM/DOMElement.h>
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <DOM/DOMProtocols.h>
|
|
|
|
#import <EOControl/EOQualifier.h>
|
2008-06-30 20:52:20 +02:00
|
|
|
#import <EOControl/EOSortOrdering.h>
|
2007-11-26 18:40:44 +01:00
|
|
|
#import <NGCards/iCalCalendar.h>
|
2010-04-21 16:44:42 +02:00
|
|
|
#import <NGCards/iCalEvent.h>
|
2008-06-30 20:52:20 +02:00
|
|
|
#import <NGCards/iCalFreeBusy.h>
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <NGCards/iCalDateTime.h>
|
|
|
|
#import <NGCards/iCalPerson.h>
|
|
|
|
#import <NGCards/iCalRecurrenceCalculator.h>
|
2009-10-21 23:17:11 +02:00
|
|
|
#import <NGCards/iCalTimeZone.h>
|
2011-01-14 03:54:33 +01:00
|
|
|
#import <NGCards/iCalTimeZonePeriod.h>
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <NGCards/NSString+NGCards.h>
|
2006-10-11 20:48:25 +02:00
|
|
|
#import <NGExtensions/NGCalendarDateRange.h>
|
2007-08-07 20:37:31 +02:00
|
|
|
#import <NGExtensions/NSNull+misc.h>
|
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
2007-03-10 00:10:43 +01:00
|
|
|
#import <SaxObjC/XMLNamespaces.h>
|
2006-10-11 20:48:25 +02:00
|
|
|
|
2009-06-18 22:58:46 +02:00
|
|
|
#import <SOGo/DOMNode+SOGo.h>
|
2008-05-03 01:08:15 +02:00
|
|
|
#import <SOGo/NSArray+Utilities.h>
|
2009-11-29 05:19:32 +01:00
|
|
|
#import <SOGo/NSDictionary+Utilities.h>
|
2008-05-03 01:08:15 +02:00
|
|
|
#import <SOGo/NSObject+DAV.h>
|
|
|
|
#import <SOGo/NSString+Utilities.h>
|
2008-01-16 19:57:58 +01:00
|
|
|
#import <SOGo/SOGoCache.h>
|
2009-11-29 05:19:32 +01:00
|
|
|
#import <SOGo/SOGoDomainDefaults.h>
|
2006-12-14 22:20:13 +01:00
|
|
|
#import <SOGo/SOGoPermissions.h>
|
2007-03-07 22:27:19 +01:00
|
|
|
#import <SOGo/SOGoUser.h>
|
2009-11-29 05:19:32 +01:00
|
|
|
#import <SOGo/SOGoUserDefaults.h>
|
|
|
|
#import <SOGo/SOGoUserSettings.h>
|
2008-06-30 20:52:20 +02:00
|
|
|
#import <SOGo/SOGoUserFolder.h>
|
2009-11-29 05:19:32 +01:00
|
|
|
#import <SOGo/SOGoUserManager.h>
|
2008-05-03 01:08:15 +02:00
|
|
|
#import <SOGo/SOGoWebDAVAclManager.h>
|
2009-06-09 22:00:28 +02:00
|
|
|
#import <SOGo/SOGoWebDAVValue.h>
|
2009-07-01 21:27:44 +02:00
|
|
|
#import <SOGo/WORequest+SOGo.h>
|
2010-01-15 00:19:19 +01:00
|
|
|
#import <SOGo/WOResponse+SOGo.h>
|
2006-11-02 22:53:27 +01:00
|
|
|
|
2010-04-21 16:35:58 +02:00
|
|
|
#import "iCalRepeatableEntityObject+SOGo.h"
|
2009-07-20 20:29:09 +02:00
|
|
|
#import "iCalPerson+SOGo.h"
|
2006-09-27 00:27:34 +02:00
|
|
|
#import "SOGoAppointmentObject.h"
|
2007-11-07 16:58:43 +01:00
|
|
|
#import "SOGoAppointmentFolders.h"
|
2008-06-30 20:52:20 +02:00
|
|
|
#import "SOGoFreeBusyObject.h"
|
2006-10-11 20:48:25 +02:00
|
|
|
#import "SOGoTaskObject.h"
|
|
|
|
|
|
|
|
#import "SOGoAppointmentFolder.h"
|
2006-09-27 00:27:34 +02:00
|
|
|
|
2008-04-22 01:03:48 +02:00
|
|
|
#define defaultColor @"#AAAAAA"
|
|
|
|
|
2010-08-12 16:02:21 +02:00
|
|
|
@interface SOGoGCSFolder (SOGoPrivate)
|
|
|
|
|
|
|
|
- (void) appendObject: (NSDictionary *) object
|
|
|
|
properties: (NSString **) properties
|
|
|
|
count: (unsigned int) propertiesCount
|
|
|
|
withBaseURL: (NSString *) baseURL
|
|
|
|
toBuffer: (NSMutableString *) r;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
@implementation SOGoAppointmentFolder
|
|
|
|
|
2008-06-30 20:52:20 +02:00
|
|
|
static NSNumber *sharedYes = nil;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
2009-07-07 22:57:00 +02:00
|
|
|
static BOOL didInit = NO;
|
2009-11-29 05:19:32 +01:00
|
|
|
|
2009-06-03 23:38:46 +02:00
|
|
|
if (!didInit)
|
|
|
|
{
|
|
|
|
didInit = YES;
|
|
|
|
sharedYes = [[NSNumber numberWithBool: YES] retain];
|
2009-11-29 05:19:32 +01:00
|
|
|
[iCalEntityObject initializeSOGoExtensions];
|
2009-06-03 23:38:46 +02:00
|
|
|
}
|
2007-04-11 21:08:58 +02:00
|
|
|
}
|
|
|
|
|
2008-05-03 01:08:15 +02:00
|
|
|
+ (SOGoWebDAVAclManager *) webdavAclManager
|
|
|
|
{
|
2008-12-15 23:27:45 +01:00
|
|
|
static SOGoWebDAVAclManager *aclManager = nil;
|
2008-06-30 20:52:20 +02:00
|
|
|
NSString *nsI;
|
2008-05-03 01:08:15 +02:00
|
|
|
|
2008-07-29 18:36:16 +02:00
|
|
|
if (!aclManager)
|
2008-05-03 01:08:15 +02:00
|
|
|
{
|
|
|
|
nsI = @"urn:inverse:params:xml:ns:inverse-dav";
|
|
|
|
|
2008-07-29 18:36:16 +02:00
|
|
|
aclManager = [SOGoWebDAVAclManager new];
|
|
|
|
[aclManager registerDAVPermission: davElement (@"read", XMLNS_WEBDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: YES
|
|
|
|
withEquivalent: SoPerm_WebDAVAccess
|
|
|
|
asChildOf: davElement (@"all", XMLNS_WEBDAV)];
|
|
|
|
[aclManager
|
|
|
|
registerDAVPermission: davElement (@"read-current-user-privilege-set", XMLNS_WEBDAV)
|
|
|
|
abstract: YES
|
|
|
|
withEquivalent: SoPerm_WebDAVAccess
|
|
|
|
asChildOf: davElement (@"read", XMLNS_WEBDAV)];
|
2010-01-15 00:19:19 +01:00
|
|
|
[aclManager registerDAVPermission: davElement (@"read-free-busy", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: SOGoCalendarPerm_ReadFreeBusy
|
|
|
|
asChildOf: davElement (@"all", XMLNS_WEBDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"write", XMLNS_WEBDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: YES
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"all", XMLNS_WEBDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"bind", XMLNS_WEBDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
|
|
|
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"schedule",
|
|
|
|
XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"bind", XMLNS_WEBDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"schedule-post",
|
|
|
|
XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-post-vevent", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-post-vtodo", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-post-vjournal", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-post-vfreebusy", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"schedule-deliver",
|
|
|
|
XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-deliver-vevent", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-deliver-vtodo", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-deliver-vjournal", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-deliver-vfreebusy", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"schedule-respond",
|
|
|
|
XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-respond-vevent", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-respond", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission:
|
|
|
|
davElement (@"schedule-respond-vtodo", XMLNS_CALDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"schedule-respond", XMLNS_CALDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"unbind", XMLNS_WEBDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: SoPerm_DeleteObjects
|
|
|
|
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager
|
2008-06-30 20:52:20 +02:00
|
|
|
registerDAVPermission: davElement (@"write-properties", XMLNS_WEBDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: SoPerm_ChangePermissions /* hackish */
|
|
|
|
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager
|
2008-06-30 20:52:20 +02:00
|
|
|
registerDAVPermission: davElement (@"write-content", XMLNS_WEBDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: NO
|
|
|
|
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
|
|
|
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"admin", nsI)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: YES
|
|
|
|
withEquivalent: nil
|
|
|
|
asChildOf: davElement (@"all", XMLNS_WEBDAV)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"read-acl", XMLNS_WEBDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: YES
|
|
|
|
withEquivalent: SOGoPerm_ReadAcls
|
|
|
|
asChildOf: davElement (@"admin", nsI)];
|
2008-07-29 18:36:16 +02:00
|
|
|
[aclManager registerDAVPermission: davElement (@"write-acl", XMLNS_WEBDAV)
|
2010-02-02 22:26:23 +01:00
|
|
|
abstract: YES
|
|
|
|
withEquivalent: SoPerm_ChangePermissions
|
|
|
|
asChildOf: davElement (@"admin", nsI)];
|
2008-05-03 01:08:15 +02:00
|
|
|
}
|
|
|
|
|
2008-07-29 18:36:16 +02:00
|
|
|
return aclManager;
|
2008-05-03 01:08:15 +02:00
|
|
|
}
|
|
|
|
|
2007-04-11 21:08:58 +02:00
|
|
|
- (id) initWithName: (NSString *) name
|
|
|
|
inContainer: (id) newContainer
|
|
|
|
{
|
2009-11-29 05:19:32 +01:00
|
|
|
SOGoUser *user;
|
2007-04-11 21:08:58 +02:00
|
|
|
if ((self = [super initWithName: name inContainer: newContainer]))
|
|
|
|
{
|
2009-11-29 05:19:32 +01:00
|
|
|
user = [context activeUser];
|
|
|
|
timeZone = [[user userDefaults] timeZone];
|
2007-11-26 18:40:44 +01:00
|
|
|
aclMatrix = [NSMutableDictionary new];
|
|
|
|
stripFields = nil;
|
|
|
|
uidToFilename = nil;
|
2009-06-04 02:40:21 +02:00
|
|
|
memset (userCanAccessObjectsClassifiedAs, NO,
|
|
|
|
iCalAccessClassCount * sizeof (BOOL));
|
2009-11-29 05:19:32 +01:00
|
|
|
|
|
|
|
davCalendarStartTimeLimit
|
|
|
|
= [[user domainDefaults] davCalendarStartTimeLimit];
|
|
|
|
davTimeLimitSeconds = davCalendarStartTimeLimit * 86400;
|
|
|
|
/* 86400 / 2 = 43200. We hardcode that value in order to avoid
|
|
|
|
integer and float confusion. */
|
|
|
|
davTimeHalfLimitSeconds = davCalendarStartTimeLimit * 43200;
|
2007-04-11 21:08:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
2007-11-26 18:40:44 +01:00
|
|
|
[aclMatrix release];
|
|
|
|
[stripFields release];
|
2007-04-11 21:08:58 +02:00
|
|
|
[uidToFilename release];
|
2006-06-15 21:34:10 +02:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (Class) objectClassForComponentName: (NSString *) componentName
|
|
|
|
{
|
|
|
|
Class objectClass;
|
|
|
|
|
|
|
|
if ([componentName isEqualToString: @"vevent"])
|
|
|
|
objectClass = [SOGoAppointmentObject class];
|
|
|
|
else if ([componentName isEqualToString: @"vtodo"])
|
|
|
|
objectClass = [SOGoTaskObject class];
|
|
|
|
else
|
|
|
|
objectClass = Nil;
|
|
|
|
|
|
|
|
return objectClass;
|
|
|
|
}
|
|
|
|
|
2008-04-22 01:03:48 +02:00
|
|
|
- (NSString *) calendarColor
|
|
|
|
{
|
|
|
|
NSString *color;
|
|
|
|
|
2010-03-10 22:53:26 +01:00
|
|
|
color = [self folderPropertyValueInCategory: @"FolderColors"];
|
2008-04-22 01:03:48 +02:00
|
|
|
if (!color)
|
|
|
|
color = defaultColor;
|
|
|
|
|
|
|
|
return color;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setCalendarColor: (NSString *) newColor
|
|
|
|
{
|
2010-03-10 22:53:26 +01:00
|
|
|
if (![newColor length])
|
|
|
|
newColor = nil;
|
|
|
|
|
|
|
|
[self setFolderPropertyValue: newColor
|
|
|
|
inCategory: @"FolderColors"];
|
2008-04-22 01:03:48 +02:00
|
|
|
}
|
|
|
|
|
2009-07-21 20:06:55 +02:00
|
|
|
- (BOOL) showCalendarAlarms
|
|
|
|
{
|
2010-03-10 22:53:26 +01:00
|
|
|
NSNumber *showAlarms;
|
|
|
|
|
|
|
|
showAlarms = [self folderPropertyValueInCategory: @"FolderShowAlarms"];
|
|
|
|
|
|
|
|
return (showAlarms ? [showAlarms boolValue] : YES);
|
2009-07-21 20:06:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setShowCalendarAlarms: (BOOL) new
|
|
|
|
{
|
2010-03-10 22:53:26 +01:00
|
|
|
NSNumber *showAlarms;
|
|
|
|
|
2009-08-18 03:03:05 +02:00
|
|
|
if (new)
|
2010-03-10 22:53:26 +01:00
|
|
|
showAlarms = nil;
|
2009-08-18 03:03:05 +02:00
|
|
|
else
|
2010-03-10 22:53:26 +01:00
|
|
|
showAlarms = [NSNumber numberWithBool: NO];
|
|
|
|
|
|
|
|
[self setFolderPropertyValue: showAlarms
|
|
|
|
inCategory: @"FolderShowAlarms"];
|
2009-07-21 20:06:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) showCalendarTasks
|
|
|
|
{
|
2010-03-10 22:53:26 +01:00
|
|
|
NSNumber *showTasks;
|
|
|
|
|
|
|
|
showTasks = [self folderPropertyValueInCategory: @"FolderShowTasks"];
|
|
|
|
|
|
|
|
return (showTasks ? [showTasks boolValue] : YES);
|
2009-07-21 20:06:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setShowCalendarTasks: (BOOL) new
|
|
|
|
{
|
2010-03-10 22:53:26 +01:00
|
|
|
NSNumber *showTasks;
|
|
|
|
|
|
|
|
/* the default value is "YES", so we keep only those with a value of "NO"... */
|
2009-08-18 03:03:05 +02:00
|
|
|
if (new)
|
2010-03-10 22:53:26 +01:00
|
|
|
showTasks = nil;
|
2009-08-18 03:03:05 +02:00
|
|
|
else
|
2010-03-10 22:53:26 +01:00
|
|
|
showTasks = [NSNumber numberWithBool: NO];
|
|
|
|
|
|
|
|
[self setFolderPropertyValue: showTasks
|
|
|
|
inCategory: @"FolderShowTasks"];
|
2009-07-21 20:06:55 +02:00
|
|
|
}
|
|
|
|
|
2008-06-20 16:52:40 +02:00
|
|
|
- (NSString *) syncTag
|
|
|
|
{
|
|
|
|
NSString *syncTag;
|
|
|
|
|
2010-03-10 22:53:26 +01:00
|
|
|
syncTag = [self folderPropertyValueInCategory: @"FolderSyncTags"];
|
2008-06-20 16:52:40 +02:00
|
|
|
if (!syncTag)
|
|
|
|
syncTag = @"";
|
|
|
|
|
|
|
|
return syncTag;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setSyncTag: (NSString *) newSyncTag
|
|
|
|
{
|
2010-03-10 22:53:26 +01:00
|
|
|
// Check for duplicated tags
|
|
|
|
SOGoUserSettings *settings;
|
|
|
|
NSDictionary *syncTags;
|
|
|
|
NSArray *values;
|
|
|
|
|
2009-08-18 03:03:05 +02:00
|
|
|
if ([newSyncTag length])
|
2008-06-20 16:52:40 +02:00
|
|
|
{
|
2009-08-18 03:03:05 +02:00
|
|
|
settings = [[context activeUser] userSettings];
|
2010-03-10 22:53:26 +01:00
|
|
|
syncTags = [[settings objectForKey: @"Calendar"]
|
|
|
|
objectForKey: @"FolderSyncTags"];
|
|
|
|
values = [syncTags allValues];
|
|
|
|
if (![values containsObject: newSyncTag])
|
|
|
|
[self setFolderPropertyValue: newSyncTag
|
|
|
|
inCategory: @"FolderSyncTags"];
|
2008-06-20 16:52:40 +02:00
|
|
|
}
|
2009-08-18 03:03:05 +02:00
|
|
|
else
|
2010-03-10 22:53:26 +01:00
|
|
|
[self setFolderPropertyValue: nil
|
|
|
|
inCategory: @"FolderSyncTags"];
|
2009-08-18 03:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) synchronizeCalendar
|
|
|
|
{
|
2010-03-10 22:53:26 +01:00
|
|
|
NSNumber *synchronize;
|
|
|
|
|
|
|
|
synchronize = [self folderPropertyValueInCategory: @"FolderSynchronize"];
|
|
|
|
|
|
|
|
return [synchronize boolValue];
|
2009-08-18 03:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setSynchronizeCalendar: (BOOL) new
|
|
|
|
{
|
2010-03-10 22:53:26 +01:00
|
|
|
NSNumber *synchronize;
|
|
|
|
|
2009-08-18 03:03:05 +02:00
|
|
|
if (new)
|
2010-03-10 22:53:26 +01:00
|
|
|
synchronize = [NSNumber numberWithBool: YES];
|
2009-08-18 03:03:05 +02:00
|
|
|
else
|
2010-03-10 22:53:26 +01:00
|
|
|
synchronize = nil;
|
|
|
|
|
|
|
|
[self setFolderPropertyValue: synchronize
|
|
|
|
inCategory: @"FolderSynchronize"];
|
2008-06-20 16:52:40 +02:00
|
|
|
}
|
|
|
|
|
2010-05-06 21:30:14 +02:00
|
|
|
- (BOOL) includeInFreeBusy
|
|
|
|
{
|
|
|
|
NSNumber *excludeFromFreeBusy;
|
|
|
|
|
2010-11-12 17:40:17 +01:00
|
|
|
// Check if the owner (not the active user) has excluded the calendar from her/his free busy data.
|
2010-05-06 21:30:14 +02:00
|
|
|
excludeFromFreeBusy
|
2010-11-12 17:40:17 +01:00
|
|
|
= [self folderPropertyValueInCategory: @"FreeBusyExclusions"
|
|
|
|
forUser: [SOGoUser userWithLogin: [self ownerInContext: context]]];
|
2010-05-06 21:30:14 +02:00
|
|
|
|
|
|
|
return ![excludeFromFreeBusy boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setIncludeInFreeBusy: (BOOL) newInclude
|
|
|
|
{
|
|
|
|
NSNumber *excludeFromFreeBusy;
|
|
|
|
|
|
|
|
excludeFromFreeBusy = [NSNumber numberWithBool: !newInclude];
|
|
|
|
|
|
|
|
[self setFolderPropertyValue: excludeFromFreeBusy
|
|
|
|
inCategory: @"FreeBusyExclusions"];
|
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* selection */
|
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
- (NSArray *) calendarUIDs
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
/* this is used for group calendars (this folder just returns itself) */
|
|
|
|
NSString *s;
|
|
|
|
|
|
|
|
s = [[self container] nameInContainer];
|
2007-04-11 21:08:58 +02:00
|
|
|
// [self logWithFormat:@"CAL UID: %@", s];
|
2006-06-15 21:34:10 +02:00
|
|
|
return [s isNotNull] ? [NSArray arrayWithObjects:&s count:1] : nil;
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
/* fetching */
|
2008-03-18 18:26:34 +01:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (NSString *) _sqlStringRangeFrom: (NSCalendarDate *) _startDate
|
|
|
|
to: (NSCalendarDate *) _endDate
|
2006-09-27 00:27:34 +02:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
unsigned int start, end;
|
2006-09-27 00:27:34 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
start = (unsigned int) [_startDate timeIntervalSince1970];
|
|
|
|
end = (unsigned int) [_endDate timeIntervalSince1970];
|
2006-09-27 00:27:34 +02:00
|
|
|
|
2009-06-09 19:50:25 +02:00
|
|
|
// vTODOs don't necessarily have start/end dates
|
2008-06-13 22:22:51 +02:00
|
|
|
return [NSString stringWithFormat:
|
2009-06-09 19:50:25 +02:00
|
|
|
@" AND (c_startdate = NULL OR c_startdate <= %u) AND (c_enddate = NULL OR c_enddate >= %u)",
|
2008-06-13 22:22:51 +02:00
|
|
|
end, start];
|
2008-03-18 18:26:34 +01:00
|
|
|
}
|
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
- (NSString *) aclSQLListingFilter
|
2008-03-18 18:26:34 +01:00
|
|
|
{
|
2010-06-01 20:12:01 +02:00
|
|
|
NSString *filter;
|
2009-06-16 23:35:23 +02:00
|
|
|
NSMutableArray *grantedClasses, *deniedClasses;
|
|
|
|
NSNumber *classNumber;
|
|
|
|
unsigned int grantedCount;
|
|
|
|
iCalAccessClass currentClass;
|
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
[self initializeQuickTablesAclsInContext: context];
|
|
|
|
grantedClasses = [NSMutableArray arrayWithCapacity: 3];
|
|
|
|
deniedClasses = [NSMutableArray arrayWithCapacity: 3];
|
|
|
|
for (currentClass = 0;
|
|
|
|
currentClass < iCalAccessClassCount; currentClass++)
|
2008-03-18 18:26:34 +01:00
|
|
|
{
|
2010-06-01 20:12:01 +02:00
|
|
|
classNumber = [NSNumber numberWithInt: currentClass];
|
|
|
|
if (userCanAccessObjectsClassifiedAs[currentClass])
|
|
|
|
[grantedClasses addObject: classNumber];
|
2009-06-17 17:19:33 +02:00
|
|
|
else
|
2010-06-01 20:12:01 +02:00
|
|
|
[deniedClasses addObject: classNumber];
|
2008-03-18 18:26:34 +01:00
|
|
|
}
|
2010-06-01 20:12:01 +02:00
|
|
|
grantedCount = [grantedClasses count];
|
|
|
|
if (grantedCount == 3)
|
|
|
|
filter = @"";
|
|
|
|
else if (grantedCount == 2)
|
|
|
|
filter
|
|
|
|
= [NSString stringWithFormat: @"c_classification != %@",
|
|
|
|
[deniedClasses objectAtIndex: 0]];
|
|
|
|
else if (grantedCount == 1)
|
|
|
|
filter
|
|
|
|
= [NSString stringWithFormat: @"c_classification = %@",
|
|
|
|
[grantedClasses objectAtIndex: 0]];
|
|
|
|
else
|
|
|
|
filter = nil;
|
2008-03-18 18:26:34 +01:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
return filter;
|
2008-03-18 18:26:34 +01:00
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (NSArray *) bareFetchFields: (NSArray *) fields
|
2009-06-02 17:28:42 +02:00
|
|
|
from: (NSCalendarDate *) startDate
|
|
|
|
to: (NSCalendarDate *) endDate
|
|
|
|
title: (NSString *) title
|
2009-06-17 20:07:23 +02:00
|
|
|
component: (NSString *) component
|
2009-06-02 17:28:42 +02:00
|
|
|
additionalFilters: (NSString *) filters
|
2008-03-18 18:26:34 +01:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
EOQualifier *qualifier;
|
|
|
|
GCSFolder *folder;
|
|
|
|
NSString *sql, *dateSqlString, *titleSqlString, *componentSqlString,
|
2010-06-01 20:12:01 +02:00
|
|
|
*privacySQLString;
|
2009-06-16 23:35:23 +02:00
|
|
|
NSMutableString *filterSqlString;
|
2010-06-01 20:12:01 +02:00
|
|
|
NSArray *records;
|
2008-03-18 18:26:34 +01:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
folder = [self ocsFolder];
|
|
|
|
if (startDate && endDate)
|
2008-10-08 18:03:24 +02:00
|
|
|
dateSqlString = [self _sqlStringRangeFrom: startDate to: endDate];
|
2008-03-18 18:26:34 +01:00
|
|
|
else
|
2008-10-08 18:03:24 +02:00
|
|
|
dateSqlString = @"";
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
if ([title length])
|
|
|
|
titleSqlString = [NSString stringWithFormat: @"AND (c_title"
|
|
|
|
@" isCaseInsensitiveLike: '%%%@%%')", title];
|
2008-03-18 18:26:34 +01:00
|
|
|
else
|
2008-06-13 22:22:51 +02:00
|
|
|
titleSqlString = @"";
|
2008-03-18 18:26:34 +01:00
|
|
|
|
2009-06-17 20:07:23 +02:00
|
|
|
if (component)
|
|
|
|
componentSqlString = [NSString stringWithFormat: @"AND c_component = '%@'",
|
|
|
|
component];
|
|
|
|
else
|
|
|
|
componentSqlString = @"";
|
2009-06-16 23:35:23 +02:00
|
|
|
filterSqlString = [NSMutableString string];
|
|
|
|
if ([filters length])
|
|
|
|
[filterSqlString appendFormat: @"AND (%@)", filters];
|
2008-03-18 18:26:34 +01:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
privacySQLString = [self aclSQLListingFilter];
|
|
|
|
if (privacySQLString)
|
|
|
|
{
|
|
|
|
if ([privacySQLString length])
|
|
|
|
[filterSqlString appendFormat: @"AND (%@)", privacySQLString];
|
|
|
|
|
|
|
|
/* prepare mandatory fields */
|
2009-06-16 23:35:23 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
sql = [NSString stringWithFormat: @"%@%@%@%@",
|
|
|
|
dateSqlString, titleSqlString, componentSqlString,
|
|
|
|
filterSqlString];
|
|
|
|
/* sql is empty when we fetch everything (all parameters are nil) */
|
|
|
|
if ([sql length] > 0)
|
|
|
|
sql = [sql substringFromIndex: 4];
|
|
|
|
else
|
|
|
|
sql = nil;
|
2006-09-27 00:27:34 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
/* fetch non-recurrent apts first */
|
|
|
|
qualifier = [EOQualifier qualifierWithQualifierFormat: sql];
|
|
|
|
|
|
|
|
records = [folder fetchFields: fields matchingQualifier: qualifier];
|
|
|
|
}
|
2009-09-24 16:29:24 +02:00
|
|
|
else
|
2010-06-01 20:12:01 +02:00
|
|
|
records = [NSArray array];
|
2008-03-18 18:26:34 +01:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
return records;
|
2008-03-18 18:26:34 +01:00
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (BOOL) _checkIfWeCanRememberRecords: (NSArray *) fields
|
2008-03-18 18:26:34 +01:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
return ([fields containsObject: @"c_name"]
|
|
|
|
&& [fields containsObject: @"c_version"]
|
|
|
|
&& [fields containsObject: @"c_lastmodified"]
|
|
|
|
&& [fields containsObject: @"c_creationdate"]
|
|
|
|
&& [fields containsObject: @"c_component"]);
|
2006-09-27 00:27:34 +02:00
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (void) _rememberRecords: (NSArray *) records
|
2006-10-17 21:57:14 +02:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
NSEnumerator *recordsEnum;
|
|
|
|
NSDictionary *currentRecord;
|
2006-10-17 21:57:14 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
recordsEnum = [records objectEnumerator];
|
|
|
|
while ((currentRecord = [recordsEnum nextObject]))
|
|
|
|
[childRecords setObject: currentRecord
|
|
|
|
forKey: [currentRecord objectForKey: @"c_name"]];
|
2006-10-17 21:57:14 +02:00
|
|
|
}
|
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
/**
|
|
|
|
* Set the timezone of the event start and end dates to the user's timezone.
|
|
|
|
* @param theRecord an dictionnary with the attributes of the event.
|
|
|
|
* @return a copy of theRecord with adjusted dates.
|
|
|
|
*/
|
|
|
|
- (NSMutableDictionary *) fixupRecord: (NSDictionary *) theRecord
|
2008-05-16 17:52:19 +02:00
|
|
|
{
|
2011-01-14 03:54:33 +01:00
|
|
|
NSMutableDictionary *record;
|
2008-06-19 20:31:18 +02:00
|
|
|
static NSString *fields[] = { @"c_startdate", @"startDate",
|
|
|
|
@"c_enddate", @"endDate" };
|
|
|
|
unsigned int count;
|
|
|
|
NSCalendarDate *date;
|
|
|
|
NSNumber *dateValue;
|
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
record = [[theRecord mutableCopy] autorelease];
|
2008-06-19 20:31:18 +02:00
|
|
|
for (count = 0; count < 2; count++)
|
|
|
|
{
|
2011-01-14 03:54:33 +01:00
|
|
|
dateValue = [theRecord objectForKey: fields[count * 2]];
|
2008-06-19 20:31:18 +02:00
|
|
|
if (dateValue)
|
|
|
|
{
|
2008-08-10 19:14:56 +02:00
|
|
|
date = [NSCalendarDate dateWithTimeIntervalSince1970: [dateValue unsignedIntValue]];
|
2008-06-19 20:31:18 +02:00
|
|
|
if (date)
|
|
|
|
{
|
|
|
|
[date setTimeZone: timeZone];
|
2011-01-14 03:54:33 +01:00
|
|
|
[record setObject: date forKey: fields[count * 2 + 1]];
|
2008-06-19 20:31:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2008-07-16 23:47:18 +02:00
|
|
|
[self logWithFormat: @"missing '%@' in record?", fields[count * 2]];
|
2008-06-19 20:31:18 +02:00
|
|
|
}
|
2008-05-16 17:52:19 +02:00
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
return record;
|
2008-05-16 17:52:19 +02:00
|
|
|
}
|
|
|
|
|
2009-03-16 22:21:43 +01:00
|
|
|
- (NSArray *) fixupRecords: (NSArray *) theRecords
|
2006-10-17 21:57:14 +02:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
// TODO: is the result supposed to be sorted by date?
|
|
|
|
NSMutableArray *ma;
|
|
|
|
unsigned count, max;
|
|
|
|
id row; // TODO: what is the type of the record?
|
2006-10-17 21:57:14 +02:00
|
|
|
|
2009-03-16 22:21:43 +01:00
|
|
|
if (theRecords)
|
2006-10-17 21:57:14 +02:00
|
|
|
{
|
2009-03-16 22:21:43 +01:00
|
|
|
max = [theRecords count];
|
2008-06-13 22:22:51 +02:00
|
|
|
ma = [NSMutableArray arrayWithCapacity: max];
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
2009-03-16 22:21:43 +01:00
|
|
|
row = [self fixupRecord: [theRecords objectAtIndex: count]];
|
2008-06-13 22:22:51 +02:00
|
|
|
if (row)
|
|
|
|
[ma addObject: row];
|
|
|
|
}
|
2006-10-17 21:57:14 +02:00
|
|
|
}
|
|
|
|
else
|
2008-06-13 22:22:51 +02:00
|
|
|
ma = nil;
|
|
|
|
|
|
|
|
return ma;
|
|
|
|
}
|
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
/**
|
|
|
|
* Adjust the timezone of the start and end dates to the user's timezone.
|
|
|
|
* The event is recurrent and the dates must first be adjusted with respect to
|
|
|
|
* the event's timezone.
|
|
|
|
* @param theRecord
|
|
|
|
* @param theCycle
|
|
|
|
* @param theFirstCycle
|
|
|
|
* @param theEventTimeZone
|
|
|
|
* @see fixupRecord:
|
|
|
|
* @return a copy of theRecord with adjusted dates.
|
|
|
|
*/
|
|
|
|
- (NSMutableDictionary *) fixupCycleRecord: (NSDictionary *) theRecord
|
|
|
|
cycleRange: (NGCalendarDateRange *) theCycle
|
|
|
|
firstInstanceCalendarDateRange: (NGCalendarDateRange *) theFirstCycle
|
|
|
|
withEventTimeZone: (iCalTimeZone *) theEventTimeZone
|
|
|
|
{
|
|
|
|
NSMutableDictionary *record;
|
2008-07-17 23:12:43 +02:00
|
|
|
NSNumber *dateSecs;
|
2011-01-14 03:54:33 +01:00
|
|
|
id date;
|
|
|
|
int secondsOffsetFromGMT;
|
|
|
|
|
|
|
|
record = [[theRecord mutableCopy] autorelease];
|
|
|
|
|
|
|
|
date = [theCycle startDate];
|
2011-02-23 17:33:29 +01:00
|
|
|
if (theEventTimeZone)
|
|
|
|
{
|
|
|
|
secondsOffsetFromGMT = (int) [[theEventTimeZone periodForDate: date] secondsOffsetFromGMT];
|
|
|
|
date = [date dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: -secondsOffsetFromGMT];
|
|
|
|
}
|
2011-01-14 03:54:33 +01:00
|
|
|
[date setTimeZone: timeZone];
|
|
|
|
[record setObject: date forKey: @"startDate"];
|
|
|
|
dateSecs = [NSNumber numberWithInt: [date timeIntervalSince1970]];
|
|
|
|
[record setObject: dateSecs forKey: @"c_startdate"];
|
|
|
|
[record setObject: dateSecs forKey: @"c_recurrence_id"];
|
|
|
|
|
|
|
|
date = [theCycle endDate];
|
2011-02-23 17:33:29 +01:00
|
|
|
if (theEventTimeZone)
|
|
|
|
{
|
|
|
|
secondsOffsetFromGMT = (int) [[theEventTimeZone periodForDate: date] secondsOffsetFromGMT];
|
|
|
|
date = [date dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: -secondsOffsetFromGMT];
|
|
|
|
}
|
2011-01-14 03:54:33 +01:00
|
|
|
[date setTimeZone: timeZone];
|
|
|
|
[record setObject: date forKey: @"endDate"];
|
|
|
|
dateSecs = [NSNumber numberWithInt: [date timeIntervalSince1970]];
|
|
|
|
[record setObject: dateSecs forKey: @"c_enddate"];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2009-06-15 23:19:36 +02:00
|
|
|
// The first instance date is added to the dictionary so it can
|
|
|
|
// be used by UIxCalListingActions to compute the DST offset.
|
2011-01-14 03:54:33 +01:00
|
|
|
date = [theFirstCycle startDate];
|
|
|
|
[record setObject: date forKey: @"cycleStartDate"];
|
2009-03-16 22:21:43 +01:00
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
return record;
|
2008-06-13 22:22:51 +02:00
|
|
|
}
|
|
|
|
|
2008-07-12 00:28:12 +02:00
|
|
|
- (int) _indexOfRecordMatchingDate: (NSCalendarDate *) matchDate
|
|
|
|
inArray: (NSArray *) recordArray
|
|
|
|
{
|
|
|
|
int count, max, recordIndex;
|
|
|
|
NSDictionary *currentRecord;
|
|
|
|
|
|
|
|
recordIndex = -1;
|
|
|
|
count = 0;
|
|
|
|
max = [recordArray count];
|
|
|
|
while (recordIndex == -1 && count < max)
|
|
|
|
{
|
|
|
|
currentRecord = [recordArray objectAtIndex: count];
|
|
|
|
if ([[currentRecord objectForKey: @"startDate"]
|
|
|
|
isEqual: matchDate])
|
|
|
|
recordIndex = count;
|
2008-07-14 17:14:40 +02:00
|
|
|
else
|
|
|
|
count++;
|
2008-07-12 00:28:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return recordIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _fixExceptionRecord: (NSMutableDictionary *) recRecord
|
|
|
|
fromRow: (NSDictionary *) row
|
|
|
|
{
|
|
|
|
NSArray *objects;
|
|
|
|
static NSArray *fields = nil;
|
|
|
|
|
|
|
|
if (!fields)
|
|
|
|
{
|
|
|
|
fields = [NSArray arrayWithObjects: @"c_name", nil];
|
|
|
|
[fields retain];
|
|
|
|
}
|
|
|
|
|
|
|
|
objects = [row objectsForKeys: fields notFoundMarker: @""];
|
|
|
|
[recRecord setObjects: objects forKeys: fields];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _appendCycleException: (iCalRepeatableEntityObject *) component
|
2008-12-30 15:47:58 +01:00
|
|
|
firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
2008-07-12 00:28:12 +02:00
|
|
|
fromRow: (NSDictionary *) row
|
|
|
|
forRange: (NGCalendarDateRange *) dateRange
|
|
|
|
toArray: (NSMutableArray *) ma
|
|
|
|
{
|
|
|
|
NSCalendarDate *startDate, *recurrenceId;
|
|
|
|
NSMutableDictionary *newRecord;
|
2008-07-17 23:12:43 +02:00
|
|
|
NSDictionary *oldRecord;
|
2008-07-12 00:28:12 +02:00
|
|
|
NGCalendarDateRange *newRecordRange;
|
|
|
|
int recordIndex;
|
2008-12-30 15:47:58 +01:00
|
|
|
signed int daylightOffset;
|
2008-07-12 00:28:12 +02:00
|
|
|
|
|
|
|
newRecord = nil;
|
|
|
|
recurrenceId = [component recurrenceId];
|
2008-12-30 15:47:58 +01:00
|
|
|
|
|
|
|
if ([timeZone isDaylightSavingTimeForDate: recurrenceId] != [timeZone isDaylightSavingTimeForDate: [fir startDate]])
|
|
|
|
{
|
|
|
|
// For the event's recurrence id, compute the daylight saving time
|
|
|
|
// offset with respect to the first occurrence of the recurring event.
|
|
|
|
daylightOffset = (signed int)[timeZone secondsFromGMTForDate: [fir startDate]]
|
|
|
|
- (signed int)[timeZone secondsFromGMTForDate: recurrenceId];
|
|
|
|
recurrenceId = [recurrenceId dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:daylightOffset];
|
|
|
|
}
|
|
|
|
|
2008-07-12 00:28:12 +02:00
|
|
|
if ([dateRange containsDate: recurrenceId])
|
|
|
|
{
|
|
|
|
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId
|
|
|
|
inArray: ma];
|
|
|
|
if (recordIndex > -1)
|
|
|
|
{
|
|
|
|
startDate = [component startDate];
|
|
|
|
if ([dateRange containsDate: startDate])
|
|
|
|
{
|
|
|
|
newRecord = [self fixupRecord: [component quickRecord]];
|
2008-07-17 23:12:43 +02:00
|
|
|
[newRecord setObject: [NSNumber numberWithInt: 1]
|
2009-06-15 23:19:36 +02:00
|
|
|
forKey: @"c_iscycle"];
|
2008-07-17 23:12:43 +02:00
|
|
|
oldRecord = [ma objectAtIndex: recordIndex];
|
|
|
|
[newRecord setObject: [oldRecord objectForKey: @"c_recurrence_id"]
|
2009-06-15 23:19:36 +02:00
|
|
|
forKey: @"c_recurrence_id"];
|
|
|
|
|
|
|
|
// The first instance date is added to the dictionary so it can
|
|
|
|
// be used by UIxCalListingActions to compute the DST offset.
|
2009-03-16 22:21:43 +01:00
|
|
|
[newRecord setObject: [fir startDate] forKey: @"cycleStartDate"];
|
2009-06-15 23:19:36 +02:00
|
|
|
|
|
|
|
// We identified the record as an exception.
|
|
|
|
[newRecord setObject: [NSNumber numberWithInt: 1]
|
|
|
|
forKey: @"isException"];
|
|
|
|
|
2008-07-12 00:28:12 +02:00
|
|
|
[ma replaceObjectAtIndex: recordIndex withObject: newRecord];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[ma removeObjectAtIndex: recordIndex];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[self errorWithFormat:
|
|
|
|
@"missing exception record for recurrence-id: %@",
|
|
|
|
recurrenceId];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newRecord = [self fixupRecord: [component quickRecord]];
|
2009-03-16 22:21:43 +01:00
|
|
|
newRecordRange = [NGCalendarDateRange
|
|
|
|
calendarDateRangeWithStartDate: [newRecord objectForKey: @"startDate"]
|
|
|
|
endDate: [newRecord objectForKey: @"endDate"]];
|
2008-07-12 00:28:12 +02:00
|
|
|
if ([dateRange doesIntersectWithDateRange: newRecordRange])
|
|
|
|
[ma addObject: newRecord];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newRecord)
|
|
|
|
[self _fixExceptionRecord: newRecord fromRow: row];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _appendCycleExceptionsFromRow: (NSDictionary *) row
|
2008-12-30 15:47:58 +01:00
|
|
|
firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
2008-07-14 17:14:40 +02:00
|
|
|
forRange: (NGCalendarDateRange *) dateRange
|
|
|
|
toArray: (NSMutableArray *) ma
|
2008-07-12 00:28:12 +02:00
|
|
|
{
|
|
|
|
NSArray *elements, *components;
|
|
|
|
unsigned int count, max;
|
|
|
|
NSString *content;
|
|
|
|
|
|
|
|
content = [row objectForKey: @"c_content"];
|
|
|
|
if ([content length])
|
|
|
|
{
|
|
|
|
elements = [iCalCalendar parseFromSource: content];
|
|
|
|
if ([elements count])
|
|
|
|
{
|
|
|
|
components = [[elements objectAtIndex: 0] allObjects];
|
|
|
|
max = [components count];
|
|
|
|
for (count = 1; count < max; count++)
|
|
|
|
[self _appendCycleException: [components objectAtIndex: count]
|
2008-12-30 15:47:58 +01:00
|
|
|
firstInstanceCalendarDateRange: fir
|
2008-07-12 00:28:12 +02:00
|
|
|
fromRow: row
|
|
|
|
forRange: dateRange
|
|
|
|
toArray: ma];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
/**
|
|
|
|
* Calculate and return the occurrences of the recurrent event for the given
|
|
|
|
* period.
|
|
|
|
* @param theRecord the event definition.
|
|
|
|
* @param theRange the period to look in.
|
|
|
|
* @param theRecords the array into which are copied the resulting occurrences.
|
2011-01-21 22:56:09 +01:00
|
|
|
* @see [iCalRepeatableEntityObject+SOGo doesOccurOnDate:]
|
2011-01-14 03:54:33 +01:00
|
|
|
*/
|
|
|
|
- (void) _flattenCycleRecord: (NSDictionary *) theRecord
|
|
|
|
forRange: (NGCalendarDateRange *) theRange
|
|
|
|
intoArray: (NSMutableArray *) theRecords
|
2008-06-13 22:22:51 +02:00
|
|
|
{
|
|
|
|
NSMutableDictionary *row, *fixedRow;
|
2011-01-14 03:54:33 +01:00
|
|
|
NSMutableArray *records;
|
|
|
|
NSDictionary *cycleinfo;
|
|
|
|
NGCalendarDateRange *firstRange, *oneRange;
|
|
|
|
NSArray *rules, *exRules, *exDates, *ranges;
|
|
|
|
NSArray *elements, *components;
|
2008-06-13 22:22:51 +02:00
|
|
|
NSString *content;
|
2011-01-14 03:54:33 +01:00
|
|
|
iCalRepeatableEntityObject *component;
|
2011-01-21 22:56:09 +01:00
|
|
|
id firstStartDate, firstEndDate;
|
2011-01-14 03:54:33 +01:00
|
|
|
NSCalendarDate *checkStartDate, *checkEndDate;
|
|
|
|
iCalTimeZone *eventTimeZone;
|
2011-01-21 22:56:09 +01:00
|
|
|
unsigned i, count, offset;
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
records = [NSMutableArray array];
|
|
|
|
ranges = nil;
|
2008-07-17 23:12:43 +02:00
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
content = [theRecord objectForKey: @"c_cycleinfo"];
|
2008-06-13 22:22:51 +02:00
|
|
|
if (![content isNotNull])
|
|
|
|
{
|
|
|
|
[self errorWithFormat:@"cyclic record doesn't have cycleinfo -> %@",
|
2011-01-14 03:54:33 +01:00
|
|
|
theRecord];
|
2008-06-13 22:22:51 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cycleinfo = [content propertyList];
|
|
|
|
if (!cycleinfo)
|
|
|
|
{
|
|
|
|
[self errorWithFormat:@"cyclic record doesn't have cycleinfo -> %@",
|
2011-01-14 03:54:33 +01:00
|
|
|
theRecord];
|
2008-06-13 22:22:51 +02:00
|
|
|
return;
|
|
|
|
}
|
2011-01-14 20:07:43 +01:00
|
|
|
rules = [cycleinfo objectForKey: @"rules"];
|
|
|
|
exRules = [cycleinfo objectForKey: @"exRules"];
|
|
|
|
exDates = [cycleinfo objectForKey: @"exDates"];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
row = [self fixupRecord: theRecord];
|
2008-06-13 22:22:51 +02:00
|
|
|
[row removeObjectForKey: @"c_cycleinfo"];
|
|
|
|
[row setObject: sharedYes forKey: @"isRecurrentEvent"];
|
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
content = [theRecord objectForKey: @"c_content"];
|
|
|
|
if ([content length])
|
|
|
|
{
|
|
|
|
elements = [iCalCalendar parseFromSource: content];
|
|
|
|
if ([elements count])
|
|
|
|
{
|
|
|
|
components = [[elements objectAtIndex: 0] events];
|
|
|
|
if ([components count])
|
|
|
|
{
|
|
|
|
// Retrieve the range of the first event
|
|
|
|
component = [components objectAtIndex: 0];
|
2011-01-21 22:56:09 +01:00
|
|
|
firstStartDate = [component uniqueChildWithTag: @"dtstart"];
|
|
|
|
firstEndDate = [component uniqueChildWithTag: @"dtend"];
|
|
|
|
eventTimeZone = [(iCalDateTime*)firstStartDate timeZone];
|
2011-01-14 03:54:33 +01:00
|
|
|
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: [[[firstStartDate values] lastObject] asCalendarDate]
|
|
|
|
endDate: [[[firstEndDate values] lastObject] asCalendarDate]];
|
|
|
|
|
2011-01-14 20:07:43 +01:00
|
|
|
if (eventTimeZone)
|
|
|
|
{
|
|
|
|
// Adjust the range to check with respect to the event timezone (extracted from the start date)
|
|
|
|
checkStartDate = [eventTimeZone computedDateForDate: [theRange startDate]];
|
|
|
|
checkEndDate = [eventTimeZone computedDateForDate: [theRange endDate]];
|
|
|
|
theRange = [NGCalendarDateRange calendarDateRangeWithStartDate: checkStartDate
|
|
|
|
endDate: checkEndDate];
|
|
|
|
exDates = [eventTimeZone computedDatesForStrings: exDates];
|
|
|
|
}
|
2011-01-21 22:56:09 +01:00
|
|
|
else if ([theRecord objectForKey: @"c_isallday"])
|
|
|
|
{
|
|
|
|
// The event lasts all-day and has no timezone (floating); we convert the range of the first event
|
|
|
|
// to the user's timezone
|
|
|
|
offset = [timeZone secondsFromGMTForDate: [firstRange startDate]];
|
|
|
|
firstStartDate = (NSCalendarDate*)[[firstRange startDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
|
|
|
|
seconds:-offset];
|
|
|
|
firstEndDate = (NSCalendarDate*)[[firstRange endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
|
|
|
|
seconds:-offset];
|
|
|
|
[firstStartDate setTimeZone: timeZone];
|
|
|
|
[firstEndDate setTimeZone: timeZone];
|
|
|
|
firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate
|
|
|
|
endDate: firstEndDate];
|
|
|
|
}
|
2011-01-14 20:07:43 +01:00
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
// Calculate the occurrences for the given range
|
|
|
|
ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: theRange
|
|
|
|
firstInstanceCalendarDateRange: firstRange
|
|
|
|
recurrenceRules: rules
|
|
|
|
exceptionRules: exRules
|
|
|
|
exceptionDates: exDates];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
count = [ranges count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2011-01-14 03:54:33 +01:00
|
|
|
oneRange = [ranges objectAtIndex: i];
|
|
|
|
fixedRow = [self fixupCycleRecord: row
|
|
|
|
cycleRange: oneRange
|
|
|
|
firstInstanceCalendarDateRange: firstRange
|
|
|
|
withEventTimeZone: eventTimeZone];
|
2008-06-13 22:22:51 +02:00
|
|
|
if (fixedRow)
|
2011-01-14 03:54:33 +01:00
|
|
|
[records addObject: fixedRow];
|
2008-06-13 22:22:51 +02:00
|
|
|
}
|
2008-07-12 00:28:12 +02:00
|
|
|
|
|
|
|
[self _appendCycleExceptionsFromRow: row
|
2011-01-14 03:54:33 +01:00
|
|
|
firstInstanceCalendarDateRange: firstRange
|
|
|
|
forRange: theRange
|
|
|
|
toArray: records];
|
2008-07-17 23:12:43 +02:00
|
|
|
|
2011-01-14 03:54:33 +01:00
|
|
|
[theRecords addObjectsFromArray: records];
|
2008-06-13 22:22:51 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 23:19:36 +02:00
|
|
|
- (NSArray *) _flattenCycleRecords: (NSArray *) _records
|
|
|
|
fetchRange: (NGCalendarDateRange *) _r
|
2008-06-13 22:22:51 +02:00
|
|
|
{
|
|
|
|
// TODO: is the result supposed to be sorted by date?
|
|
|
|
NSMutableArray *ma;
|
|
|
|
NSDictionary *row;
|
2011-01-21 22:56:09 +01:00
|
|
|
NSCalendarDate *rangeEndDate;
|
2008-07-12 00:28:12 +02:00
|
|
|
unsigned int count, max;
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2008-07-12 00:28:12 +02:00
|
|
|
max = [_records count];
|
|
|
|
ma = [NSMutableArray arrayWithCapacity: max];
|
|
|
|
|
2011-01-21 22:56:09 +01:00
|
|
|
// Adjust the range so it ends at midnight. This is necessary when calculating
|
|
|
|
// recurrences of all-day events.
|
|
|
|
rangeEndDate = [[_r endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:1];
|
|
|
|
_r = [NGCalendarDateRange calendarDateRangeWithStartDate: [_r startDate]
|
|
|
|
endDate: rangeEndDate];
|
|
|
|
|
2008-07-12 00:28:12 +02:00
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
row = [_records objectAtIndex: count];
|
|
|
|
[self _flattenCycleRecord: row forRange: _r intoArray: ma];
|
|
|
|
}
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
return ma;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _buildStripFieldsFromFields: (NSArray *) fields
|
|
|
|
{
|
|
|
|
stripFields = [[NSMutableArray alloc] initWithCapacity: [fields count]];
|
|
|
|
[stripFields setArray: fields];
|
2008-12-23 19:43:37 +01:00
|
|
|
|
|
|
|
// What we keep....
|
2008-06-13 22:22:51 +02:00
|
|
|
[stripFields removeObjectsInArray: [NSArray arrayWithObjects: @"c_name",
|
|
|
|
@"c_uid", @"c_startdate",
|
|
|
|
@"c_enddate", @"c_isallday",
|
2008-12-14 16:47:01 +01:00
|
|
|
@"c_iscycle", @"c_isopaque",
|
2009-02-06 21:17:04 +01:00
|
|
|
@"c_cycleinfo",
|
|
|
|
@"c_cycleenddate",
|
2008-06-13 22:22:51 +02:00
|
|
|
@"c_classification",
|
|
|
|
@"c_component", nil]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _fixupProtectedInformation: (NSEnumerator *) ma
|
|
|
|
inFields: (NSArray *) fields
|
|
|
|
forUser: (NSString *) uid
|
|
|
|
{
|
|
|
|
NSMutableDictionary *currentRecord;
|
|
|
|
NSString *roles[] = {nil, nil, nil};
|
|
|
|
iCalAccessClass accessClass;
|
|
|
|
NSString *fullRole, *role;
|
|
|
|
|
|
|
|
if (!stripFields)
|
|
|
|
[self _buildStripFieldsFromFields: fields];
|
|
|
|
|
|
|
|
#warning we do not take the participation status into account
|
|
|
|
while ((currentRecord = [ma nextObject]))
|
|
|
|
{
|
|
|
|
accessClass
|
2009-06-02 16:40:50 +02:00
|
|
|
= [[currentRecord objectForKey: @"c_classification"] intValue];
|
2008-06-13 22:22:51 +02:00
|
|
|
role = roles[accessClass];
|
|
|
|
if (!role)
|
2009-06-02 16:40:50 +02:00
|
|
|
{
|
|
|
|
fullRole = [self roleForComponentsWithAccessClass: accessClass
|
|
|
|
forUser: uid];
|
|
|
|
if ([fullRole length] > 9)
|
|
|
|
role = [fullRole substringFromIndex: 9];
|
|
|
|
roles[accessClass] = role;
|
|
|
|
}
|
2008-06-13 22:22:51 +02:00
|
|
|
if ([role isEqualToString: @"DAndTViewer"])
|
2009-06-02 16:40:50 +02:00
|
|
|
[currentRecord removeObjectsForKeys: stripFields];
|
2008-06-13 22:22:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-02 19:59:06 +02:00
|
|
|
/* TODO: this method should make use of bareFetchFields instead and only keep
|
|
|
|
its "intelligence" part for handling protected infos and recurrent
|
|
|
|
events... */
|
2008-12-23 19:43:37 +01:00
|
|
|
- (NSArray *) fetchFields: (NSArray *) _fields
|
2009-06-02 16:40:50 +02:00
|
|
|
from: (NSCalendarDate *) _startDate
|
|
|
|
to: (NSCalendarDate *) _endDate
|
|
|
|
title: (NSString *) title
|
|
|
|
component: (id) _component
|
|
|
|
additionalFilters: (NSString *) filters
|
2009-06-02 16:39:21 +02:00
|
|
|
includeProtectedInformation: (BOOL) _includeProtectedInformation
|
2008-06-13 22:22:51 +02:00
|
|
|
{
|
|
|
|
EOQualifier *qualifier;
|
|
|
|
GCSFolder *folder;
|
2009-06-17 20:07:23 +02:00
|
|
|
NSMutableArray *fields, *ma;
|
2008-06-13 22:22:51 +02:00
|
|
|
NSArray *records;
|
2009-06-17 20:07:23 +02:00
|
|
|
NSMutableString *baseWhere;
|
2010-06-01 20:12:01 +02:00
|
|
|
NSString *where, *dateSqlString, *privacySQLString, *currentLogin;
|
2008-11-07 19:56:03 +01:00
|
|
|
NSCalendarDate *endDate;
|
2008-06-13 22:22:51 +02:00
|
|
|
NGCalendarDateRange *r;
|
2009-06-17 20:07:23 +02:00
|
|
|
BOOL rememberRecords, canCycle;
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
rememberRecords = [self _checkIfWeCanRememberRecords: _fields];
|
2009-06-17 20:07:23 +02:00
|
|
|
canCycle = [_component isEqualToString: @"vevent"];
|
2008-06-13 22:22:51 +02:00
|
|
|
// if (rememberRecords)
|
|
|
|
// NSLog (@"we will remember those records!");
|
|
|
|
|
|
|
|
folder = [self ocsFolder];
|
|
|
|
if (!folder)
|
|
|
|
{
|
|
|
|
[self errorWithFormat:@"(%s): missing folder for fetch!",
|
|
|
|
__PRETTY_FUNCTION__];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2009-06-17 20:07:23 +02:00
|
|
|
if (_component)
|
|
|
|
baseWhere = [NSMutableString stringWithFormat: @"AND c_component = '%@'",
|
|
|
|
_component];
|
|
|
|
else
|
|
|
|
baseWhere = [NSMutableString string];
|
|
|
|
|
2008-11-07 19:56:03 +01:00
|
|
|
if (_startDate)
|
2008-06-13 22:22:51 +02:00
|
|
|
{
|
2008-11-07 19:56:03 +01:00
|
|
|
if (_endDate)
|
2009-06-02 16:40:50 +02:00
|
|
|
endDate = _endDate;
|
2008-11-07 19:56:03 +01:00
|
|
|
else
|
2009-06-02 16:40:50 +02:00
|
|
|
endDate = [NSCalendarDate distantFuture];
|
2008-06-13 22:22:51 +02:00
|
|
|
r = [NGCalendarDateRange calendarDateRangeWithStartDate: _startDate
|
2009-06-02 16:40:50 +02:00
|
|
|
endDate: endDate];
|
2008-11-07 19:56:03 +01:00
|
|
|
dateSqlString = [self _sqlStringRangeFrom: _startDate to: endDate];
|
2008-06-13 22:22:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
r = nil;
|
|
|
|
dateSqlString = @"";
|
|
|
|
}
|
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
privacySQLString = [self aclSQLListingFilter];
|
|
|
|
if (privacySQLString)
|
|
|
|
{
|
|
|
|
if ([privacySQLString length])
|
|
|
|
[baseWhere appendFormat: @"AND %@", privacySQLString];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
if ([title length])
|
|
|
|
[baseWhere
|
|
|
|
appendFormat: @"AND c_title isCaseInsensitiveLike: '%%%@%%'",
|
|
|
|
[title stringByReplacingString: @"'" withString: @"\\'\\'"]];
|
2009-06-16 23:35:23 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
if ([filters length])
|
|
|
|
[baseWhere appendFormat: @"AND (%@)", filters];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
/* prepare mandatory fields */
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
fields = [NSMutableArray arrayWithArray: _fields];
|
|
|
|
[fields addObjectUniquely: @"c_name"];
|
|
|
|
[fields addObjectUniquely: @"c_uid"];
|
|
|
|
[fields addObjectUniquely: @"c_startdate"];
|
|
|
|
[fields addObjectUniquely: @"c_enddate"];
|
|
|
|
[fields addObjectUniquely: @"c_isallday"];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
if (canCycle)
|
|
|
|
where = [NSString stringWithFormat: @"%@ %@ AND c_iscycle = 0",
|
|
|
|
baseWhere, dateSqlString];
|
|
|
|
else
|
|
|
|
where = baseWhere;
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
/* fetch non-recurrent apts first */
|
|
|
|
qualifier = [EOQualifier qualifierWithQualifierFormat:
|
|
|
|
[where substringFromIndex: 4]];
|
2008-11-07 19:56:03 +01:00
|
|
|
records = [folder fetchFields: fields matchingQualifier: qualifier];
|
|
|
|
if (records)
|
2009-06-02 16:40:50 +02:00
|
|
|
{
|
|
|
|
if (r)
|
2010-06-01 20:12:01 +02:00
|
|
|
records = [self fixupRecords: records];
|
|
|
|
ma = [NSMutableArray arrayWithArray: records];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ma = nil;
|
|
|
|
|
|
|
|
/* fetch recurrent apts now. we do NOT consider events with no cycle
|
|
|
|
end. */
|
|
|
|
if (canCycle && _endDate)
|
|
|
|
{
|
|
|
|
where = [NSString stringWithFormat: @"%@ AND c_iscycle = 1", baseWhere];
|
|
|
|
qualifier = [EOQualifier qualifierWithQualifierFormat: [where substringFromIndex: 4]];
|
|
|
|
records = [folder fetchFields: fields matchingQualifier: qualifier];
|
|
|
|
if (records)
|
|
|
|
{
|
|
|
|
if (r)
|
|
|
|
records = [self _flattenCycleRecords: records fetchRange: r];
|
|
|
|
if (ma)
|
|
|
|
[ma addObjectsFromArray: records];
|
|
|
|
else
|
|
|
|
ma = [NSMutableArray arrayWithArray: records];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ma)
|
|
|
|
{
|
|
|
|
[self errorWithFormat: @"(%s): fetch failed!", __PRETTY_FUNCTION__];
|
|
|
|
return nil;
|
2009-06-02 16:40:50 +02:00
|
|
|
}
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
currentLogin = [[context activeUser] login];
|
|
|
|
if (![currentLogin isEqualToString: owner]
|
|
|
|
&& !_includeProtectedInformation)
|
|
|
|
[self _fixupProtectedInformation: [ma objectEnumerator]
|
|
|
|
inFields: _fields
|
|
|
|
forUser: currentLogin];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2010-06-01 20:12:01 +02:00
|
|
|
if (rememberRecords)
|
|
|
|
[self _rememberRecords: ma];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ma = [NSMutableArray array];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
return ma;
|
|
|
|
}
|
|
|
|
|
|
|
|
#warning we should use the EOFetchSpecification for that!!! (see doPROPFIND:)
|
|
|
|
|
|
|
|
#warning components in calendar-data query are ignored
|
2008-07-12 00:28:12 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (NSString *) _nodeTagForProperty: (NSString *) property
|
|
|
|
{
|
|
|
|
NSString *namespace, *nodeName, *nsRep;
|
|
|
|
NSRange nsEnd;
|
|
|
|
|
|
|
|
nsEnd = [property rangeOfString: @"}"];
|
|
|
|
namespace
|
|
|
|
= [property substringFromRange: NSMakeRange (1, nsEnd.location - 1)];
|
|
|
|
nodeName = [property substringFromIndex: nsEnd.location + 1];
|
2008-06-30 20:52:20 +02:00
|
|
|
if ([namespace isEqualToString: XMLNS_CALDAV])
|
2008-06-13 22:22:51 +02:00
|
|
|
nsRep = @"C";
|
|
|
|
else
|
|
|
|
nsRep = @"D";
|
|
|
|
|
|
|
|
return [NSString stringWithFormat: @"%@:%@", nsRep, nodeName];
|
|
|
|
}
|
|
|
|
|
2009-06-02 16:05:59 +02:00
|
|
|
- (NSCalendarDate *) _getMaxStartDate
|
|
|
|
{
|
2009-09-09 19:35:03 +02:00
|
|
|
NSCalendarDate *now, *rc;
|
2009-07-07 22:57:00 +02:00
|
|
|
|
2009-09-09 19:35:03 +02:00
|
|
|
if (davCalendarStartTimeLimit > 0 && ![[context activeUser] isSuperUser])
|
2009-06-02 16:05:59 +02:00
|
|
|
{
|
2009-09-09 19:35:03 +02:00
|
|
|
now = [NSCalendarDate date];
|
|
|
|
rc = [now addTimeInterval: -davTimeLimitSeconds];
|
2009-06-02 16:05:59 +02:00
|
|
|
}
|
2009-07-07 22:57:00 +02:00
|
|
|
else
|
|
|
|
rc = nil;
|
2009-06-02 16:05:59 +02:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _enforceTimeLimitOnFilter: (NSMutableDictionary *) filter
|
2009-09-09 19:35:03 +02:00
|
|
|
withStartDate: (NSCalendarDate *) startDate
|
|
|
|
andEndDate: (NSCalendarDate *) endDate
|
2009-06-02 16:05:59 +02:00
|
|
|
{
|
2009-09-09 19:35:03 +02:00
|
|
|
NSCalendarDate *now;
|
2009-07-07 22:57:00 +02:00
|
|
|
int interval, intervalStart, intervalEnd;
|
2009-06-02 16:05:59 +02:00
|
|
|
|
2009-09-09 19:35:03 +02:00
|
|
|
if (davCalendarStartTimeLimit > 0 && ![[context activeUser] isSuperUser])
|
2009-06-02 16:05:59 +02:00
|
|
|
{
|
2009-09-09 19:35:03 +02:00
|
|
|
interval = ([endDate timeIntervalSinceDate: startDate] / 86400);
|
|
|
|
if (interval > davCalendarStartTimeLimit)
|
2009-06-02 16:05:59 +02:00
|
|
|
{
|
2009-09-09 19:35:03 +02:00
|
|
|
now = [NSCalendarDate date];
|
|
|
|
if ([now compare: startDate] == NSOrderedDescending
|
|
|
|
&& [now compare: endDate] == NSOrderedAscending)
|
2009-06-02 16:05:59 +02:00
|
|
|
{
|
2009-09-09 19:35:03 +02:00
|
|
|
intervalStart = [now timeIntervalSinceDate: startDate] / 86400;
|
|
|
|
intervalEnd = [endDate timeIntervalSinceDate: now] / 86400;
|
|
|
|
if (intervalStart > davCalendarStartTimeLimit / 2)
|
|
|
|
{
|
|
|
|
startDate = [now addTimeInterval: -davTimeHalfLimitSeconds];
|
|
|
|
[filter setObject: startDate forKey: @"start"];
|
|
|
|
}
|
|
|
|
if (intervalEnd > davCalendarStartTimeLimit / 2)
|
|
|
|
{
|
|
|
|
endDate = [now addTimeInterval: davTimeHalfLimitSeconds];
|
|
|
|
[filter setObject: endDate forKey: @"end"];
|
|
|
|
}
|
2009-06-02 16:05:59 +02:00
|
|
|
}
|
2009-09-09 19:35:03 +02:00
|
|
|
else if ([now compare: endDate] == NSOrderedDescending)
|
2009-06-02 16:05:59 +02:00
|
|
|
{
|
2009-09-09 19:35:03 +02:00
|
|
|
startDate = [endDate addTimeInterval: -davTimeLimitSeconds];
|
|
|
|
[filter setObject: startDate forKey: @"start"];
|
|
|
|
}
|
|
|
|
else if ([now compare: startDate] == NSOrderedAscending)
|
|
|
|
{
|
|
|
|
endDate = [startDate addTimeInterval: davTimeLimitSeconds];
|
|
|
|
[filter setObject: endDate forKey: @"end"];
|
2009-06-02 16:05:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (void) _appendTimeRange: (id <DOMElement>) timeRangeElement
|
|
|
|
toFilter: (NSMutableDictionary *) filter
|
|
|
|
{
|
2009-09-09 19:35:03 +02:00
|
|
|
NSCalendarDate *startDate, *endDate;
|
|
|
|
|
|
|
|
startDate = [[timeRangeElement attribute: @"start"] asCalendarDate];
|
|
|
|
if (!startDate)
|
|
|
|
startDate = [NSCalendarDate distantPast];
|
|
|
|
[filter setObject: startDate forKey: @"start"];
|
|
|
|
|
|
|
|
endDate = [[timeRangeElement attribute: @"end"] asCalendarDate];
|
|
|
|
if (!endDate)
|
|
|
|
endDate = [NSCalendarDate distantFuture];
|
|
|
|
[filter setObject: endDate forKey: @"end"];
|
|
|
|
|
|
|
|
[self _enforceTimeLimitOnFilter: filter
|
|
|
|
withStartDate: startDate andEndDate: endDate];
|
2008-06-13 22:22:51 +02:00
|
|
|
}
|
|
|
|
|
2009-06-02 16:39:21 +02:00
|
|
|
- (void) _addDateRangeLimitToFilter: (NSMutableDictionary *) filter
|
|
|
|
{
|
|
|
|
NSCalendarDate *now;
|
|
|
|
|
|
|
|
now = [NSCalendarDate date];
|
2009-09-09 19:35:03 +02:00
|
|
|
[filter setObject: [now addTimeInterval: davTimeHalfLimitSeconds]
|
2009-06-02 16:39:21 +02:00
|
|
|
forKey: @"start"];
|
2009-09-09 19:35:03 +02:00
|
|
|
[filter setObject: [now addTimeInterval: -davTimeHalfLimitSeconds]
|
2009-06-02 16:39:21 +02:00
|
|
|
forKey: @"end"];
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
#warning This method lacks support for timeranges
|
|
|
|
- (void) _appendPropertyFilter: (id <DOMElement>) propFilter
|
|
|
|
toFilter: (NSMutableDictionary *) filter
|
|
|
|
{
|
|
|
|
NSString *propName, *textMatch;
|
|
|
|
id <DOMNodeList> matches;
|
|
|
|
|
|
|
|
propName = [[propFilter attribute: @"name"] lowercaseString];
|
|
|
|
matches = [propFilter getElementsByTagName: @"text-match"];
|
|
|
|
if ([matches length])
|
|
|
|
textMatch = [[matches objectAtIndex: 0] textValue];
|
|
|
|
else
|
|
|
|
{
|
|
|
|
matches = [propFilter getElementsByTagName: @"is-not-defined"];
|
|
|
|
if ([matches length])
|
|
|
|
textMatch = @"NULL";
|
|
|
|
else
|
|
|
|
textMatch = @"";
|
|
|
|
}
|
|
|
|
|
|
|
|
[filter setObject: textMatch forKey: propName];
|
|
|
|
}
|
|
|
|
|
2009-06-18 22:58:46 +02:00
|
|
|
- (NSDictionary *) _parseCalendarFilter: (DOMElement *) filterElement
|
2008-06-13 22:22:51 +02:00
|
|
|
{
|
|
|
|
NSMutableDictionary *filterData;
|
|
|
|
id <DOMElement> parentNode;
|
|
|
|
id <DOMNodeList> elements;
|
|
|
|
NSString *componentName;
|
2009-06-02 16:05:59 +02:00
|
|
|
NSCalendarDate *maxStart;
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
parentNode = (id <DOMElement>) [filterElement parentNode];
|
|
|
|
if ([[parentNode tagName] isEqualToString: @"comp-filter"]
|
|
|
|
&& [[parentNode attribute: @"name"] isEqualToString: @"VCALENDAR"])
|
|
|
|
{
|
|
|
|
componentName = [[filterElement attribute: @"name"] lowercaseString];
|
|
|
|
filterData = [NSMutableDictionary dictionary];
|
|
|
|
[filterData setObject: componentName forKey: @"name"];
|
|
|
|
elements = [filterElement getElementsByTagName: @"time-range"];
|
|
|
|
if ([elements length])
|
|
|
|
[self _appendTimeRange: [elements objectAtIndex: 0]
|
2009-06-02 19:59:06 +02:00
|
|
|
toFilter: filterData];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
elements = [filterElement getElementsByTagName: @"prop-filter"];
|
|
|
|
if ([elements length])
|
|
|
|
[self _appendPropertyFilter: [elements objectAtIndex: 0]
|
2009-06-02 19:59:06 +02:00
|
|
|
toFilter: filterData];
|
2009-06-02 16:05:59 +02:00
|
|
|
|
2009-06-02 19:59:06 +02:00
|
|
|
if (![filterData objectForKey: @"start"])
|
2009-06-02 16:05:59 +02:00
|
|
|
{
|
|
|
|
maxStart = [self _getMaxStartDate];
|
|
|
|
if (maxStart)
|
2009-06-08 16:32:21 +02:00
|
|
|
[self _addDateRangeLimitToFilter: filterData];
|
2009-06-02 16:05:59 +02:00
|
|
|
}
|
2009-06-02 17:28:42 +02:00
|
|
|
[filterData setObject: [NSNumber numberWithBool: NO] forKey: @"iscycle"];
|
2008-06-13 22:22:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
filterData = nil;
|
2006-10-17 21:57:14 +02:00
|
|
|
|
|
|
|
return filterData;
|
|
|
|
}
|
|
|
|
|
2009-06-02 17:28:42 +02:00
|
|
|
- (NSDictionary *) _makeCyclicFilterFrom: (NSDictionary *) filter
|
|
|
|
{
|
|
|
|
NSMutableDictionary *rc;
|
2009-06-09 14:49:44 +02:00
|
|
|
NSNumber *start;
|
2009-06-02 17:28:42 +02:00
|
|
|
|
|
|
|
rc = [NSMutableDictionary dictionaryWithDictionary: filter];
|
2009-06-09 14:49:44 +02:00
|
|
|
start = [rc objectForKey: @"start"];
|
|
|
|
if (start)
|
|
|
|
[rc setObject: start forKey: @"cycleenddate"];
|
2009-06-02 17:28:42 +02:00
|
|
|
[rc removeObjectForKey: @"start"];
|
|
|
|
[rc removeObjectForKey: @"end"];
|
2009-06-02 19:59:06 +02:00
|
|
|
[rc setObject: sharedYes forKey: @"iscycle"];
|
2009-06-02 17:28:42 +02:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2009-06-18 22:58:46 +02:00
|
|
|
- (NSArray *) _parseCalendarFilters: (DOMElement *) parentNode
|
2006-10-17 21:57:14 +02:00
|
|
|
{
|
2008-03-18 18:26:34 +01:00
|
|
|
id <DOMNodeList> children;
|
2009-06-18 22:58:46 +02:00
|
|
|
DOMElement *element;
|
2006-10-17 21:57:14 +02:00
|
|
|
NSMutableArray *filters;
|
|
|
|
NSDictionary *filter;
|
2008-03-18 18:26:34 +01:00
|
|
|
unsigned int count, max;
|
2006-10-17 21:57:14 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
// NSLog (@"parseCalendarFilter: %@", [NSDate date]);
|
|
|
|
|
2007-12-05 00:28:52 +01:00
|
|
|
filters = [NSMutableArray array];
|
2008-03-18 18:26:34 +01:00
|
|
|
children = [parentNode getElementsByTagName: @"comp-filter"];
|
|
|
|
max = [children length];
|
|
|
|
for (count = 0; count < max; count++)
|
2006-10-17 21:57:14 +02:00
|
|
|
{
|
2009-06-18 22:58:46 +02:00
|
|
|
element = [children objectAtIndex: count];
|
|
|
|
filter = [self _parseCalendarFilter: element];
|
2006-10-17 21:57:14 +02:00
|
|
|
if (filter)
|
2009-06-02 17:28:42 +02:00
|
|
|
{
|
|
|
|
[filters addObject: filter];
|
|
|
|
[filters addObject: [self _makeCyclicFilterFrom: filter]];
|
|
|
|
}
|
2006-10-17 21:57:14 +02:00
|
|
|
}
|
2008-06-13 22:22:51 +02:00
|
|
|
// NSLog (@"/parseCalendarFilter: %@", [NSDate date]);
|
2006-10-17 21:57:14 +02:00
|
|
|
|
|
|
|
return filters;
|
|
|
|
}
|
|
|
|
|
2008-05-16 17:52:19 +02:00
|
|
|
- (NSString *) _additionalFilterKey: (NSString *) key
|
2009-06-02 17:28:42 +02:00
|
|
|
value: (NSString *) value
|
2008-05-16 17:52:19 +02:00
|
|
|
{
|
|
|
|
NSString *filterString;
|
|
|
|
|
|
|
|
if ([value length])
|
|
|
|
{
|
|
|
|
if ([value isEqualToString: @"NULL"])
|
2009-06-02 17:28:42 +02:00
|
|
|
filterString = [NSString stringWithFormat: @"(%@ = '')", key];
|
2008-05-16 17:52:19 +02:00
|
|
|
else
|
2009-06-02 17:28:42 +02:00
|
|
|
filterString
|
|
|
|
= [NSString stringWithFormat: @"(%@ like '%%%@%%')", key, value];
|
2008-05-16 17:52:19 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
filterString = [NSString stringWithFormat: @"(%@ != '')", key];
|
|
|
|
|
|
|
|
return filterString;
|
|
|
|
}
|
|
|
|
|
2009-06-09 19:42:00 +02:00
|
|
|
/* This method enables the mapping between comp-filter attributes and SQL
|
2009-06-09 19:41:15 +02:00
|
|
|
fields in the quick table. Probably unused most of the time but should be
|
|
|
|
completed one day for full CalDAV compliance. */
|
2008-05-16 17:52:19 +02:00
|
|
|
- (NSString *) _composeAdditionalFilters: (NSDictionary *) filter
|
|
|
|
{
|
|
|
|
NSString *additionalFilter;
|
|
|
|
NSEnumerator *keys;
|
|
|
|
NSString *currentKey, *keyField, *filterString;
|
|
|
|
static NSArray *fields = nil;
|
|
|
|
NSMutableArray *filters;
|
2009-06-19 17:17:12 +02:00
|
|
|
NSCalendarDate *cEndDate;
|
|
|
|
NSNumber *cycle;
|
2008-05-16 17:52:19 +02:00
|
|
|
|
|
|
|
#warning the list of fields should be taken from the .ocs description file
|
|
|
|
if (!fields)
|
|
|
|
{
|
|
|
|
fields = [NSArray arrayWithObject: @"c_uid"];
|
|
|
|
[fields retain];
|
|
|
|
}
|
2008-06-13 22:22:51 +02:00
|
|
|
|
2009-06-16 23:35:23 +02:00
|
|
|
filters = [NSMutableArray array];
|
2008-06-13 22:22:51 +02:00
|
|
|
keys = [[filter allKeys] objectEnumerator];
|
|
|
|
while ((currentKey = [keys nextObject]))
|
|
|
|
{
|
|
|
|
keyField = [NSString stringWithFormat: @"c_%@", currentKey];
|
|
|
|
if ([fields containsObject: keyField])
|
2009-06-02 16:05:59 +02:00
|
|
|
{
|
2009-06-02 19:59:06 +02:00
|
|
|
filterString
|
|
|
|
= [self _additionalFilterKey: keyField
|
|
|
|
value: [filter objectForKey: currentKey]];
|
2009-06-02 16:05:59 +02:00
|
|
|
[filters addObject: filterString];
|
|
|
|
}
|
2006-10-11 20:48:25 +02:00
|
|
|
}
|
2006-09-27 00:27:34 +02:00
|
|
|
|
2009-06-02 17:28:42 +02:00
|
|
|
// Exception for iscycle
|
|
|
|
cycle = [filter objectForKey: @"iscycle"];
|
|
|
|
if (cycle)
|
|
|
|
{
|
|
|
|
filterString = [NSString stringWithFormat: @"(c_iscycle = '%d')",
|
2009-06-02 19:59:06 +02:00
|
|
|
[cycle intValue]];
|
2009-06-02 17:28:42 +02:00
|
|
|
[filters addObject: filterString];
|
2009-06-08 16:32:21 +02:00
|
|
|
|
|
|
|
if ([cycle intValue])
|
|
|
|
{
|
|
|
|
cEndDate = [filter objectForKey: @"cycleenddate"];
|
2009-06-19 17:17:12 +02:00
|
|
|
if (cEndDate)
|
2009-06-16 18:21:21 +02:00
|
|
|
{
|
|
|
|
filterString = [NSString stringWithFormat:
|
2009-07-07 20:21:15 +02:00
|
|
|
@"(c_cycleenddate = NULL OR c_cycleenddate >= %d)",
|
2009-06-19 17:17:12 +02:00
|
|
|
(int) [cEndDate timeIntervalSince1970]];
|
2009-06-16 18:21:21 +02:00
|
|
|
[filters addObject: filterString];
|
|
|
|
}
|
2009-06-08 16:32:21 +02:00
|
|
|
}
|
2009-06-02 17:28:42 +02:00
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
if ([filters count])
|
2009-06-09 19:50:25 +02:00
|
|
|
additionalFilter = [filters componentsJoinedByString: @" AND "];
|
2008-06-13 22:22:51 +02:00
|
|
|
else
|
|
|
|
additionalFilter = nil;
|
2008-01-16 19:57:58 +01:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
return additionalFilter;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (NSString *) davCalendarColor
|
|
|
|
{
|
|
|
|
NSString *color;
|
2006-11-02 22:53:27 +01:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
color = [[self calendarColor] uppercaseString];
|
2006-11-02 22:53:27 +01:00
|
|
|
|
2009-07-16 19:35:40 +02:00
|
|
|
// return color;
|
|
|
|
return [NSString stringWithFormat: @"%@FF", color];
|
2006-11-02 22:53:27 +01:00
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (NSException *) setDavCalendarColor: (NSString *) newColor
|
2006-12-14 22:20:13 +01:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
NSException *error;
|
|
|
|
NSString *realColor;
|
|
|
|
|
|
|
|
if ([newColor length] == 9
|
|
|
|
&& [newColor hasPrefix: @"#"])
|
|
|
|
{
|
|
|
|
realColor = [newColor substringToIndex: 7];
|
|
|
|
[self setCalendarColor: realColor];
|
|
|
|
error = nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
error = [NSException exceptionWithHTTPStatus: 400
|
|
|
|
reason: @"Bad color format (should be '#XXXXXXXX')."];
|
|
|
|
|
|
|
|
return error;
|
2006-12-14 22:20:13 +01:00
|
|
|
}
|
|
|
|
|
2008-07-14 18:46:10 +02:00
|
|
|
- (NSString *) davCalendarOrder
|
|
|
|
{
|
|
|
|
unsigned int order;
|
|
|
|
|
|
|
|
order = [[container subFolders] indexOfObject: self];
|
|
|
|
|
|
|
|
return [NSString stringWithFormat: @"%d", order];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSException *) setDavCalendarOrder: (NSString *) newColor
|
|
|
|
{
|
2009-10-21 23:17:11 +02:00
|
|
|
/* we fail silently */
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) davCalendarTimeZone
|
|
|
|
{
|
|
|
|
SOGoUser *ownerUser;
|
|
|
|
NSString *ownerTimeZone;
|
|
|
|
|
|
|
|
ownerUser = [SOGoUser userWithLogin: [self ownerInContext: context]];
|
2009-11-29 05:19:32 +01:00
|
|
|
ownerTimeZone = [[ownerUser userDefaults] timeZoneName];
|
|
|
|
|
2009-10-21 23:17:11 +02:00
|
|
|
return [[iCalTimeZone timeZoneForName: ownerTimeZone] versitString];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSException *) setDavCalendarTimeZone: (NSString *) newTimeZone
|
|
|
|
{
|
|
|
|
/* we fail silently */
|
2008-07-14 18:46:10 +02:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2009-06-16 23:35:23 +02:00
|
|
|
- (void) _appendComponentProperties: (NSDictionary *) properties
|
2009-06-02 16:05:59 +02:00
|
|
|
matchingFilters: (NSArray *) filters
|
|
|
|
toResponse: (WOResponse *) response
|
2007-03-10 00:10:43 +01:00
|
|
|
{
|
2009-06-16 23:35:23 +02:00
|
|
|
NSArray *apts;
|
|
|
|
NSMutableArray *fields;
|
2008-06-13 22:22:51 +02:00
|
|
|
NSDictionary *currentFilter;
|
|
|
|
NSEnumerator *filterList;
|
2009-06-30 23:21:50 +02:00
|
|
|
NSString *additionalFilters, *baseURL, *currentField;
|
2008-11-18 01:06:37 +01:00
|
|
|
NSMutableString *buffer;
|
2009-06-16 23:35:23 +02:00
|
|
|
NSString **propertiesArray;
|
2009-06-30 23:21:50 +02:00
|
|
|
NSEnumerator *addFields;
|
2009-06-03 23:38:46 +02:00
|
|
|
unsigned int count, max, propertiesCount;
|
2007-03-10 00:10:43 +01:00
|
|
|
|
2009-06-24 01:38:52 +02:00
|
|
|
fields = [NSMutableArray arrayWithObjects: @"c_name", @"c_component", nil];
|
2009-06-30 23:21:50 +02:00
|
|
|
addFields = [[properties allValues] objectEnumerator];
|
|
|
|
while ((currentField = [addFields nextObject]))
|
|
|
|
if ([currentField length])
|
|
|
|
[fields addObjectUniquely: currentField];
|
2009-10-21 23:17:11 +02:00
|
|
|
baseURL = [self davURLAsString];
|
2008-11-22 22:52:40 +01:00
|
|
|
|
2009-06-16 23:35:23 +02:00
|
|
|
propertiesArray = [[properties allKeys] asPointersOfObjects];
|
|
|
|
propertiesCount = [properties count];
|
2009-06-03 23:38:46 +02:00
|
|
|
|
2009-06-18 22:58:46 +02:00
|
|
|
// NSLog (@"start");
|
2008-06-13 22:22:51 +02:00
|
|
|
filterList = [filters objectEnumerator];
|
|
|
|
while ((currentFilter = [filterList nextObject]))
|
2007-03-10 00:10:43 +01:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
additionalFilters = [self _composeAdditionalFilters: currentFilter];
|
2009-06-02 20:00:19 +02:00
|
|
|
/* TODO: we should invoke bareFetchField:... twice and compute the
|
|
|
|
recurrent events properly instead of using _makeCyclicFilterFrom: */
|
2008-11-18 01:06:37 +01:00
|
|
|
apts = [self bareFetchFields: fields
|
2009-06-02 16:05:59 +02:00
|
|
|
from: [currentFilter objectForKey: @"start"]
|
|
|
|
to: [currentFilter objectForKey: @"end"]
|
|
|
|
title: [currentFilter objectForKey: @"title"]
|
|
|
|
component: [currentFilter objectForKey: @"name"]
|
|
|
|
additionalFilters: additionalFilters];
|
2009-06-18 22:58:46 +02:00
|
|
|
// NSLog(@"adding properties");
|
2008-06-13 22:22:51 +02:00
|
|
|
max = [apts count];
|
2009-06-16 23:35:23 +02:00
|
|
|
buffer = [NSMutableString stringWithCapacity: max * 512];
|
2008-06-13 22:22:51 +02:00
|
|
|
for (count = 0; count < max; count++)
|
2009-06-02 16:05:59 +02:00
|
|
|
[self appendObject: [apts objectAtIndex: count]
|
2009-06-16 23:35:23 +02:00
|
|
|
properties: propertiesArray
|
2009-06-03 23:38:46 +02:00
|
|
|
count: propertiesCount
|
2009-06-02 16:05:59 +02:00
|
|
|
withBaseURL: baseURL
|
|
|
|
toBuffer: buffer];
|
2009-06-18 22:58:46 +02:00
|
|
|
// NSLog(@"done 1");
|
2008-11-18 01:06:37 +01:00
|
|
|
[response appendContentString: buffer];
|
2009-06-18 22:58:46 +02:00
|
|
|
// NSLog(@"done 2");
|
2007-03-10 00:10:43 +01:00
|
|
|
}
|
2009-06-18 22:58:46 +02:00
|
|
|
// NSLog (@"stop");
|
2009-06-03 23:38:46 +02:00
|
|
|
|
2009-06-16 23:35:23 +02:00
|
|
|
NSZoneFree (NULL, propertiesArray);
|
2007-03-10 00:10:43 +01:00
|
|
|
}
|
|
|
|
|
2009-06-18 22:58:46 +02:00
|
|
|
/* This table is meant to match SQL fields to the properties that requires
|
|
|
|
them. The fields may NOT be processed directly. This list is not complete
|
|
|
|
but is at least sufficient for processing requests from Lightning. */
|
|
|
|
- (NSDictionary *) davSQLFieldsTable
|
|
|
|
{
|
|
|
|
static NSMutableDictionary *davSQLFieldsTable = nil;
|
|
|
|
|
|
|
|
if (!davSQLFieldsTable)
|
|
|
|
{
|
|
|
|
davSQLFieldsTable = [[super davSQLFieldsTable] mutableCopy];
|
|
|
|
[davSQLFieldsTable setObject: @"c_content"
|
|
|
|
forKey: @"{" XMLNS_CALDAV @"}calendar-data"];
|
|
|
|
}
|
|
|
|
|
|
|
|
return davSQLFieldsTable;
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (id) davCalendarQuery: (id) queryContext
|
2006-08-16 00:04:37 +02:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
WOResponse *r;
|
|
|
|
id <DOMDocument> document;
|
2009-06-18 22:58:46 +02:00
|
|
|
DOMElement *documentElement, *propElement;
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
r = [context response];
|
2010-01-15 00:19:19 +01:00
|
|
|
[r prepareDAVResponse];
|
2008-06-13 22:22:51 +02:00
|
|
|
[r appendContentString: @"<D:multistatus xmlns:D=\"DAV:\""
|
2009-06-18 22:58:46 +02:00
|
|
|
@" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">"];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
document = [[context request] contentAsDOMDocument];
|
2009-06-18 22:58:46 +02:00
|
|
|
documentElement = (DOMElement *) [document documentElement];
|
|
|
|
propElement = [documentElement firstElementWithTag: @"prop"
|
|
|
|
inNamespace: XMLNS_WEBDAV];
|
|
|
|
|
|
|
|
[self _appendComponentProperties: [self parseDAVRequestedProperties: propElement]
|
2009-06-16 23:35:23 +02:00
|
|
|
matchingFilters: [self _parseCalendarFilters: documentElement]
|
2009-06-01 19:56:31 +02:00
|
|
|
toResponse: r];
|
2008-10-22 17:54:02 +02:00
|
|
|
[r appendContentString:@"</D:multistatus>"];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
return r;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2010-08-12 16:02:21 +02:00
|
|
|
- (WOResponse *) davCalendarMultiget: (WOContext *) queryContext
|
2007-04-11 21:08:58 +02:00
|
|
|
{
|
2010-08-12 16:02:21 +02:00
|
|
|
return [self performMultigetInContext: queryContext
|
|
|
|
inNamespace: @"urn:ietf:params:xml:ns:caldav"];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2009-07-07 22:57:00 +02:00
|
|
|
- (NSString *) additionalWebdavSyncFilters
|
|
|
|
{
|
|
|
|
NSCalendarDate *startDate;
|
|
|
|
NSString *filter;
|
|
|
|
int startDateSecs;
|
|
|
|
|
|
|
|
startDate = [self _getMaxStartDate];
|
|
|
|
if (startDate)
|
|
|
|
{
|
|
|
|
startDateSecs = (int) [startDate timeIntervalSince1970];
|
|
|
|
filter = [NSString stringWithFormat: @"c_enddate = NULL"
|
|
|
|
@" OR (c_enddate >= %d AND c_iscycle = 0)"
|
|
|
|
@" OR (c_cycleenddate >= %d AND c_iscycle = 1)",
|
|
|
|
startDateSecs, startDateSecs];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
filter = @"";
|
|
|
|
|
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (Class) objectClassForContent: (NSString *) content
|
2006-10-11 20:48:25 +02:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
iCalCalendar *calendar;
|
|
|
|
NSArray *elements;
|
|
|
|
NSString *firstTag;
|
|
|
|
Class objectClass;
|
2006-10-11 20:48:25 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
objectClass = Nil;
|
2006-10-11 20:48:25 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
calendar = [iCalCalendar parseSingleFromSource: content];
|
|
|
|
if (calendar)
|
|
|
|
{
|
|
|
|
elements = [calendar allObjects];
|
|
|
|
if ([elements count])
|
|
|
|
{
|
|
|
|
firstTag = [[[elements objectAtIndex: 0] tag] uppercaseString];
|
|
|
|
if ([firstTag isEqualToString: @"VEVENT"])
|
|
|
|
objectClass = [SOGoAppointmentObject class];
|
|
|
|
else if ([firstTag isEqualToString: @"VTODO"])
|
|
|
|
objectClass = [SOGoTaskObject class];
|
|
|
|
}
|
2006-10-11 20:48:25 +02:00
|
|
|
}
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
return objectClass;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) requestNamedIsHandledLater: (NSString *) name
|
|
|
|
{
|
|
|
|
return [name isEqualToString: @"OPTIONS"];
|
|
|
|
}
|
|
|
|
|
2008-06-30 23:11:20 +02:00
|
|
|
- (id) lookupComponentByUID: (NSString *) uid
|
|
|
|
{
|
|
|
|
NSString *filename;
|
|
|
|
id component;
|
|
|
|
|
|
|
|
filename = [self resourceNameForEventUID: uid];
|
|
|
|
if (filename)
|
|
|
|
{
|
|
|
|
component = [self lookupName: filename inContext: context acquire: NO];
|
|
|
|
if ([component isKindOfClass: [NSException class]])
|
|
|
|
component = nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
component = nil;
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (id) lookupName: (NSString *)_key
|
|
|
|
inContext: (id)_ctx
|
|
|
|
acquire: (BOOL)_flag
|
|
|
|
{
|
|
|
|
id obj;
|
|
|
|
NSString *url;
|
|
|
|
BOOL handledLater;
|
2009-07-01 21:27:44 +02:00
|
|
|
WORequest *rq;
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
/* first check attributes directly bound to the application */
|
|
|
|
handledLater = [self requestNamedIsHandledLater: _key];
|
|
|
|
if (handledLater)
|
|
|
|
obj = nil;
|
2006-10-11 20:48:25 +02:00
|
|
|
else
|
2008-06-13 22:22:51 +02:00
|
|
|
{
|
|
|
|
obj = [super lookupName:_key inContext:_ctx acquire:NO];
|
|
|
|
if (!obj)
|
|
|
|
{
|
2009-07-01 21:27:44 +02:00
|
|
|
rq = [_ctx request];
|
|
|
|
if ([self isValidContentName:_key]
|
|
|
|
&& [rq handledByDefaultHandler])
|
2008-06-13 22:22:51 +02:00
|
|
|
{
|
2009-07-01 21:27:44 +02:00
|
|
|
url = [[rq uri] urlWithoutParameters];
|
2008-07-14 17:14:40 +02:00
|
|
|
if ([url hasSuffix: @"AsTask"])
|
|
|
|
obj = [SOGoTaskObject objectWithName: _key
|
|
|
|
inContainer: self];
|
|
|
|
else if ([url hasSuffix: @"AsAppointment"])
|
|
|
|
obj = [SOGoAppointmentObject objectWithName: _key
|
|
|
|
inContainer: self];
|
2008-07-14 18:46:10 +02:00
|
|
|
[obj setIsNew: YES];
|
2008-06-13 22:22:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!obj)
|
|
|
|
obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */];
|
|
|
|
}
|
2006-10-11 20:48:25 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
if (obj)
|
|
|
|
[[SOGoCache sharedCache] registerObject: obj
|
|
|
|
withName: _key
|
|
|
|
inContainer: container];
|
|
|
|
|
|
|
|
return obj;
|
2006-10-11 20:48:25 +02:00
|
|
|
}
|
|
|
|
|
2009-07-20 20:29:09 +02:00
|
|
|
- (NSDictionary *) freebusyResponseForRecipient: (iCalPerson *) recipient
|
2008-06-30 20:52:20 +02:00
|
|
|
withUser: (SOGoUser *) user
|
|
|
|
andCalendarData: (NSString *) calendarData
|
|
|
|
{
|
|
|
|
NSDictionary *response;
|
|
|
|
NSMutableArray *content;
|
|
|
|
|
2009-06-16 23:35:23 +02:00
|
|
|
content = [NSMutableArray array];
|
2008-06-30 20:52:20 +02:00
|
|
|
|
2009-07-20 20:29:09 +02:00
|
|
|
[content addObject: davElementWithContent (@"recipient",
|
|
|
|
XMLNS_CALDAV, [recipient email])];
|
2008-06-30 20:52:20 +02:00
|
|
|
if (user)
|
|
|
|
{
|
|
|
|
[content addObject: davElementWithContent (@"request-status", XMLNS_CALDAV,
|
|
|
|
@"2.0;Success")];
|
2009-06-09 22:00:28 +02:00
|
|
|
[content addObject: davElementWithContent (@"calendar-data", XMLNS_CALDAV,
|
2009-07-19 19:22:26 +02:00
|
|
|
[calendarData stringByEscapingXMLString])];
|
2008-06-30 20:52:20 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
[content addObject:
|
|
|
|
davElementWithContent (@"request-status", XMLNS_CALDAV,
|
|
|
|
@"3.7;Invalid Calendar User")];
|
|
|
|
response = davElementWithContent (@"response", XMLNS_CALDAV, content);
|
|
|
|
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
|
2009-07-20 20:29:09 +02:00
|
|
|
- (NSDictionary *) caldavFreeBusyRequestOnRecipient: (iCalPerson *) recipient
|
2009-06-09 22:43:53 +02:00
|
|
|
withUID: (NSString *) uid
|
2009-06-09 23:10:25 +02:00
|
|
|
andOrganizer: (iCalPerson *) organizer
|
2008-06-30 20:52:20 +02:00
|
|
|
from: (NSCalendarDate *) start
|
|
|
|
to: (NSCalendarDate *) to
|
|
|
|
{
|
|
|
|
SOGoUser *user;
|
2009-07-20 20:29:09 +02:00
|
|
|
NSString *login, *calendarData;
|
2008-06-30 20:52:20 +02:00
|
|
|
SOGoFreeBusyObject *freebusy;
|
|
|
|
|
2009-07-20 20:29:09 +02:00
|
|
|
login = [recipient uid];
|
|
|
|
if ([login length])
|
2008-06-30 20:52:20 +02:00
|
|
|
{
|
2009-08-25 23:28:24 +02:00
|
|
|
user = [SOGoUser userWithLogin: login];
|
2009-07-20 20:29:09 +02:00
|
|
|
freebusy = [[user homeFolderInContext: context]
|
2008-06-30 20:52:20 +02:00
|
|
|
freeBusyObject: @"freebusy.ifb"
|
2009-07-20 20:29:09 +02:00
|
|
|
inContext: context];
|
|
|
|
calendarData = [freebusy contentAsStringWithMethod: @"REPLY"
|
|
|
|
andUID: uid
|
|
|
|
andOrganizer: organizer
|
|
|
|
from: start to: to];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
user = nil;
|
|
|
|
calendarData = nil;
|
2008-06-30 20:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return [self freebusyResponseForRecipient: recipient
|
2009-07-20 20:29:09 +02:00
|
|
|
withUser: user
|
|
|
|
andCalendarData: calendarData];
|
2008-06-30 20:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *) caldavFreeBusyRequest: (iCalFreeBusy *) freebusy
|
|
|
|
{
|
|
|
|
NSDictionary *responseElement;
|
|
|
|
NSMutableArray *elements;
|
2009-07-20 20:29:09 +02:00
|
|
|
NSString *uid;
|
|
|
|
iCalPerson *recipient, *organizer;
|
2008-07-05 00:25:27 +02:00
|
|
|
NSEnumerator *allRecipients;
|
2008-06-30 20:52:20 +02:00
|
|
|
NSCalendarDate *startDate, *endDate;
|
|
|
|
|
2009-06-16 23:35:23 +02:00
|
|
|
elements = [NSMutableArray array];
|
2008-06-30 20:52:20 +02:00
|
|
|
[freebusy fillStartDate: &startDate andEndDate: &endDate];
|
2009-06-09 22:43:53 +02:00
|
|
|
uid = [freebusy uid];
|
2009-06-09 23:10:25 +02:00
|
|
|
organizer = [freebusy organizer];
|
2009-07-20 20:29:09 +02:00
|
|
|
allRecipients = [[freebusy attendees] objectEnumerator];
|
2008-07-05 00:25:27 +02:00
|
|
|
while ((recipient = [allRecipients nextObject]))
|
2009-07-20 20:29:09 +02:00
|
|
|
[elements addObject: [self caldavFreeBusyRequestOnRecipient: recipient
|
2009-06-09 22:43:53 +02:00
|
|
|
withUID: uid
|
2009-06-09 23:10:25 +02:00
|
|
|
andOrganizer: organizer
|
2009-06-09 22:43:53 +02:00
|
|
|
from: startDate
|
|
|
|
to: endDate]];
|
2008-06-30 20:52:20 +02:00
|
|
|
responseElement = davElementWithContent (@"schedule-response",
|
|
|
|
XMLNS_CALDAV, elements);
|
|
|
|
|
|
|
|
return responseElement;
|
|
|
|
}
|
|
|
|
|
2008-07-08 17:44:50 +02:00
|
|
|
#warning we should merge this code with the code from the iTIP interpreter in MailPartViewer
|
2008-06-30 22:18:32 +02:00
|
|
|
- (NSDictionary *) caldavEventRequest: (iCalEvent *) event
|
2008-07-05 00:25:27 +02:00
|
|
|
withContent: (NSString *) iCalString
|
2008-06-30 22:18:32 +02:00
|
|
|
from: (NSString *) originator
|
|
|
|
to: (NSArray *) recipients
|
|
|
|
{
|
|
|
|
NSDictionary *responseElement;
|
2008-07-08 17:44:50 +02:00
|
|
|
NSArray *elements;
|
|
|
|
NSString *method, *filename;
|
|
|
|
SOGoAppointmentObject *apt;
|
2008-11-10 16:38:05 +01:00
|
|
|
|
2008-07-08 17:44:50 +02:00
|
|
|
filename = [NSString stringWithFormat: @"%@.ics", [event uid]];
|
|
|
|
apt = [SOGoAppointmentObject objectWithName: filename
|
|
|
|
andContent: iCalString
|
|
|
|
inContainer: self];
|
2008-06-30 22:18:32 +02:00
|
|
|
method = [[event parent] method];
|
|
|
|
if ([method isEqualToString: @"REQUEST"])
|
2008-11-10 16:38:05 +01:00
|
|
|
elements = [apt postCalDAVEventRequestTo: recipients from: originator];
|
2008-06-30 22:18:32 +02:00
|
|
|
else if ([method isEqualToString: @"REPLY"])
|
2008-11-10 16:38:05 +01:00
|
|
|
elements = [apt postCalDAVEventReplyTo: recipients from: originator];
|
2008-07-09 17:54:39 +02:00
|
|
|
else if ([method isEqualToString: @"CANCEL"])
|
2008-11-10 16:38:05 +01:00
|
|
|
elements = [apt postCalDAVEventCancelTo: recipients from: originator];
|
2008-07-08 17:44:50 +02:00
|
|
|
else
|
|
|
|
elements = nil;
|
|
|
|
|
|
|
|
if (elements)
|
|
|
|
responseElement = davElementWithContent (@"schedule-response",
|
|
|
|
XMLNS_CALDAV, elements);
|
2008-06-30 22:18:32 +02:00
|
|
|
else
|
|
|
|
responseElement = nil;
|
|
|
|
|
|
|
|
return responseElement;
|
|
|
|
}
|
|
|
|
|
2008-06-30 20:52:20 +02:00
|
|
|
- (WOResponse *) _caldavScheduleResponse: (NSDictionary *) tags
|
|
|
|
{
|
|
|
|
WOResponse *response;
|
|
|
|
|
|
|
|
response = [context response];
|
|
|
|
if (tags)
|
|
|
|
{
|
2009-07-20 20:23:44 +02:00
|
|
|
// WARNING
|
|
|
|
// don't touch unless you're going to re-test caldav sync
|
|
|
|
// with an iPhone AND lightning
|
2008-06-30 20:52:20 +02:00
|
|
|
[response setStatus: 200];
|
2009-07-19 19:22:54 +02:00
|
|
|
[response appendContentString: @"<?xml version=\"1.0\""
|
2009-07-19 19:22:26 +02:00
|
|
|
@" encoding=\"utf-8\"?>"];
|
2008-06-30 20:52:20 +02:00
|
|
|
[response setHeader: @"application/xml; charset=utf-8"
|
2009-07-17 20:36:09 +02:00
|
|
|
forKey: @"Content-Type"];
|
2008-06-30 20:52:20 +02:00
|
|
|
[response appendContentString:
|
|
|
|
[tags asWebDavStringWithNamespaces: nil]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[response setStatus: 415];
|
|
|
|
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
|
2008-07-05 00:25:27 +02:00
|
|
|
- (WOResponse *) caldavScheduleRequest: (NSString *) iCalString
|
|
|
|
from: (NSString *) originator
|
|
|
|
to: (NSArray *) recipients
|
2008-06-30 20:52:20 +02:00
|
|
|
{
|
2008-07-05 00:25:27 +02:00
|
|
|
NSString *tag;
|
|
|
|
iCalCalendar *calendar;
|
2008-06-30 20:52:20 +02:00
|
|
|
iCalEntityObject *element;
|
|
|
|
NSDictionary *tags;
|
|
|
|
|
|
|
|
#warning needs to handle errors
|
2008-07-05 00:25:27 +02:00
|
|
|
calendar = [iCalCalendar parseSingleFromSource: iCalString];
|
|
|
|
element = [[calendar allObjects] objectAtIndex: 0];
|
|
|
|
tag = [[element tag] uppercaseString];
|
|
|
|
if ([tag isEqualToString: @"VFREEBUSY"])
|
2009-07-20 20:29:09 +02:00
|
|
|
tags = [self caldavFreeBusyRequest: (iCalFreeBusy *) element];
|
2008-07-05 00:25:27 +02:00
|
|
|
else if ([tag isEqualToString: @"VEVENT"])
|
|
|
|
tags = [self caldavEventRequest: (iCalEvent *) element
|
|
|
|
withContent: iCalString
|
|
|
|
from: originator to: recipients];
|
|
|
|
else
|
|
|
|
tags = nil;
|
2008-06-30 20:52:20 +02:00
|
|
|
|
|
|
|
return [self _caldavScheduleResponse: tags];
|
|
|
|
}
|
|
|
|
|
2008-07-04 20:22:06 +02:00
|
|
|
- (id) davPOSTRequest: (WORequest *) request
|
|
|
|
withContentType: (NSString *) cType
|
|
|
|
inContext: (WOContext *) localContext
|
2008-06-30 20:52:20 +02:00
|
|
|
{
|
|
|
|
id obj;
|
2008-07-05 00:25:27 +02:00
|
|
|
NSString *originator;
|
|
|
|
NSArray *recipients;
|
2008-06-30 20:52:20 +02:00
|
|
|
|
2008-07-04 20:22:06 +02:00
|
|
|
if ([cType hasPrefix: @"text/calendar"])
|
2008-06-30 20:52:20 +02:00
|
|
|
{
|
2008-07-05 00:25:27 +02:00
|
|
|
originator = [request headerForKey: @"originator"];
|
2008-11-10 16:38:05 +01:00
|
|
|
|
|
|
|
if ([[originator lowercaseString] hasPrefix: @"mailto:"])
|
|
|
|
originator = [originator substringFromIndex: 7];
|
|
|
|
|
2008-07-05 00:25:27 +02:00
|
|
|
recipients = [[request headerForKey: @"recipient"]
|
2009-07-23 19:34:10 +02:00
|
|
|
componentsSeparatedByString: @","];
|
2008-07-05 00:25:27 +02:00
|
|
|
obj = [self caldavScheduleRequest: [request contentAsString]
|
2009-07-23 19:34:10 +02:00
|
|
|
from: originator to: [recipients trimmedComponents]];
|
2008-06-30 20:52:20 +02:00
|
|
|
}
|
2008-07-04 20:22:06 +02:00
|
|
|
else
|
|
|
|
obj = [super davPOSTRequest: request withContentType: cType
|
|
|
|
inContext: localContext];
|
2008-06-30 20:52:20 +02:00
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (NSArray *) davComplianceClassesInContext: (id)_ctx
|
2006-10-30 23:39:31 +01:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
NSMutableArray *classes;
|
|
|
|
NSArray *primaryClasses;
|
2006-10-30 23:39:31 +01:00
|
|
|
|
2009-06-16 23:35:23 +02:00
|
|
|
classes = [NSMutableArray array];
|
2006-10-30 23:39:31 +01:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
primaryClasses = [super davComplianceClassesInContext: _ctx];
|
|
|
|
if (primaryClasses)
|
|
|
|
[classes addObjectsFromArray: primaryClasses];
|
|
|
|
[classes addObject: @"calendar-access"];
|
2010-08-11 16:52:11 +02:00
|
|
|
//[classes addObject: @"calendar-schedule"];
|
|
|
|
[classes addObject: @"calendar-auto-schedule"];
|
2008-06-13 22:22:51 +02:00
|
|
|
|
|
|
|
return classes;
|
2006-10-30 23:39:31 +01:00
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (NSArray *) groupDavResourceType
|
2007-04-26 03:16:19 +02:00
|
|
|
{
|
2008-06-13 22:22:51 +02:00
|
|
|
return [NSArray arrayWithObjects: @"vevent-collection",
|
|
|
|
@"vtodo-collection", nil];
|
|
|
|
}
|
2007-04-26 03:16:19 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
- (NSArray *) davResourceType
|
|
|
|
{
|
2009-06-19 17:34:22 +02:00
|
|
|
NSMutableArray *colType;
|
|
|
|
NSArray *gdRT, *gdVEventCol, *gdVTodoCol;
|
2009-07-20 20:20:44 +02:00
|
|
|
WORequest *request;
|
2009-06-19 17:34:22 +02:00
|
|
|
|
|
|
|
colType = [NSMutableArray arrayWithCapacity: 10];
|
|
|
|
[colType addObject: @"collection"];
|
|
|
|
[colType addObject: [NSArray arrayWithObjects: @"calendar", XMLNS_CALDAV, nil]];
|
|
|
|
|
2009-07-20 20:49:56 +02:00
|
|
|
/* iPhone compatibility: we can only return a caldav "calendar"
|
|
|
|
resourcetype. Anything else will prevent the iPhone from querying the
|
|
|
|
collection. */
|
2009-07-20 20:20:44 +02:00
|
|
|
request = [context request];
|
2009-10-21 23:17:11 +02:00
|
|
|
if (!([request isIPhone] || [request isICal4]))
|
2007-04-26 03:16:19 +02:00
|
|
|
{
|
2009-07-20 20:20:44 +02:00
|
|
|
gdRT = [self groupDavResourceType];
|
|
|
|
gdVEventCol = [NSArray arrayWithObjects: [gdRT objectAtIndex: 0],
|
|
|
|
XMLNS_GROUPDAV, nil];
|
|
|
|
[colType addObject: gdVEventCol];
|
|
|
|
gdVTodoCol = [NSArray arrayWithObjects: [gdRT objectAtIndex: 1],
|
|
|
|
XMLNS_GROUPDAV, nil];
|
|
|
|
[colType addObject: gdVTodoCol];
|
|
|
|
if ([nameInContainer isEqualToString: @"personal"])
|
2010-01-21 00:09:35 +01:00
|
|
|
[colType addObject: [NSArray arrayWithObjects: @"schedule-outbox",
|
|
|
|
XMLNS_CALDAV, nil]];
|
2007-04-26 03:16:19 +02:00
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
return colType;
|
2007-04-26 03:16:19 +02:00
|
|
|
}
|
|
|
|
|
2009-06-19 18:20:49 +02:00
|
|
|
- (SOGoWebDAVValue *) davCalendarComponentSet
|
|
|
|
{
|
|
|
|
static SOGoWebDAVValue *componentSet = nil;
|
|
|
|
NSMutableArray *components;
|
|
|
|
|
|
|
|
if (!componentSet)
|
|
|
|
{
|
|
|
|
components = [NSMutableArray array];
|
|
|
|
/* Totally hackish.... we use the "n1" prefix because we know our
|
|
|
|
extensions will assign that one to ..:caldav but we really need to
|
|
|
|
handle element attributes */
|
|
|
|
[components addObject: [SOGoWebDAVValue
|
|
|
|
valueForObject: @"<n1:comp name=\"VEVENT\"/>"
|
|
|
|
attributes: nil]];
|
|
|
|
[components addObject: [SOGoWebDAVValue
|
|
|
|
valueForObject: @"<n1:comp name=\"VTODO\"/>"
|
|
|
|
attributes: nil]];
|
|
|
|
componentSet
|
|
|
|
= [davElementWithContent (@"supported-calendar-component-set",
|
|
|
|
XMLNS_CALDAV,
|
|
|
|
components)
|
|
|
|
asWebDAVValue];
|
2009-06-30 23:34:17 +02:00
|
|
|
[componentSet retain];
|
2009-06-19 18:20:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return componentSet;
|
|
|
|
}
|
|
|
|
|
2008-06-30 20:52:20 +02:00
|
|
|
- (NSString *) davDescription
|
|
|
|
{
|
|
|
|
return @"";
|
|
|
|
}
|
|
|
|
|
2010-05-06 21:30:14 +02:00
|
|
|
- (NSArray *) davScheduleCalendarTransparency
|
|
|
|
{
|
|
|
|
const NSString *opacity;
|
|
|
|
|
|
|
|
opacity = ([self includeInFreeBusy] ? @"opaque" : @"transparent");
|
|
|
|
|
|
|
|
return [NSArray arrayWithObject: [NSArray arrayWithObjects: opacity,
|
|
|
|
XMLNS_CALDAV,
|
|
|
|
nil]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSException *) setDavScheduleCalendarTransparency: (id) newName
|
|
|
|
{
|
|
|
|
NSException *error;
|
|
|
|
|
|
|
|
error = nil;
|
|
|
|
|
|
|
|
if ([newName rangeOfString: @"opaque"].location != NSNotFound)
|
|
|
|
[self setIncludeInFreeBusy: YES];
|
|
|
|
else if ([newName rangeOfString: @"transparent"].location != NSNotFound)
|
|
|
|
[self setIncludeInFreeBusy: NO];
|
|
|
|
else
|
|
|
|
error = [NSException exceptionWithHTTPStatus: 400
|
|
|
|
reason: @"Bad transparency value."];
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
/* vevent UID handling */
|
2007-03-07 22:27:19 +01:00
|
|
|
|
2008-06-30 23:11:20 +02:00
|
|
|
- (NSString *) resourceNameForEventUID: (NSString *) uid
|
|
|
|
inFolder: (GCSFolder *) folder
|
2008-06-13 22:22:51 +02:00
|
|
|
{
|
|
|
|
static NSArray *nameFields = nil;
|
|
|
|
EOQualifier *qualifier;
|
2008-06-30 23:11:20 +02:00
|
|
|
NSArray *records;
|
|
|
|
NSString *filename;
|
|
|
|
unsigned int count;
|
|
|
|
|
2008-06-30 23:46:05 +02:00
|
|
|
filename = nil;
|
|
|
|
|
2008-06-30 23:11:20 +02:00
|
|
|
if (!nameFields)
|
2008-06-13 22:22:51 +02:00
|
|
|
nameFields = [[NSArray alloc] initWithObjects: @"c_name", nil];
|
2008-06-30 23:11:20 +02:00
|
|
|
|
|
|
|
if (uid && folder)
|
|
|
|
{
|
2008-07-05 00:25:27 +02:00
|
|
|
qualifier = [EOQualifier qualifierWithQualifierFormat: @"c_uid = %@",
|
|
|
|
uid];
|
2008-06-30 23:11:20 +02:00
|
|
|
records = [folder fetchFields: nameFields matchingQualifier: qualifier];
|
|
|
|
count = [records count];
|
|
|
|
if (count)
|
|
|
|
{
|
2009-06-24 01:38:52 +02:00
|
|
|
filename = [[records objectAtIndex:0] valueForKey: @"c_name"];
|
2008-06-30 23:11:20 +02:00
|
|
|
if (count > 1)
|
|
|
|
[self errorWithFormat:
|
2008-07-05 00:25:27 +02:00
|
|
|
@"The storage contains more than file with UID '%@'",
|
|
|
|
uid];
|
2008-06-30 23:11:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return filename;
|
2008-06-13 22:22:51 +02:00
|
|
|
}
|
2007-03-07 22:27:19 +01:00
|
|
|
|
2008-06-30 23:11:20 +02:00
|
|
|
- (NSString *) resourceNameForEventUID: (NSString *) uid
|
2008-06-13 22:22:51 +02:00
|
|
|
{
|
|
|
|
/* caches UIDs */
|
|
|
|
GCSFolder *folder;
|
|
|
|
NSString *rname;
|
2008-06-30 23:11:20 +02:00
|
|
|
|
|
|
|
rname = nil;
|
|
|
|
if (uid)
|
2007-03-07 22:27:19 +01:00
|
|
|
{
|
2008-06-30 23:11:20 +02:00
|
|
|
if (!uidToFilename)
|
|
|
|
uidToFilename = [NSMutableDictionary new];
|
|
|
|
rname = [uidToFilename objectForKey: uid];
|
|
|
|
if (!rname)
|
|
|
|
{
|
|
|
|
folder = [self ocsFolder];
|
|
|
|
rname = [self resourceNameForEventUID: uid inFolder: folder];
|
|
|
|
if (rname)
|
|
|
|
[uidToFilename setObject: rname forKey: uid];
|
|
|
|
}
|
2007-03-07 22:27:19 +01:00
|
|
|
}
|
2008-06-30 23:11:20 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
return rname;
|
2007-03-07 22:27:19 +01:00
|
|
|
}
|
|
|
|
|
2007-11-29 17:14:11 +01:00
|
|
|
- (NSArray *) subscriptionRoles
|
|
|
|
{
|
|
|
|
return [NSArray arrayWithObjects:
|
2008-12-23 16:51:12 +01:00
|
|
|
SOGoRole_ObjectCreator,
|
|
|
|
SOGoRole_ObjectEraser,
|
2007-11-29 17:14:11 +01:00
|
|
|
SOGoCalendarRole_PublicResponder,
|
|
|
|
SOGoCalendarRole_PublicModifier,
|
|
|
|
SOGoCalendarRole_PublicViewer,
|
|
|
|
SOGoCalendarRole_PublicDAndTViewer,
|
|
|
|
SOGoCalendarRole_PrivateResponder,
|
|
|
|
SOGoCalendarRole_PrivateModifier,
|
|
|
|
SOGoCalendarRole_PrivateViewer,
|
|
|
|
SOGoCalendarRole_PrivateDAndTViewer,
|
|
|
|
SOGoCalendarRole_ConfidentialResponder,
|
|
|
|
SOGoCalendarRole_ConfidentialModifier,
|
|
|
|
SOGoCalendarRole_ConfidentialViewer,
|
|
|
|
SOGoCalendarRole_ConfidentialDAndTViewer, nil];
|
|
|
|
}
|
|
|
|
|
2007-04-26 03:16:19 +02:00
|
|
|
- (NSString *) roleForComponentsWithAccessClass: (iCalAccessClass) accessClass
|
|
|
|
forUser: (NSString *) uid
|
|
|
|
{
|
2009-07-27 23:36:03 +02:00
|
|
|
NSString *accessRole, *ownerLogin, *prefix, *currentRole, *suffix;
|
2007-04-26 03:16:19 +02:00
|
|
|
NSEnumerator *acls;
|
2007-11-26 18:40:44 +01:00
|
|
|
NSMutableDictionary *userRoles;
|
2007-04-26 03:16:19 +02:00
|
|
|
|
|
|
|
accessRole = nil;
|
|
|
|
|
|
|
|
if (accessClass == iCalAccessPublic)
|
|
|
|
prefix = @"Public";
|
|
|
|
else if (accessClass == iCalAccessPrivate)
|
|
|
|
prefix = @"Private";
|
|
|
|
else
|
|
|
|
prefix = @"Confidential";
|
|
|
|
|
2007-11-26 18:40:44 +01:00
|
|
|
userRoles = [aclMatrix objectForKey: uid];
|
|
|
|
if (!userRoles)
|
|
|
|
{
|
|
|
|
userRoles = [NSMutableDictionary dictionaryWithCapacity: 3];
|
|
|
|
[aclMatrix setObject: userRoles forKey: uid];
|
|
|
|
}
|
2009-07-27 23:36:03 +02:00
|
|
|
|
2007-11-26 18:40:44 +01:00
|
|
|
accessRole = [userRoles objectForKey: prefix];
|
|
|
|
if (!accessRole)
|
|
|
|
{
|
2009-07-27 23:36:03 +02:00
|
|
|
ownerLogin = [self ownerInContext: context];
|
|
|
|
if ([ownerLogin isEqualToString: uid])
|
2007-11-26 18:40:44 +01:00
|
|
|
accessRole = @"";
|
2009-07-27 23:36:03 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
acls = [[self aclsForUser: uid] objectEnumerator];
|
|
|
|
currentRole = [acls nextObject];
|
|
|
|
while (currentRole && !accessRole)
|
|
|
|
if ([currentRole hasPrefix: prefix])
|
|
|
|
{
|
|
|
|
suffix = [currentRole substringFromIndex: [prefix length]];
|
|
|
|
accessRole = [NSString stringWithFormat: @"Component%@", suffix];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
currentRole = [acls nextObject];
|
|
|
|
if (!accessRole)
|
|
|
|
accessRole = @"";
|
|
|
|
}
|
2007-11-26 18:40:44 +01:00
|
|
|
[userRoles setObject: accessRole forKey: prefix];
|
|
|
|
}
|
2007-04-26 03:16:19 +02:00
|
|
|
|
|
|
|
return accessRole;
|
|
|
|
}
|
|
|
|
|
2009-06-04 02:40:21 +02:00
|
|
|
- (void) initializeQuickTablesAclsInContext: (WOContext *) localContext
|
|
|
|
{
|
|
|
|
NSString *login, *role, *permission;
|
|
|
|
iCalAccessClass currentClass;
|
|
|
|
unsigned int permStrIndex;
|
|
|
|
|
|
|
|
[super initializeQuickTablesAclsInContext: localContext];
|
|
|
|
/* We assume "userIsOwner" will be set after calling the super method. */
|
2009-06-04 02:51:47 +02:00
|
|
|
if (!userCanAccessAllObjects)
|
2009-06-04 02:40:21 +02:00
|
|
|
{
|
|
|
|
login = [[localContext activeUser] login];
|
|
|
|
permStrIndex = [@"Component" length];
|
|
|
|
}
|
|
|
|
|
|
|
|
for (currentClass = 0; currentClass < iCalAccessClassCount; currentClass++)
|
|
|
|
{
|
2009-06-04 02:51:47 +02:00
|
|
|
if (userCanAccessAllObjects)
|
2009-06-04 02:40:21 +02:00
|
|
|
userCanAccessObjectsClassifiedAs[currentClass] = YES;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
role = [self roleForComponentsWithAccessClass: currentClass
|
|
|
|
forUser: login];
|
|
|
|
if ([role length])
|
|
|
|
{
|
|
|
|
permission = [role substringFromIndex: permStrIndex];
|
|
|
|
userCanAccessObjectsClassifiedAs[currentClass]
|
|
|
|
= ([permission isEqualToString: @"Viewer"]
|
|
|
|
|| [permission isEqualToString: @"DAndTViewer"]
|
|
|
|
|| [permission isEqualToString: @"Modifier"]
|
|
|
|
|| [permission isEqualToString: @"Responder"]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-14 22:20:13 +01:00
|
|
|
- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) _startDate
|
2006-08-16 00:04:37 +02:00
|
|
|
to: (NSCalendarDate *) _endDate
|
2006-06-15 21:34:10 +02:00
|
|
|
{
|
|
|
|
static NSArray *infos = nil; // TODO: move to a plist file
|
2006-10-26 02:08:24 +02:00
|
|
|
|
|
|
|
if (!infos)
|
2007-07-24 20:45:52 +02:00
|
|
|
infos = [[NSArray alloc] initWithObjects: @"c_partmails", @"c_partstates",
|
2008-11-20 20:17:59 +01:00
|
|
|
@"c_isopaque", @"c_status", @"c_cycleinfo", @"c_orgmail", nil];
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-12-30 20:48:33 +01:00
|
|
|
// We MUST include the protected information when checking for freebusy info as
|
2008-12-23 19:43:37 +01:00
|
|
|
// we rely on the c_partmails/c_partstates fields for many operations.
|
2008-05-16 17:52:19 +02:00
|
|
|
return [self fetchFields: infos
|
|
|
|
from: _startDate to: _endDate
|
2007-11-21 18:23:51 +01:00
|
|
|
title: nil
|
2008-05-16 17:52:19 +02:00
|
|
|
component: @"vevent"
|
2008-12-23 19:43:37 +01:00
|
|
|
additionalFilters: nil
|
|
|
|
includeProtectedInformation: YES];
|
2006-10-26 02:08:24 +02:00
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
- (NSArray *) fetchCoreInfosFrom: (NSCalendarDate *) _startDate
|
2006-10-11 20:48:25 +02:00
|
|
|
to: (NSCalendarDate *) _endDate
|
2007-11-21 18:23:51 +01:00
|
|
|
title: (NSString *) title
|
2006-10-11 20:48:25 +02:00
|
|
|
component: (id) _component
|
2008-05-16 17:52:19 +02:00
|
|
|
{
|
|
|
|
return [self fetchCoreInfosFrom: _startDate to: _endDate title: title
|
|
|
|
component: _component additionalFilters: nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) fetchCoreInfosFrom: (NSCalendarDate *) _startDate
|
|
|
|
to: (NSCalendarDate *) _endDate
|
|
|
|
title: (NSString *) title
|
|
|
|
component: (id) _component
|
|
|
|
additionalFilters: (NSString *) filters
|
2006-06-15 21:34:10 +02:00
|
|
|
{
|
|
|
|
static NSArray *infos = nil; // TODO: move to a plist file
|
2006-08-16 00:04:37 +02:00
|
|
|
|
2006-10-11 20:48:25 +02:00
|
|
|
if (!infos)
|
2008-06-13 22:22:51 +02:00
|
|
|
infos = [[NSArray alloc] initWithObjects: @"c_name", @"c_content",
|
|
|
|
@"c_creationdate", @"c_lastmodified",
|
|
|
|
@"c_version", @"c_component", @"c_title",
|
|
|
|
@"c_location", @"c_orgmail", @"c_status",
|
2010-05-16 19:13:11 +02:00
|
|
|
@"c_category", @"c_classification", @"c_isallday",
|
2008-06-13 22:22:51 +02:00
|
|
|
@"c_isopaque", @"c_participants", @"c_partmails",
|
|
|
|
@"c_partstates", @"c_sequence", @"c_priority",
|
2009-04-24 21:19:43 +02:00
|
|
|
@"c_cycleinfo", @"c_iscycle", @"c_nextalarm", nil];
|
2006-10-11 20:48:25 +02:00
|
|
|
|
2007-11-21 18:23:51 +01:00
|
|
|
return [self fetchFields: infos from: _startDate to: _endDate title: title
|
2008-05-16 17:52:19 +02:00
|
|
|
component: _component
|
2008-12-23 19:43:37 +01:00
|
|
|
additionalFilters: filters
|
|
|
|
includeProtectedInformation: NO];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2009-04-22 23:02:11 +02:00
|
|
|
- (NSArray *) fetchAlarmInfosFrom: (NSNumber *) _startUTCDate
|
|
|
|
to: (NSNumber *) _endUTCDate
|
|
|
|
{
|
|
|
|
static NSArray *nameFields = nil;
|
|
|
|
EOQualifier *qualifier;
|
|
|
|
GCSFolder *folder;
|
|
|
|
NSArray *records;
|
|
|
|
NSString *sql;
|
|
|
|
|
|
|
|
if (!nameFields)
|
|
|
|
nameFields = [[NSArray alloc] initWithObjects: @"c_name", @"c_nextalarm", @"c_iscycle", nil];
|
|
|
|
|
|
|
|
folder = [self ocsFolder];
|
|
|
|
if (!folder)
|
|
|
|
{
|
|
|
|
[self errorWithFormat:@"(%s): missing folder for fetch!",
|
|
|
|
__PRETTY_FUNCTION__];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
sql = [NSString stringWithFormat: @"((c_nextalarm <= %u) AND (c_nextalarm >= %u)) OR ((c_nextalarm > 0) AND (c_enddate > %u))",
|
|
|
|
[_endUTCDate unsignedIntValue], [_startUTCDate unsignedIntValue], [_startUTCDate unsignedIntValue]];
|
|
|
|
qualifier = [EOQualifier qualifierWithQualifierFormat: sql];
|
|
|
|
records = [folder fetchFields: nameFields matchingQualifier: qualifier];
|
|
|
|
|
|
|
|
return records;
|
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* URL generation */
|
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
- (NSString *) baseURLForAptWithUID: (NSString *)_uid
|
|
|
|
inContext: (id)_ctx
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
// TODO: who calls this?
|
|
|
|
NSString *url;
|
|
|
|
|
|
|
|
if ([_uid length] == 0)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
url = [self baseURLInContext:_ctx];
|
2007-06-01 06:15:56 +02:00
|
|
|
if (![url hasSuffix: @"/"])
|
|
|
|
url = [url stringByAppendingString: @"/"];
|
2006-06-15 21:34:10 +02:00
|
|
|
|
|
|
|
// TODO: this should run a query to determine the uid!
|
|
|
|
return [url stringByAppendingString:_uid];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* folder management */
|
2007-11-08 18:12:30 +01:00
|
|
|
- (BOOL) create
|
|
|
|
{
|
|
|
|
BOOL rc;
|
2009-11-29 05:19:32 +01:00
|
|
|
SOGoUserSettings *userSettings;
|
2007-11-08 18:12:30 +01:00
|
|
|
NSMutableDictionary *calendarSettings;
|
|
|
|
SOGoUser *ownerUser;
|
|
|
|
|
|
|
|
rc = [super create];
|
|
|
|
if (rc)
|
|
|
|
{
|
2009-08-25 23:28:24 +02:00
|
|
|
ownerUser = [SOGoUser userWithLogin: [self ownerInContext: context]];
|
2007-11-08 18:12:30 +01:00
|
|
|
userSettings = [ownerUser userSettings];
|
|
|
|
calendarSettings = [userSettings objectForKey: @"Calendar"];
|
|
|
|
if (!calendarSettings)
|
|
|
|
{
|
|
|
|
calendarSettings = [NSMutableDictionary dictionary];
|
|
|
|
[userSettings setObject: calendarSettings forKey: @"Calendar"];
|
|
|
|
}
|
|
|
|
[userSettings synchronize];
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2010-10-08 21:53:04 +02:00
|
|
|
- (void) removeFolderSettings: (NSMutableDictionary *) moduleSettings
|
|
|
|
withReference: (NSString *) reference
|
|
|
|
{
|
|
|
|
NSMutableArray *refArray;
|
|
|
|
NSMutableDictionary *refDict;
|
|
|
|
|
|
|
|
refDict = [moduleSettings objectForKey: @"FreeBusyExclusions"];
|
|
|
|
[refDict removeObjectForKey: reference];
|
|
|
|
|
|
|
|
refDict = [moduleSettings objectForKey: @"FolderColors"];
|
|
|
|
[refDict removeObjectForKey: reference];
|
|
|
|
|
|
|
|
refDict = [moduleSettings objectForKey: @"FolderShowAlarms"];
|
|
|
|
[refDict removeObjectForKey: reference];
|
|
|
|
|
|
|
|
refDict = [moduleSettings objectForKey: @"FolderShowTasks"];
|
|
|
|
[refDict removeObjectForKey: reference];
|
|
|
|
|
|
|
|
refArray = [moduleSettings objectForKey: @"InactiveFolders"];
|
|
|
|
[refArray removeObject: nameInContainer];
|
|
|
|
|
|
|
|
refDict = [moduleSettings objectForKey: @"FolderSyncTags"];
|
|
|
|
[refDict removeObjectForKey: reference];
|
|
|
|
|
|
|
|
refDict = [moduleSettings objectForKey: @"FolderSynchronize"];
|
|
|
|
[refDict removeObjectForKey: reference];
|
|
|
|
|
|
|
|
[super removeFolderSettings: moduleSettings
|
|
|
|
withReference: reference];
|
|
|
|
}
|
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
- (id) lookupHomeFolderForUID: (NSString *) _uid
|
|
|
|
inContext: (id)_ctx
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
// TODO: DUP to SOGoGroupFolder
|
|
|
|
NSException *error = nil;
|
|
|
|
NSArray *path;
|
|
|
|
id ctx, result;
|
|
|
|
|
|
|
|
if (![_uid isNotNull])
|
|
|
|
return nil;
|
2007-06-01 06:15:56 +02:00
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* create subcontext, so that we don't destroy our environment */
|
|
|
|
|
2007-04-11 21:08:58 +02:00
|
|
|
if ((ctx = [context createSubContext]) == nil) {
|
2006-06-15 21:34:10 +02:00
|
|
|
[self errorWithFormat:@"could not create SOPE subcontext!"];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* build path */
|
|
|
|
|
|
|
|
path = _uid != nil ? [NSArray arrayWithObjects:&_uid count:1] : nil;
|
|
|
|
|
|
|
|
/* traverse path */
|
|
|
|
|
|
|
|
result = [[ctx application] traversePathArray:path inContext:ctx
|
|
|
|
error:&error acquire:NO];
|
|
|
|
if (error != nil) {
|
2007-07-27 19:30:57 +02:00
|
|
|
[self errorWithFormat: @"folder lookup failed (c_uid=%@): %@",
|
2006-06-15 21:34:10 +02:00
|
|
|
_uid, error];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
[self debugWithFormat:@"Note: got folder for uid %@ path %@: %@",
|
|
|
|
_uid, [path componentsJoinedByString:@"=>"], result];
|
2008-08-18 17:21:23 +02:00
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-03-23 22:19:55 +01:00
|
|
|
//
|
|
|
|
// This method returns an array containing all the calendar folders
|
|
|
|
// of a specific user, excluding her/his subscriptions.
|
|
|
|
//
|
|
|
|
- (NSArray *) lookupCalendarFoldersForUID: (NSString *) theUID
|
|
|
|
{
|
|
|
|
NSArray *aFolders;
|
|
|
|
NSEnumerator *e;
|
|
|
|
NSMutableArray *aUserFolders;
|
|
|
|
SOGoAppointmentFolders *aParent;
|
|
|
|
SOGoFolder *aContainer, *aFolder;
|
|
|
|
|
|
|
|
aUserFolders = [NSMutableArray arrayWithCapacity: 16];
|
|
|
|
aContainer = [[container container] container];
|
|
|
|
aContainer = [aContainer lookupName: theUID
|
|
|
|
inContext: context
|
|
|
|
acquire: NO];
|
|
|
|
aParent = [aContainer lookupName: @"Calendar"
|
|
|
|
inContext: context
|
|
|
|
acquire: NO];
|
|
|
|
aFolders = [aParent subFolders];
|
|
|
|
e = [aFolders objectEnumerator];
|
|
|
|
while ( (aFolder = [e nextObject]) )
|
|
|
|
{
|
|
|
|
if (![aFolder isSubscription])
|
|
|
|
[aUserFolders addObject: aFolder];
|
|
|
|
}
|
|
|
|
|
|
|
|
return aUserFolders;
|
|
|
|
}
|
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
- (NSArray *) lookupCalendarFoldersForUIDs: (NSArray *) _uids
|
|
|
|
inContext: (id)_ctx
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
/* Note: can return NSNull objects in the array! */
|
|
|
|
NSMutableArray *folders;
|
|
|
|
NSEnumerator *e;
|
2007-09-15 00:01:02 +02:00
|
|
|
NSString *uid, *ownerLogin;
|
2010-07-15 19:05:29 +02:00
|
|
|
SOGoUser *user;
|
2007-09-15 00:01:02 +02:00
|
|
|
id folder;
|
|
|
|
|
|
|
|
ownerLogin = [self ownerInContext: context];
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
if ([_uids count] == 0) return nil;
|
|
|
|
folders = [NSMutableArray arrayWithCapacity:16];
|
|
|
|
e = [_uids objectEnumerator];
|
2007-09-15 00:01:02 +02:00
|
|
|
while ((uid = [e nextObject]))
|
|
|
|
{
|
|
|
|
if ([uid isEqualToString: ownerLogin])
|
|
|
|
folder = self;
|
|
|
|
else
|
|
|
|
{
|
2010-07-15 19:05:29 +02:00
|
|
|
user = [SOGoUser userWithLogin: uid];
|
|
|
|
folder = [user personalCalendarFolderInContext: context];
|
2007-09-15 00:01:02 +02:00
|
|
|
if (![folder isNotNull])
|
|
|
|
[self logWithFormat:@"Note: did not find folder for uid: '%@'", uid];
|
|
|
|
}
|
2007-11-07 16:58:43 +01:00
|
|
|
|
|
|
|
if (folder)
|
|
|
|
[folders addObject: folder];
|
2007-09-15 00:01:02 +02:00
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
return folders;
|
|
|
|
}
|
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
- (NSArray *) lookupFreeBusyObjectsForUIDs: (NSArray *) _uids
|
|
|
|
inContext: (id) _ctx
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
/* Note: can return NSNull objects in the array! */
|
|
|
|
NSMutableArray *objs;
|
|
|
|
NSEnumerator *e;
|
|
|
|
NSString *uid;
|
|
|
|
|
|
|
|
if ([_uids count] == 0) return nil;
|
|
|
|
objs = [NSMutableArray arrayWithCapacity:16];
|
|
|
|
e = [_uids objectEnumerator];
|
2008-05-16 17:52:19 +02:00
|
|
|
while ((uid = [e nextObject]))
|
|
|
|
{
|
|
|
|
id obj;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-05-16 17:52:19 +02:00
|
|
|
obj = [self lookupHomeFolderForUID:uid inContext:nil];
|
|
|
|
if ([obj isNotNull])
|
|
|
|
{
|
|
|
|
obj = [obj lookupName: @"freebusy.ifb" inContext: nil acquire: NO];
|
|
|
|
if ([obj isKindOfClass: [NSException class]])
|
|
|
|
obj = nil;
|
|
|
|
}
|
|
|
|
if (![obj isNotNull])
|
|
|
|
[self logWithFormat: @"Note: did not find freebusy.ifb for uid: '%@'",
|
|
|
|
uid];
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-05-16 17:52:19 +02:00
|
|
|
/* Note: intentionally add 'null' folders to allow a mapping */
|
|
|
|
if (!obj)
|
|
|
|
obj = [NSNull null];
|
|
|
|
[objs addObject: obj];
|
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
return objs;
|
|
|
|
}
|
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
- (NSArray *) uidsFromICalPersons: (NSArray *) _persons
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
/* Note: can return NSNull objects in the array! */
|
|
|
|
NSMutableArray *uids;
|
2009-09-25 16:42:33 +02:00
|
|
|
SOGoUserManager *um;
|
2006-06-15 21:34:10 +02:00
|
|
|
unsigned i, count;
|
2008-06-30 20:52:20 +02:00
|
|
|
iCalPerson *person;
|
|
|
|
NSString *email;
|
|
|
|
NSString *uid;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-06-30 20:52:20 +02:00
|
|
|
if (_persons)
|
2008-05-16 17:52:19 +02:00
|
|
|
{
|
2008-06-30 20:52:20 +02:00
|
|
|
count = [_persons count];
|
|
|
|
uids = [NSMutableArray arrayWithCapacity:count + 1];
|
2009-09-25 16:42:33 +02:00
|
|
|
um = [SOGoUserManager sharedUserManager];
|
2008-06-30 20:52:20 +02:00
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
person = [_persons objectAtIndex:i];
|
|
|
|
email = [person rfc822Email];
|
|
|
|
if ([email isNotNull])
|
|
|
|
uid = [um getUIDForEmail:email];
|
|
|
|
else
|
|
|
|
uid = nil;
|
|
|
|
|
|
|
|
if (!uid)
|
|
|
|
uid = (NSString *) [NSNull null];
|
|
|
|
[uids addObject: uid];
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
2008-06-30 20:52:20 +02:00
|
|
|
else
|
|
|
|
uids = nil;
|
2008-05-16 17:52:19 +02:00
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
return uids;
|
|
|
|
}
|
|
|
|
|
2008-06-30 20:52:20 +02:00
|
|
|
- (NSArray *) lookupCalendarFoldersForICalPerson: (NSArray *) _persons
|
|
|
|
inContext: (id) _ctx
|
2006-06-15 21:34:10 +02:00
|
|
|
{
|
|
|
|
/* Note: can return NSNull objects in the array! */
|
2008-06-30 20:52:20 +02:00
|
|
|
NSArray *uids, *folders;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-06-30 20:52:20 +02:00
|
|
|
uids = [self uidsFromICalPersons: _persons];
|
|
|
|
if (uids)
|
|
|
|
folders = [self lookupCalendarFoldersForUIDs: uids
|
|
|
|
inContext: _ctx];
|
|
|
|
else
|
|
|
|
folders = nil;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-06-30 20:52:20 +02:00
|
|
|
return folders;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* folder type */
|
|
|
|
|
2007-02-09 22:21:35 +01:00
|
|
|
- (NSString *) folderType
|
|
|
|
{
|
|
|
|
return @"Appointment";
|
|
|
|
}
|
|
|
|
|
2006-08-16 00:04:37 +02:00
|
|
|
- (NSString *) outlookFolderClass
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
return @"IPF.Appointment";
|
|
|
|
}
|
|
|
|
|
2007-09-15 00:01:02 +02:00
|
|
|
- (BOOL) isActive
|
2007-08-24 20:47:32 +02:00
|
|
|
{
|
2009-11-29 05:19:32 +01:00
|
|
|
SOGoUserSettings *settings;
|
2008-05-06 01:39:07 +02:00
|
|
|
NSArray *inactiveFolders;
|
2007-08-24 20:47:32 +02:00
|
|
|
|
2007-09-15 00:01:02 +02:00
|
|
|
settings = [[context activeUser] userSettings];
|
2008-05-06 01:39:07 +02:00
|
|
|
inactiveFolders
|
|
|
|
= [[settings objectForKey: @"Calendar"] objectForKey: @"InactiveFolders"];
|
2007-08-24 20:47:32 +02:00
|
|
|
|
2008-06-13 22:22:51 +02:00
|
|
|
return (![inactiveFolders containsObject: nameInContainer]);
|
2007-08-24 20:47:32 +02:00
|
|
|
}
|
|
|
|
|
2009-09-03 19:53:38 +02:00
|
|
|
- (BOOL) importComponent: (iCalEntityObject *) event
|
2009-09-02 21:14:15 +02:00
|
|
|
{
|
|
|
|
SOGoAppointmentObject *object;
|
|
|
|
NSString *uid;
|
|
|
|
NSString *content;
|
|
|
|
|
|
|
|
uid = [self globallyUniqueObjectId];
|
|
|
|
[event setUid: uid];
|
|
|
|
object = [SOGoAppointmentObject objectWithName: uid
|
|
|
|
inContainer: self];
|
2009-09-28 15:25:14 +02:00
|
|
|
[object setIsNew: YES];
|
2009-09-02 21:14:15 +02:00
|
|
|
content =
|
2009-09-23 17:00:50 +02:00
|
|
|
[NSString stringWithFormat: @"BEGIN:VCALENDAR\n%@\nEND:VCALENDAR",
|
2009-09-02 21:14:15 +02:00
|
|
|
[event versitString]];
|
2009-09-03 19:53:38 +02:00
|
|
|
return ([object saveContentString: content] == nil);
|
2009-09-02 21:14:15 +02:00
|
|
|
}
|
|
|
|
|
2009-09-10 19:26:57 +02:00
|
|
|
- (int) importCalendar: (iCalCalendar *) calendar
|
|
|
|
{
|
2009-09-23 17:00:50 +02:00
|
|
|
NSMutableArray *components;
|
2009-09-10 19:26:57 +02:00
|
|
|
int imported, count, i;
|
|
|
|
|
|
|
|
imported = 0;
|
|
|
|
|
|
|
|
if (calendar)
|
|
|
|
{
|
2009-09-23 17:00:50 +02:00
|
|
|
components = [[calendar events] mutableCopy];
|
2009-09-23 20:17:31 +02:00
|
|
|
[components autorelease];
|
2009-09-23 17:00:50 +02:00
|
|
|
[components addObjectsFromArray: [calendar todos]];
|
|
|
|
[components addObjectsFromArray: [calendar journals]];
|
|
|
|
[components addObjectsFromArray: [calendar freeBusys]];
|
2009-09-10 19:26:57 +02:00
|
|
|
|
|
|
|
count = [components count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
if ([self importComponent: [components objectAtIndex: i]])
|
|
|
|
imported++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return imported;
|
|
|
|
}
|
|
|
|
|
2010-01-15 00:19:19 +01:00
|
|
|
/* acls */
|
|
|
|
- (NSArray *) aclsForUser: (NSString *) uid
|
|
|
|
forObjectAtPath: (NSArray *) objectPathArray
|
|
|
|
{
|
|
|
|
NSMutableArray *aclsForUser;
|
|
|
|
NSArray *superAcls;
|
|
|
|
|
|
|
|
superAcls = [super aclsForUser: uid forObjectAtPath: objectPathArray];
|
|
|
|
if ([uid isEqualToString: [self defaultUserID]])
|
|
|
|
{
|
|
|
|
if (superAcls)
|
|
|
|
{
|
|
|
|
aclsForUser = [superAcls mutableCopy];
|
|
|
|
[aclsForUser autorelease];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
aclsForUser = [NSMutableArray array];
|
|
|
|
[aclsForUser addObject: SoRole_Authenticated];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
aclsForUser = (NSMutableArray *) superAcls;
|
|
|
|
|
|
|
|
return aclsForUser;
|
|
|
|
}
|
|
|
|
|
2010-01-19 13:28:10 +01:00
|
|
|
/* caldav-proxy */
|
|
|
|
- (SOGoAppointmentProxyPermission)
|
|
|
|
proxyPermissionForUserWithLogin: (NSString *) login
|
2010-01-15 00:19:19 +01:00
|
|
|
{
|
2010-01-19 13:28:10 +01:00
|
|
|
SOGoAppointmentProxyPermission permission;
|
2010-01-15 00:19:19 +01:00
|
|
|
NSArray *roles;
|
2010-01-19 13:28:10 +01:00
|
|
|
static NSArray *readRoles = nil;
|
|
|
|
static NSArray *writeRoles = nil;
|
|
|
|
|
|
|
|
if (!readRoles)
|
|
|
|
{
|
|
|
|
readRoles = [NSArray arrayWithObjects:
|
|
|
|
SOGoCalendarRole_ConfidentialViewer,
|
|
|
|
SOGoCalendarRole_ConfidentialDAndTViewer,
|
|
|
|
SOGoCalendarRole_PrivateViewer,
|
|
|
|
SOGoCalendarRole_PrivateDAndTViewer,
|
|
|
|
SOGoCalendarRole_PublicViewer,
|
|
|
|
SOGoCalendarRole_PublicDAndTViewer,
|
|
|
|
nil];
|
|
|
|
[readRoles retain];
|
|
|
|
}
|
|
|
|
if (!writeRoles)
|
|
|
|
{
|
|
|
|
writeRoles = [NSArray arrayWithObjects:
|
|
|
|
SOGoRole_ObjectCreator,
|
|
|
|
SOGoRole_ObjectEraser,
|
|
|
|
SOGoCalendarRole_ConfidentialModifier,
|
|
|
|
SOGoCalendarRole_ConfidentialResponder,
|
|
|
|
SOGoCalendarRole_PrivateModifier,
|
|
|
|
SOGoCalendarRole_PrivateResponder,
|
|
|
|
SOGoCalendarRole_PublicModifier,
|
|
|
|
SOGoCalendarRole_PublicResponder,
|
|
|
|
nil];
|
|
|
|
[writeRoles retain];
|
|
|
|
}
|
|
|
|
|
|
|
|
permission = SOGoAppointmentProxyPermissionNone;
|
|
|
|
roles = [self aclsForUser: login];
|
|
|
|
if ([roles count])
|
|
|
|
{
|
|
|
|
if ([roles firstObjectCommonWithArray: readRoles])
|
|
|
|
permission = SOGoAppointmentProxyPermissionRead;
|
|
|
|
if ([roles firstObjectCommonWithArray: writeRoles])
|
|
|
|
permission = SOGoAppointmentProxyPermissionWrite;
|
|
|
|
}
|
|
|
|
|
|
|
|
return permission;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) aclUsersWithProxyWriteAccess: (BOOL) write
|
|
|
|
{
|
|
|
|
NSMutableArray *users;
|
|
|
|
NSArray *aclUsers;
|
|
|
|
NSString *aclUser;
|
|
|
|
SOGoAppointmentProxyPermission permission;
|
|
|
|
int count, max;
|
|
|
|
|
|
|
|
permission = (write
|
|
|
|
? SOGoAppointmentProxyPermissionWrite
|
|
|
|
: SOGoAppointmentProxyPermissionRead);
|
|
|
|
aclUsers = [self aclUsers];
|
|
|
|
max = [aclUsers count];
|
|
|
|
users = [NSMutableArray arrayWithCapacity: max];
|
|
|
|
for (count = 0; count < max; count++)
|
2010-01-15 00:19:19 +01:00
|
|
|
{
|
2010-01-19 13:28:10 +01:00
|
|
|
aclUser = [aclUsers objectAtIndex: count];
|
|
|
|
if ([self proxyPermissionForUserWithLogin: aclUser]
|
|
|
|
== permission)
|
|
|
|
[users addObject: aclUser];
|
2010-01-15 00:19:19 +01:00
|
|
|
}
|
2010-01-19 13:28:10 +01:00
|
|
|
|
|
|
|
return users;
|
2010-01-15 00:19:19 +01:00
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
@end /* SOGoAppointmentFolder */
|