2009-07-14 16:35:35 +02:00
|
|
|
|
2007-09-15 00:08:43 +02:00
|
|
|
/* SOGoAppointmentFolders.m - this file is part of SOGo
|
|
|
|
*
|
2016-09-26 21:22:49 +02:00
|
|
|
* Copyright (C) 2007-2016 Inverse inc.
|
2007-09-15 00:08:43 +02:00
|
|
|
*
|
|
|
|
* This file is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This file is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; see the file COPYING. If not, write to
|
|
|
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2008-02-08 15:28:35 +01:00
|
|
|
#import <Foundation/NSArray.h>
|
2009-07-14 16:35:35 +02:00
|
|
|
#import <Foundation/NSDictionary.h>
|
2008-07-09 23:09:08 +02:00
|
|
|
#import <Foundation/NSEnumerator.h>
|
2007-09-15 00:08:43 +02:00
|
|
|
#import <Foundation/NSString.h>
|
2012-04-18 21:13:26 +02:00
|
|
|
#import <Foundation/NSURL.h>
|
2007-09-15 00:08:43 +02:00
|
|
|
|
2009-08-27 23:14:54 +02:00
|
|
|
#import <NGObjWeb/WOContext+SoObjects.h>
|
2008-07-09 18:02:42 +02:00
|
|
|
#import <NGObjWeb/WORequest+So.h>
|
|
|
|
#import <NGObjWeb/NSException+HTTP.h>
|
2010-07-15 16:54:03 +02:00
|
|
|
#import <NGObjWeb/SoSecurityManager.h>
|
2009-10-07 15:20:16 +02:00
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
|
|
|
|
2009-09-10 19:26:57 +02:00
|
|
|
#import <GDLAccess/EOAdaptorChannel.h>
|
2009-08-27 23:14:54 +02:00
|
|
|
|
2014-09-18 01:45:44 +02:00
|
|
|
#import <DOM/DOMElement.h>
|
|
|
|
#import <DOM/DOMNode.h>
|
2010-01-15 00:19:19 +01:00
|
|
|
#import <DOM/DOMProtocols.h>
|
2009-07-14 16:35:35 +02:00
|
|
|
#import <SaxObjC/XMLNamespaces.h>
|
2009-08-27 23:14:54 +02:00
|
|
|
|
2008-07-09 23:09:08 +02:00
|
|
|
#import <SOGo/WORequest+SOGo.h>
|
2009-07-14 16:35:35 +02:00
|
|
|
#import <SOGo/NSObject+DAV.h>
|
2010-04-09 20:45:14 +02:00
|
|
|
#import <SOGo/NSObject+Utilities.h>
|
2009-10-15 23:33:56 +02:00
|
|
|
#import <SOGo/SOGoParentFolder.h>
|
|
|
|
#import <SOGo/SOGoPermissions.h>
|
2010-01-15 00:19:19 +01:00
|
|
|
#import <SOGo/SOGoUser.h>
|
2012-10-22 16:09:13 +02:00
|
|
|
#import <SOGo/SOGoUserDefaults.h>
|
2010-01-15 00:19:19 +01:00
|
|
|
#import <SOGo/SOGoUserSettings.h>
|
|
|
|
#import <SOGo/SOGoWebDAVValue.h>
|
2009-10-15 23:33:56 +02:00
|
|
|
#import <SOGo/SOGoWebDAVAclManager.h>
|
|
|
|
|
2007-09-15 00:08:43 +02:00
|
|
|
#import "SOGoAppointmentFolder.h"
|
2010-06-04 22:54:07 +02:00
|
|
|
#import "SOGoAppointmentFolderICS.h"
|
|
|
|
#import "SOGoAppointmentFolderXML.h"
|
2010-01-15 00:19:19 +01:00
|
|
|
#import "SOGoAppointmentInboxFolder.h"
|
2009-09-10 19:26:57 +02:00
|
|
|
#import "SOGoWebAppointmentFolder.h"
|
2010-01-15 00:19:19 +01:00
|
|
|
#import "SOGoUser+Appointments.h"
|
2007-09-15 00:08:43 +02:00
|
|
|
|
|
|
|
#import "SOGoAppointmentFolders.h"
|
|
|
|
|
2010-07-15 16:54:03 +02:00
|
|
|
static SoSecurityManager *sm = nil;
|
|
|
|
|
2014-09-18 01:45:44 +02:00
|
|
|
@interface NGDOMElement (SOGo)
|
|
|
|
|
|
|
|
- (BOOL) isTextNode;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NGDOMElement (SOGo)
|
|
|
|
|
|
|
|
- (BOOL) isTextNode
|
|
|
|
{
|
|
|
|
id <DOMNodeList> children;
|
|
|
|
id <DOMElement> element;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if ([self nodeType] == DOM_TEXT_NODE)
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
children = [self childNodes];
|
|
|
|
|
|
|
|
for (i = 0; i < [children length]; i++)
|
|
|
|
{
|
|
|
|
element = [children objectAtIndex: i];
|
|
|
|
|
|
|
|
if ([element nodeType] != DOM_TEXT_NODE)
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-09-15 00:08:43 +02:00
|
|
|
@implementation SOGoAppointmentFolders
|
|
|
|
|
2010-07-15 16:54:03 +02:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
if (!sm)
|
|
|
|
sm = [SoSecurityManager sharedSecurityManager];
|
|
|
|
}
|
|
|
|
|
2010-07-15 18:59:35 +02:00
|
|
|
+ (SOGoWebDAVAclManager *) webdavAclManager
|
|
|
|
{
|
|
|
|
static SOGoWebDAVAclManager *aclManager = nil;
|
|
|
|
|
|
|
|
if (!aclManager)
|
|
|
|
{
|
|
|
|
aclManager = [[super webdavAclManager] copy];
|
|
|
|
[aclManager
|
|
|
|
registerDAVPermission: davElement (@"write", XMLNS_WEBDAV)
|
|
|
|
abstract: NO
|
|
|
|
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
|
|
|
asChildOf: davElement (@"all", XMLNS_WEBDAV)];
|
|
|
|
[aclManager
|
|
|
|
registerDAVPermission: davElement (@"write-properties", XMLNS_WEBDAV)
|
|
|
|
abstract: YES
|
|
|
|
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
|
|
|
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
|
|
|
[aclManager
|
|
|
|
registerDAVPermission: davElement (@"write-content", XMLNS_WEBDAV)
|
|
|
|
abstract: YES
|
|
|
|
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
|
|
|
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
|
|
|
}
|
|
|
|
|
|
|
|
return aclManager;
|
|
|
|
}
|
|
|
|
|
2010-06-04 22:54:07 +02:00
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
if ((self = [super init]))
|
|
|
|
{
|
|
|
|
folderObjectKeys = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
[folderObjectKeys release];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2007-09-15 00:08:43 +02:00
|
|
|
+ (NSString *) gcsFolderType
|
|
|
|
{
|
|
|
|
return @"Appointment";
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (Class) subFolderClass
|
|
|
|
{
|
|
|
|
return [SOGoAppointmentFolder class];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) defaultFolderName
|
|
|
|
{
|
2010-04-09 20:45:14 +02:00
|
|
|
return [self labelForKey: @"Personal Calendar" inContext: context];
|
2007-09-15 00:08:43 +02:00
|
|
|
}
|
|
|
|
|
2013-09-30 16:50:27 +02:00
|
|
|
|
|
|
|
|
|
|
|
- (SOGoWebAppointmentFolder *) newWebCalendarWithURL: (NSString *) urlString
|
|
|
|
nameInContainer: (NSString *) name
|
2010-06-11 20:43:46 +02:00
|
|
|
{
|
2013-09-30 16:50:27 +02:00
|
|
|
NSString *folderDisplayName, *tmp;
|
2010-06-11 20:43:46 +02:00
|
|
|
SOGoWebAppointmentFolder *webCalendar;
|
2013-09-30 16:50:27 +02:00
|
|
|
SOGoAppointmentFolder *aptFolder;
|
|
|
|
NSException *error;
|
2012-04-18 21:13:26 +02:00
|
|
|
NSURL *url;
|
2010-06-11 20:43:46 +02:00
|
|
|
|
2013-09-30 16:50:27 +02:00
|
|
|
folderDisplayName = [self labelForKey: @"Web Calendar"];
|
2012-04-18 21:13:26 +02:00
|
|
|
webCalendar = nil;
|
|
|
|
|
2013-09-30 16:50:27 +02:00
|
|
|
tmp = [urlString lastPathComponent];
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if ([[tmp pathExtension] caseInsensitiveCompare: @"ics"] == NSOrderedSame)
|
|
|
|
folderDisplayName = [tmp substringToIndex: [tmp length] - 4];
|
|
|
|
else
|
|
|
|
folderDisplayName = tmp;
|
|
|
|
}
|
|
|
|
|
2012-04-18 21:13:26 +02:00
|
|
|
if ([folderDisplayName length] > 0 && [urlString length] > 0)
|
2010-06-11 20:43:46 +02:00
|
|
|
{
|
2012-04-18 21:13:26 +02:00
|
|
|
url = [NSURL URLWithString: urlString];
|
|
|
|
if ([[url scheme] hasPrefix: @"http"])
|
|
|
|
{
|
|
|
|
error = [self newFolderWithName: folderDisplayName
|
|
|
|
nameInContainer: &name];
|
|
|
|
if (!error)
|
|
|
|
{
|
2013-09-30 16:50:27 +02:00
|
|
|
// We make sure we initialized our subfolfers list. This can happen
|
|
|
|
// when auto-creating Web calendars during the logon process.
|
|
|
|
[self subFolders];
|
|
|
|
|
2012-04-18 21:13:26 +02:00
|
|
|
aptFolder = [subFolders objectForKey: name];
|
|
|
|
[aptFolder setFolderPropertyValue: urlString
|
|
|
|
inCategory: @"WebCalendars"];
|
|
|
|
|
|
|
|
webCalendar = [SOGoWebAppointmentFolder objectWithName: name
|
|
|
|
inContainer: self];
|
|
|
|
[webCalendar setOCSPath: [aptFolder ocsPath]];
|
|
|
|
[subFolders setObject: webCalendar forKey: name];
|
|
|
|
}
|
|
|
|
}
|
2010-06-11 20:43:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return webCalendar;
|
|
|
|
}
|
|
|
|
|
2009-08-27 23:14:54 +02:00
|
|
|
- (NSArray *) toManyRelationshipKeys
|
|
|
|
{
|
2010-01-15 00:19:19 +01:00
|
|
|
NSMutableArray *keys;
|
2009-08-27 23:14:54 +02:00
|
|
|
NSEnumerator *sortedSubFolders;
|
2010-01-19 13:28:10 +01:00
|
|
|
SOGoAppointmentFolder *currentFolder;
|
|
|
|
SOGoUser *currentUser;
|
2009-08-27 23:14:54 +02:00
|
|
|
NSString *login;
|
|
|
|
|
|
|
|
if ([[context request] isICal])
|
|
|
|
{
|
2010-01-19 13:28:10 +01:00
|
|
|
currentUser = [context activeUser];
|
|
|
|
login = [currentUser login];
|
2009-08-27 23:14:54 +02:00
|
|
|
keys = [NSMutableArray array];
|
2010-01-21 00:09:35 +01:00
|
|
|
[keys addObject: @"inbox"];
|
2009-08-27 23:14:54 +02:00
|
|
|
if ([owner isEqualToString: login])
|
|
|
|
{
|
|
|
|
sortedSubFolders = [[self subFolders] objectEnumerator];
|
|
|
|
while ((currentFolder = [sortedSubFolders nextObject]))
|
|
|
|
{
|
|
|
|
if ([[currentFolder ownerInContext: context]
|
|
|
|
isEqualToString: owner])
|
|
|
|
[keys addObject: [currentFolder nameInContainer]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2010-01-15 00:19:19 +01:00
|
|
|
{
|
2010-01-19 13:28:10 +01:00
|
|
|
sortedSubFolders = [[self subFolders] objectEnumerator];
|
|
|
|
while ((currentFolder = [sortedSubFolders nextObject]))
|
|
|
|
if ([currentUser hasSubscribedToCalendar: currentFolder]
|
|
|
|
&& ([currentFolder proxyPermissionForUserWithLogin: login]
|
|
|
|
!= SOGoAppointmentProxyPermissionNone))
|
|
|
|
[keys addObject: [currentFolder nameInContainer]];
|
2010-01-15 00:19:19 +01:00
|
|
|
}
|
2009-08-27 23:14:54 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
keys = (NSMutableArray *) [super toManyRelationshipKeys];
|
|
|
|
|
|
|
|
return keys;
|
|
|
|
}
|
|
|
|
|
2010-06-04 22:54:07 +02:00
|
|
|
- (NSArray *) folderObjectKeys
|
|
|
|
{
|
|
|
|
NSArray *folders;
|
|
|
|
SOGoAppointmentFolder *folder;
|
|
|
|
NSString *folderObjectKey;
|
|
|
|
int count, max;
|
2010-07-15 16:54:03 +02:00
|
|
|
BOOL ignoreRights;
|
2010-06-04 22:54:07 +02:00
|
|
|
|
|
|
|
if (!folderObjectKeys)
|
|
|
|
{
|
2010-07-15 16:54:03 +02:00
|
|
|
ignoreRights = [self ignoreRights];
|
2010-06-04 22:54:07 +02:00
|
|
|
folders = [self subFolders];
|
|
|
|
max = [folders count];
|
|
|
|
folderObjectKeys = [[NSMutableArray alloc] initWithCapacity: max];
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
folder = [folders objectAtIndex: count];
|
|
|
|
if ([folder isMemberOfClass: [SOGoAppointmentFolder class]]
|
2010-07-15 16:54:03 +02:00
|
|
|
&& ![folder isSubscription]
|
|
|
|
&& (ignoreRights || ![sm validatePermission: SOGoPerm_AccessObject
|
|
|
|
onObject: folder
|
|
|
|
inContext: context]))
|
2010-06-04 22:54:07 +02:00
|
|
|
{
|
|
|
|
folderObjectKey = [NSString stringWithFormat: @"%@.ics",
|
2010-06-07 14:45:22 +02:00
|
|
|
[folder nameInContainer]];
|
2010-06-04 22:54:07 +02:00
|
|
|
[folderObjectKeys addObject: folderObjectKey];
|
|
|
|
folderObjectKey = [NSString stringWithFormat: @"%@.xml",
|
2010-06-07 14:45:22 +02:00
|
|
|
[folder nameInContainer]];
|
2010-06-04 22:54:07 +02:00
|
|
|
[folderObjectKeys addObject: folderObjectKey];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return folderObjectKeys;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) toOneRelationshipKeys
|
|
|
|
{
|
2010-06-07 14:45:22 +02:00
|
|
|
NSArray *keys;
|
|
|
|
|
2010-06-07 14:46:35 +02:00
|
|
|
if ([[context request] isICal])
|
2010-06-07 14:45:22 +02:00
|
|
|
keys = [NSArray array];
|
|
|
|
else
|
|
|
|
keys = [self folderObjectKeys];
|
|
|
|
|
|
|
|
return keys;
|
2010-06-04 22:54:07 +02:00
|
|
|
}
|
|
|
|
|
2010-01-15 00:19:19 +01:00
|
|
|
- (id) lookupName: (NSString *) name
|
|
|
|
inContext: (WOContext *) lookupContext
|
|
|
|
acquire: (BOOL) acquire
|
|
|
|
{
|
|
|
|
id obj;
|
|
|
|
|
|
|
|
if ([name isEqualToString: @"inbox"])
|
2010-01-21 00:09:35 +01:00
|
|
|
obj = [SOGoAppointmentInboxFolder objectWithName: name
|
|
|
|
inContainer: self];
|
2010-06-04 22:54:07 +02:00
|
|
|
else if ([[self folderObjectKeys] containsObject: name])
|
|
|
|
{
|
|
|
|
if ([name hasSuffix: @".ics"])
|
|
|
|
obj = [SOGoAppointmentFolderICS objectWithName: name
|
|
|
|
inContainer: self];
|
|
|
|
else if ([name hasSuffix: @".xml"])
|
|
|
|
obj = [SOGoAppointmentFolderXML objectWithName: name
|
|
|
|
inContainer: self];
|
|
|
|
else
|
|
|
|
obj = nil;
|
|
|
|
}
|
2010-01-15 00:19:19 +01:00
|
|
|
else
|
|
|
|
obj = [super lookupName: name inContext: lookupContext acquire: NO];
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2008-07-09 23:09:08 +02:00
|
|
|
- (NSString *) _fetchPropertyWithName: (NSString *) propertyName
|
|
|
|
inArray: (NSArray *) section
|
2008-07-09 18:02:42 +02:00
|
|
|
{
|
2008-07-09 23:09:08 +02:00
|
|
|
NSObject <DOMElement> *currentElement;
|
|
|
|
NSString *currentName, *property;
|
|
|
|
NSEnumerator *elements;
|
|
|
|
NSObject <DOMNodeList> *values;
|
2008-07-09 18:02:42 +02:00
|
|
|
|
2008-07-09 23:09:08 +02:00
|
|
|
property = nil;
|
2008-07-09 18:02:42 +02:00
|
|
|
|
2008-07-09 23:09:08 +02:00
|
|
|
elements = [section objectEnumerator];
|
|
|
|
while (!property && (currentElement = [elements nextObject]))
|
2008-07-09 18:02:42 +02:00
|
|
|
{
|
2008-07-09 23:09:08 +02:00
|
|
|
currentName = [NSString stringWithFormat: @"{%@}%@",
|
|
|
|
[currentElement namespaceURI],
|
|
|
|
[currentElement nodeName]];
|
|
|
|
if ([currentName isEqualToString: propertyName])
|
2008-07-09 18:02:42 +02:00
|
|
|
{
|
2014-09-18 01:45:44 +02:00
|
|
|
if ([(id)currentElement isTextNode])
|
|
|
|
{
|
|
|
|
property = [(id)currentElement textValue];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
values = [currentElement childNodes];
|
|
|
|
if ([values length])
|
|
|
|
property = [[values objectAtIndex: 0] nodeValue];
|
|
|
|
}
|
|
|
|
}
|
2008-07-09 18:02:42 +02:00
|
|
|
}
|
|
|
|
|
2008-07-09 23:09:08 +02:00
|
|
|
return property;
|
2008-07-09 18:02:42 +02:00
|
|
|
}
|
|
|
|
|
2008-07-09 23:09:08 +02:00
|
|
|
#warning this method may be useful at a higher level
|
|
|
|
#warning not all values are simple strings...
|
|
|
|
- (NSException *) _applyMkCalendarProperties: (NSArray *) properties
|
|
|
|
toObject: (SOGoObject *) newFolder
|
2008-07-09 18:02:42 +02:00
|
|
|
{
|
2008-07-09 23:09:08 +02:00
|
|
|
NSEnumerator *allProperties;
|
|
|
|
NSObject <DOMElement> *currentProperty;
|
|
|
|
NSObject <DOMNodeList> *values;
|
|
|
|
NSString *value, *currentName;
|
|
|
|
SEL methodSel;
|
|
|
|
|
|
|
|
allProperties = [properties objectEnumerator];
|
|
|
|
while ((currentProperty = [allProperties nextObject]))
|
|
|
|
{
|
|
|
|
values = [currentProperty childNodes];
|
|
|
|
if ([values length])
|
|
|
|
{
|
2014-09-18 01:45:44 +02:00
|
|
|
if ([(id)currentProperty isTextNode])
|
|
|
|
value = [(id)currentProperty textValue];
|
|
|
|
else
|
|
|
|
value = [[values objectAtIndex: 0] nodeValue];
|
|
|
|
|
2008-07-09 23:09:08 +02:00
|
|
|
currentName = [NSString stringWithFormat: @"{%@}%@",
|
|
|
|
[currentProperty namespaceURI],
|
|
|
|
[currentProperty nodeName]];
|
|
|
|
methodSel = SOGoSelectorForPropertySetter (currentName);
|
|
|
|
if ([newFolder respondsToSelector: methodSel])
|
|
|
|
[newFolder performSelector: methodSel
|
|
|
|
withObject: value];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-09 18:02:42 +02:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2008-07-09 23:09:08 +02:00
|
|
|
- (NSException *) davCreateCalendarCollection: (NSString *) newName
|
|
|
|
inContext: (id) createContext
|
2008-07-09 18:02:42 +02:00
|
|
|
{
|
2008-07-09 23:09:08 +02:00
|
|
|
NSArray *subfolderNames, *setProperties;
|
|
|
|
NSString *content, *newDisplayName;
|
|
|
|
NSDictionary *properties;
|
|
|
|
NSException *error;
|
|
|
|
SOGoAppointmentFolder *newFolder;
|
|
|
|
|
|
|
|
subfolderNames = [self toManyRelationshipKeys];
|
|
|
|
if ([subfolderNames containsObject: newName])
|
|
|
|
{
|
|
|
|
content = [NSString stringWithFormat:
|
|
|
|
@"A collection named '%@' already exists.",
|
|
|
|
newName];
|
|
|
|
error = [NSException exceptionWithHTTPStatus: 403
|
|
|
|
reason: content];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
properties = [[createContext request]
|
|
|
|
davPatchedPropertiesWithTopTag: @"mkcalendar"];
|
|
|
|
setProperties = [properties objectForKey: @"set"];
|
|
|
|
newDisplayName = [self _fetchPropertyWithName: @"{DAV:}displayname"
|
|
|
|
inArray: setProperties];
|
|
|
|
if (![newDisplayName length])
|
|
|
|
newDisplayName = newName;
|
|
|
|
error
|
|
|
|
= [self newFolderWithName: newDisplayName andNameInContainer: newName];
|
|
|
|
if (!error)
|
|
|
|
{
|
|
|
|
newFolder = [self lookupName: newName
|
|
|
|
inContext: createContext
|
|
|
|
acquire: NO];
|
|
|
|
error = [self _applyMkCalendarProperties: setProperties
|
|
|
|
toObject: newFolder];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
2008-07-09 18:02:42 +02:00
|
|
|
}
|
|
|
|
|
2009-07-14 16:35:35 +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",
|
2010-01-22 17:33:35 +01:00
|
|
|
XMLNS_CALDAV, components)
|
2009-07-14 16:35:35 +02:00
|
|
|
asWebDAVValue];
|
|
|
|
[componentSet retain];
|
|
|
|
}
|
|
|
|
|
|
|
|
return componentSet;
|
|
|
|
}
|
|
|
|
|
2012-02-21 17:19:46 +01:00
|
|
|
- (NSString *) _davDefaultClassWithSelector: (SEL) selector
|
|
|
|
{
|
|
|
|
SOGoUser *ownerUser;
|
|
|
|
SOGoUserDefaults *defaults;
|
|
|
|
NSString *classification;
|
|
|
|
|
|
|
|
ownerUser = [SOGoUser userWithLogin: [self ownerInContext: context]];
|
|
|
|
defaults = [ownerUser userDefaults];
|
|
|
|
classification = [defaults performSelector: selector];
|
|
|
|
|
|
|
|
return classification;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSException *) _davSetDefaultClass: (NSString *) newClass
|
|
|
|
withSelector: (SEL) selector
|
|
|
|
{
|
|
|
|
NSException *error;
|
|
|
|
static NSArray *validClassifications = nil;
|
|
|
|
SOGoUser *ownerUser;
|
|
|
|
SOGoUserDefaults *defaults;
|
|
|
|
|
|
|
|
if (!validClassifications)
|
|
|
|
validClassifications = [[NSArray alloc] initWithObjects: @"PUBLIC",
|
|
|
|
@"CONFIDENTIAL", @"PRIVATE", nil];
|
|
|
|
|
|
|
|
if (newClass && [validClassifications containsObject: newClass])
|
|
|
|
{
|
|
|
|
error = nil;
|
|
|
|
ownerUser = [SOGoUser userWithLogin: [self ownerInContext: context]];
|
|
|
|
defaults = [ownerUser userDefaults];
|
|
|
|
[defaults performSelector: selector withObject: newClass];
|
|
|
|
[defaults synchronize];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
error = [NSException exceptionWithHTTPStatus: 403
|
|
|
|
reason: @"invalid"
|
|
|
|
@" classification value"];
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) davEventsDefaultClassification
|
|
|
|
{
|
|
|
|
return [self _davDefaultClassWithSelector: @selector (calendarEventsDefaultClassification)];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSException *) setDavEventsDefaultClassification: (NSString *) newClass
|
|
|
|
{
|
|
|
|
return [self _davSetDefaultClass: newClass
|
|
|
|
withSelector: @selector (setCalendarEventsDefaultClassification:)];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) davTasksDefaultClassification
|
|
|
|
{
|
|
|
|
return [self _davDefaultClassWithSelector: @selector (calendarTasksDefaultClassification)];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSException *) setDavTasksDefaultClassification: (NSString *) newClass
|
|
|
|
{
|
|
|
|
return [self _davSetDefaultClass: newClass
|
|
|
|
withSelector: @selector (setCalendarTasksDefaultClassification:)];
|
|
|
|
}
|
|
|
|
|
2010-10-28 17:47:29 +02:00
|
|
|
/* This method fixes an issue that occurred previously in
|
|
|
|
_migrateWebCalendarsSettings, where the active user, rather than the
|
|
|
|
owner's login would be taken to compose the expected key prefix, leading to
|
|
|
|
a corrupted calendar key with an endless chain of
|
|
|
|
[user]:/Calendar/[user]:/Calendar/[user].... occurrences. */
|
|
|
|
- (NSString *) _fixedWebCalendarKey: (NSString *) oldKey
|
|
|
|
{
|
|
|
|
NSString *newKey;
|
2010-10-28 18:10:58 +02:00
|
|
|
NSRange lastOccurrence;
|
2010-10-28 17:47:29 +02:00
|
|
|
|
|
|
|
lastOccurrence = [oldKey rangeOfString: @":Calendar/"
|
|
|
|
options: NSBackwardsSearch];
|
2010-10-28 18:10:58 +02:00
|
|
|
if ([oldKey rangeOfString: @":Calendar/"].location
|
|
|
|
!= lastOccurrence.location)
|
2010-10-28 17:47:29 +02:00
|
|
|
{
|
2010-10-28 18:10:58 +02:00
|
|
|
newKey
|
|
|
|
= [NSString stringWithFormat: @"%@%@", owner,
|
|
|
|
[oldKey substringFromIndex: lastOccurrence.location]];
|
|
|
|
[self logWithFormat: @"fixed erroneous calendar key: '%@' -> '%@'",
|
|
|
|
oldKey, newKey];
|
2010-10-28 17:47:29 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
newKey = nil;
|
|
|
|
|
|
|
|
return newKey;
|
|
|
|
}
|
|
|
|
|
2010-06-11 20:43:46 +02:00
|
|
|
- (void) _migrateWebCalendarsSettings
|
2010-04-19 23:30:25 +02:00
|
|
|
{
|
2010-06-11 20:43:46 +02:00
|
|
|
SOGoUserSettings *us;
|
|
|
|
NSDictionary *module;
|
|
|
|
NSMutableDictionary *webCalendars;
|
|
|
|
NSArray *keys;
|
|
|
|
NSString *oldKey, *prefix, *newKey;
|
2010-04-19 23:30:25 +02:00
|
|
|
int count, max;
|
2010-06-11 20:43:46 +02:00
|
|
|
BOOL hasChanged;
|
|
|
|
|
|
|
|
hasChanged = NO;
|
2010-04-19 23:30:25 +02:00
|
|
|
|
2010-10-28 17:47:29 +02:00
|
|
|
prefix = [NSString stringWithFormat: @"%@:Calendar/",
|
|
|
|
[self ownerInContext: context]];
|
|
|
|
|
|
|
|
us = [[SOGoUser userWithLogin: owner] userSettings];
|
2010-06-11 20:43:46 +02:00
|
|
|
module = [us objectForKey: @"Calendar"];
|
|
|
|
webCalendars = [module objectForKey: @"WebCalendars"];
|
|
|
|
keys = [webCalendars allKeys];
|
|
|
|
max = [keys count];
|
|
|
|
|
2010-04-19 23:30:25 +02:00
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
2010-06-11 20:43:46 +02:00
|
|
|
oldKey = [keys objectAtIndex: count];
|
2010-10-28 17:47:29 +02:00
|
|
|
if ([oldKey hasPrefix: prefix])
|
|
|
|
newKey = [self _fixedWebCalendarKey: oldKey];
|
|
|
|
else
|
|
|
|
newKey = [prefix stringByAppendingString: oldKey];
|
2010-10-28 18:02:10 +02:00
|
|
|
if (newKey && ![newKey isEqualToString: oldKey])
|
2010-06-11 20:43:46 +02:00
|
|
|
{
|
|
|
|
[webCalendars setObject: [webCalendars objectForKey: oldKey]
|
|
|
|
forKey: newKey];
|
|
|
|
[webCalendars removeObjectForKey: oldKey];
|
|
|
|
hasChanged = YES;
|
|
|
|
}
|
2010-04-19 23:30:25 +02:00
|
|
|
}
|
2010-06-11 20:43:46 +02:00
|
|
|
if (hasChanged)
|
|
|
|
[us synchronize];
|
2010-04-19 23:30:25 +02:00
|
|
|
}
|
|
|
|
|
2010-07-16 16:34:39 +02:00
|
|
|
- (void) reloadWebCalendars: (BOOL) forceReload
|
|
|
|
{
|
|
|
|
NSArray *refs;
|
|
|
|
SOGoWebAppointmentFolder *folder;
|
|
|
|
SOGoUserSettings *us;
|
|
|
|
NSDictionary *calSettings;
|
|
|
|
NSString *ref;
|
|
|
|
int count, max;
|
|
|
|
|
|
|
|
[self _migrateWebCalendarsSettings];
|
|
|
|
us = [[SOGoUser userWithLogin: owner] userSettings];
|
|
|
|
calSettings = [us objectForKey: @"Calendar"];
|
|
|
|
refs = [[calSettings objectForKey: @"WebCalendars"] allKeys];
|
|
|
|
max = [refs count];
|
2012-04-18 21:13:26 +02:00
|
|
|
|
2010-07-16 16:34:39 +02:00
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
ref = [refs objectAtIndex: count];
|
|
|
|
folder = [SOGoWebAppointmentFolder
|
|
|
|
folderWithSubscriptionReference: ref
|
|
|
|
inContainer: self];
|
2013-09-30 16:50:27 +02:00
|
|
|
|
|
|
|
if (forceReload || [folder reloadOnLogin] || !folder)
|
|
|
|
{
|
|
|
|
if (!folder)
|
|
|
|
{
|
|
|
|
NSString *s, *urlString;
|
|
|
|
|
|
|
|
urlString = [[calSettings objectForKey: @"WebCalendars"] objectForKey: ref];
|
|
|
|
s = [ref lastPathComponent];
|
|
|
|
|
|
|
|
// See bug #2007. Some admins want to subscribe users to Web calendars
|
|
|
|
// using sogo-tool. If they do that, the db tables won't be created
|
|
|
|
// so we must detect that here and create them upon login.
|
|
|
|
folder = [self newWebCalendarWithURL: urlString
|
|
|
|
nameInContainer: s];
|
|
|
|
}
|
|
|
|
|
|
|
|
[folder loadWebCalendar];
|
|
|
|
}
|
2010-07-16 16:34:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-08 17:19:53 +02:00
|
|
|
- (NSException *) fetchSpecialFolders: (NSString *) sql
|
|
|
|
withChannel: (EOAdaptorChannel *) fc
|
|
|
|
andFolderType: (SOGoFolderType) folderType
|
2009-09-10 19:26:57 +02:00
|
|
|
{
|
2010-06-11 20:43:46 +02:00
|
|
|
BOOL isWebRequest;
|
|
|
|
NSException *error;
|
|
|
|
NSArray *folders;
|
2009-09-10 19:26:57 +02:00
|
|
|
int count, max;
|
2010-06-11 20:43:46 +02:00
|
|
|
SOGoAppointmentFolder *folder;
|
|
|
|
SOGoWebAppointmentFolder *webFolder;
|
2009-09-10 19:26:57 +02:00
|
|
|
NSString *name;
|
|
|
|
|
2014-04-08 17:19:53 +02:00
|
|
|
error = [super fetchSpecialFolders: sql withChannel: fc andFolderType: folderType];
|
2009-10-07 15:20:16 +02:00
|
|
|
if (!error)
|
2009-09-10 19:26:57 +02:00
|
|
|
{
|
2010-06-11 20:43:46 +02:00
|
|
|
isWebRequest = [[context request] handledByDefaultHandler];
|
|
|
|
folders = [subFolders allValues];
|
|
|
|
max = [folders count];
|
|
|
|
|
|
|
|
[self _migrateWebCalendarsSettings];
|
2009-09-10 19:26:57 +02:00
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
2010-06-11 20:43:46 +02:00
|
|
|
folder = [folders objectAtIndex: count];
|
2017-11-16 17:41:36 +01:00
|
|
|
if ([folder folderPropertyValueInCategory: @"WebCalendars"
|
|
|
|
forUser: [SOGoUser userWithLogin: owner]])
|
2009-09-10 19:26:57 +02:00
|
|
|
{
|
2010-06-11 20:43:46 +02:00
|
|
|
name = [folder nameInContainer];
|
|
|
|
if (isWebRequest)
|
2009-10-07 15:20:16 +02:00
|
|
|
{
|
2010-06-11 20:43:46 +02:00
|
|
|
webFolder = [SOGoWebAppointmentFolder objectWithName: name
|
2009-10-07 15:20:16 +02:00
|
|
|
inContainer: self];
|
2010-06-11 20:43:46 +02:00
|
|
|
[webFolder setOCSPath: [folder ocsPath]];
|
|
|
|
[subFolders setObject: webFolder forKey: name];
|
2009-10-07 15:20:16 +02:00
|
|
|
}
|
|
|
|
else
|
2010-06-11 20:43:46 +02:00
|
|
|
[subFolders removeObjectForKey: name];
|
2009-09-10 19:26:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2010-01-19 13:28:10 +01:00
|
|
|
- (BOOL) hasProxyCalendarsWithWriteAccess: (BOOL) write
|
|
|
|
forUserWithLogin: (NSString *) userLogin
|
2010-01-15 00:19:19 +01:00
|
|
|
{
|
2010-01-19 13:28:10 +01:00
|
|
|
NSEnumerator *sortedSubFolders;
|
|
|
|
SOGoAppointmentFolder *currentFolder;
|
|
|
|
SOGoUser *currentUser;
|
|
|
|
SOGoAppointmentProxyPermission permission, curPermission, foundPermission;
|
|
|
|
BOOL rc;
|
2010-01-15 00:19:19 +01:00
|
|
|
|
2010-01-19 13:28:10 +01:00
|
|
|
if ([owner isEqualToString: userLogin])
|
|
|
|
rc = NO;
|
|
|
|
else
|
2010-01-15 00:19:19 +01:00
|
|
|
{
|
2010-01-19 13:28:10 +01:00
|
|
|
foundPermission = SOGoAppointmentProxyPermissionNone;
|
|
|
|
permission = (write
|
|
|
|
? SOGoAppointmentProxyPermissionWrite
|
|
|
|
: SOGoAppointmentProxyPermissionRead);
|
|
|
|
currentUser = [SOGoUser userWithLogin: userLogin];
|
|
|
|
sortedSubFolders = [[self subFolders] objectEnumerator];
|
|
|
|
while ((currentFolder = [sortedSubFolders nextObject]))
|
2010-01-19 14:38:09 +01:00
|
|
|
if ([currentUser hasSubscribedToCalendar: currentFolder]
|
|
|
|
&& [owner
|
|
|
|
isEqualToString: [currentFolder ownerInContext: nil]])
|
2010-01-19 13:28:10 +01:00
|
|
|
{
|
|
|
|
curPermission = [currentFolder
|
|
|
|
proxyPermissionForUserWithLogin: userLogin];
|
|
|
|
if ((foundPermission == SOGoAppointmentProxyPermissionNone)
|
|
|
|
|| (foundPermission == SOGoAppointmentProxyPermissionRead
|
|
|
|
&& curPermission == SOGoAppointmentProxyPermissionWrite))
|
|
|
|
foundPermission = curPermission;
|
|
|
|
}
|
|
|
|
rc = (foundPermission == permission);
|
2010-01-15 00:19:19 +01:00
|
|
|
}
|
2010-01-19 13:28:10 +01:00
|
|
|
|
|
|
|
return rc;
|
2010-01-15 00:19:19 +01:00
|
|
|
}
|
|
|
|
|
2010-01-19 13:28:10 +01:00
|
|
|
- (NSArray *) proxySubscribersWithWriteAccess: (BOOL) write
|
2010-01-15 00:19:19 +01:00
|
|
|
{
|
2010-01-19 13:28:10 +01:00
|
|
|
SOGoAppointmentFolder *currentFolder;
|
|
|
|
SOGoUser *currentUser;
|
|
|
|
NSArray *subFolderNames, *aclUsers;
|
|
|
|
NSString *aclUser;
|
|
|
|
NSMutableArray *subscribers;
|
|
|
|
int folderCount, folderMax, userCount, userMax;
|
|
|
|
|
|
|
|
subscribers = [NSMutableArray array];
|
|
|
|
|
|
|
|
subFolderNames = [self subFolders];
|
|
|
|
folderMax = [subFolderNames count];
|
|
|
|
for (folderCount = 0; folderCount < folderMax; folderCount++)
|
|
|
|
{
|
|
|
|
currentFolder = [subFolderNames objectAtIndex: folderCount];
|
2010-01-19 14:38:09 +01:00
|
|
|
if ([owner isEqualToString: [currentFolder ownerInContext: nil]])
|
2010-01-19 13:28:10 +01:00
|
|
|
{
|
2010-01-19 14:38:09 +01:00
|
|
|
aclUsers = [currentFolder aclUsersWithProxyWriteAccess: write];
|
|
|
|
userMax = [aclUsers count];
|
|
|
|
for (userCount = 0; userCount < userMax; userCount++)
|
2010-01-19 13:28:10 +01:00
|
|
|
{
|
2010-01-19 14:38:09 +01:00
|
|
|
aclUser = [aclUsers objectAtIndex: userCount];
|
|
|
|
if (![subscribers containsObject: aclUser])
|
|
|
|
{
|
2016-09-26 21:22:49 +02:00
|
|
|
if ([aclUser hasPrefix: @"@"])
|
|
|
|
[subscribers addObject: aclUser];
|
|
|
|
else
|
|
|
|
{
|
|
|
|
currentUser = [SOGoUser userWithLogin: aclUser];
|
|
|
|
if ([currentUser hasSubscribedToCalendar: currentFolder])
|
|
|
|
[subscribers addObject: aclUser];
|
|
|
|
}
|
2010-01-19 14:38:09 +01:00
|
|
|
}
|
2010-01-19 13:28:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return subscribers;
|
|
|
|
}
|
2010-01-15 00:19:19 +01:00
|
|
|
|
2010-01-19 13:28:10 +01:00
|
|
|
- (NSArray *) _requiredProxyRolesWithWriteAccess: (BOOL) hasWriteAccess
|
|
|
|
{
|
|
|
|
static NSArray *writeAccessRoles = nil;
|
|
|
|
static NSArray *readAccessRoles = nil;
|
|
|
|
|
|
|
|
if (!writeAccessRoles)
|
2010-01-22 17:33:35 +01:00
|
|
|
writeAccessRoles = [[NSArray alloc] initWithObjects:
|
|
|
|
SOGoCalendarRole_ConfidentialModifier,
|
|
|
|
SOGoRole_ObjectCreator,
|
|
|
|
SOGoRole_ObjectEraser,
|
|
|
|
SOGoCalendarRole_PrivateModifier,
|
|
|
|
SOGoCalendarRole_PublicModifier,
|
|
|
|
nil];
|
2010-01-19 13:28:10 +01:00
|
|
|
|
|
|
|
if (!readAccessRoles)
|
2010-01-22 17:33:35 +01:00
|
|
|
readAccessRoles = [[NSArray alloc] initWithObjects:
|
|
|
|
SOGoCalendarRole_ConfidentialViewer,
|
|
|
|
SOGoCalendarRole_PrivateViewer,
|
|
|
|
SOGoCalendarRole_PublicViewer,
|
|
|
|
nil];
|
2010-01-19 13:28:10 +01:00
|
|
|
|
|
|
|
return (hasWriteAccess) ? writeAccessRoles : readAccessRoles;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addProxySubscribers: (NSArray *) proxySubscribers
|
|
|
|
withWriteAccess: (BOOL) write
|
|
|
|
{
|
|
|
|
SOGoAppointmentFolder *currentFolder;
|
|
|
|
NSArray *subFolderNames, *proxyRoles;
|
|
|
|
int folderCount, folderMax, userCount, userMax;
|
|
|
|
|
|
|
|
proxyRoles = [self _requiredProxyRolesWithWriteAccess: write];
|
|
|
|
subFolderNames = [self subFolders];
|
|
|
|
folderMax = [subFolderNames count];
|
|
|
|
for (folderCount = 0; folderCount < folderMax; folderCount++)
|
|
|
|
{
|
|
|
|
currentFolder = [subFolderNames objectAtIndex: folderCount];
|
2010-01-19 14:38:09 +01:00
|
|
|
if ([owner isEqualToString: [currentFolder ownerInContext: nil]])
|
|
|
|
{
|
|
|
|
[currentFolder setRoles: proxyRoles
|
|
|
|
forUsers: proxySubscribers];
|
|
|
|
|
|
|
|
userMax = [proxySubscribers count];
|
|
|
|
for (userCount = 0; userCount < userMax; userCount++)
|
|
|
|
[currentFolder
|
2012-04-18 19:39:11 +02:00
|
|
|
subscribeUserOrGroup: [proxySubscribers objectAtIndex: userCount]
|
2014-07-24 18:48:03 +02:00
|
|
|
reallyDo: YES
|
|
|
|
response: nil];
|
2010-01-19 14:38:09 +01:00
|
|
|
}
|
2010-01-19 13:28:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeProxySubscribers: (NSArray *) proxySubscribers
|
|
|
|
withWriteAccess: (BOOL) write
|
|
|
|
{
|
|
|
|
SOGoAppointmentFolder *currentFolder;
|
|
|
|
NSArray *subFolderNames;
|
|
|
|
int folderCount, folderMax, userCount, userMax;
|
|
|
|
|
|
|
|
subFolderNames = [self subFolders];
|
|
|
|
folderMax = [subFolderNames count];
|
|
|
|
for (folderCount = 0; folderCount < folderMax; folderCount++)
|
|
|
|
{
|
|
|
|
currentFolder = [subFolderNames objectAtIndex: folderCount];
|
2010-01-19 14:38:09 +01:00
|
|
|
if ([owner isEqualToString: [currentFolder ownerInContext: nil]])
|
|
|
|
{
|
|
|
|
[currentFolder removeAclsForUsers: proxySubscribers];
|
2010-01-19 13:28:10 +01:00
|
|
|
|
2010-01-19 14:38:09 +01:00
|
|
|
userMax = [proxySubscribers count];
|
|
|
|
for (userCount = 0; userCount < userMax; userCount++)
|
|
|
|
[currentFolder
|
2012-04-18 19:39:11 +02:00
|
|
|
subscribeUserOrGroup: [proxySubscribers objectAtIndex: userCount]
|
2014-07-24 18:48:03 +02:00
|
|
|
reallyDo: NO
|
|
|
|
response: nil];
|
2010-01-19 14:38:09 +01:00
|
|
|
}
|
2010-01-15 00:19:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-15 00:08:43 +02:00
|
|
|
@end
|