2006-06-15 21:34:10 +02:00
|
|
|
/*
|
|
|
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
|
|
|
|
|
|
|
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-06-18 17:37:37 +02:00
|
|
|
#import <Foundation/NSArray.h>
|
|
|
|
#import <Foundation/NSString.h>
|
|
|
|
#import <Foundation/NSValue.h>
|
|
|
|
|
|
|
|
#import <NGObjWeb/NSException+HTTP.h>
|
|
|
|
#import <NGObjWeb/WOContext.h>
|
|
|
|
#import <NGObjWeb/WOResponse.h>
|
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
2007-02-21 22:12:41 +01:00
|
|
|
#import <GDLContentStore/GCSFolder.h>
|
|
|
|
|
2007-12-12 16:57:40 +01:00
|
|
|
#import "NSCalendarDate+SOGo.h"
|
2007-11-07 16:59:01 +01:00
|
|
|
#import "SOGoGCSFolder.h"
|
2007-04-26 03:16:19 +02:00
|
|
|
#import "SOGoUser.h"
|
|
|
|
#import "SOGoPermissions.h"
|
2007-02-21 22:12:41 +01:00
|
|
|
#import "SOGoContentObject.h"
|
2006-06-15 21:34:10 +02:00
|
|
|
|
|
|
|
@interface SOGoContentObject(ETag)
|
|
|
|
- (NSArray *)parseETagList:(NSString *)_c;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation SOGoContentObject
|
|
|
|
|
2008-07-05 00:25:27 +02:00
|
|
|
+ (id) objectWithRecord: (NSDictionary *) objectRecord
|
|
|
|
inContainer: (SOGoGCSFolder *) newContainer
|
2008-06-13 21:59:22 +02:00
|
|
|
{
|
|
|
|
SOGoContentObject *newObject;
|
|
|
|
|
|
|
|
newObject = [[self alloc] initWithRecord: objectRecord
|
|
|
|
inContainer: newContainer];
|
|
|
|
[newObject autorelease];
|
|
|
|
|
|
|
|
return newObject;
|
|
|
|
}
|
|
|
|
|
2008-07-09 17:42:22 +02:00
|
|
|
+ (id) objectWithName: (NSString *) newName
|
2008-07-05 00:25:27 +02:00
|
|
|
andContent: (NSString *) newContent
|
|
|
|
inContainer: (SOGoGCSFolder *) newContainer
|
|
|
|
{
|
|
|
|
SOGoContentObject *newObject;
|
|
|
|
|
2008-07-09 17:42:22 +02:00
|
|
|
newObject = [[self alloc] initWithName: newName
|
2008-07-05 00:25:27 +02:00
|
|
|
andContent: newContent
|
|
|
|
inContainer: newContainer];
|
|
|
|
[newObject autorelease];
|
|
|
|
|
|
|
|
return newObject;
|
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
// TODO: check superclass version
|
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
- (id) init
|
2007-06-01 22:59:47 +02:00
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
if ((self = [super init]))
|
2007-06-01 22:59:47 +02:00
|
|
|
{
|
2008-07-14 18:47:10 +02:00
|
|
|
isNew = NO;
|
2008-06-13 21:59:22 +02:00
|
|
|
content = nil;
|
|
|
|
version = 0;
|
|
|
|
lastModified = nil;
|
|
|
|
creationDate = nil;
|
2007-06-01 22:59:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
- (void) _setRecord: (NSDictionary *) objectRecord
|
2007-06-01 22:59:47 +02:00
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
NSString *newContent;
|
|
|
|
int intValue;
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
newContent = [objectRecord objectForKey: @"c_content"];
|
|
|
|
if (newContent)
|
2007-06-01 22:59:47 +02:00
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
ASSIGN (content, newContent);
|
|
|
|
version = [[objectRecord objectForKey: @"c_version"] unsignedIntValue];
|
|
|
|
intValue = [[objectRecord objectForKey: @"c_creationdate"] intValue];
|
|
|
|
ASSIGN (creationDate,
|
|
|
|
[NSCalendarDate dateWithTimeIntervalSince1970: intValue]);
|
|
|
|
intValue = [[objectRecord objectForKey: @"c_lastmodified"] intValue];
|
|
|
|
ASSIGN (lastModified,
|
|
|
|
[NSCalendarDate dateWithTimeIntervalSince1970: intValue]);
|
2007-06-01 22:59:47 +02:00
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
- (id) initWithRecord: (NSDictionary *) objectRecord
|
2008-07-09 17:42:22 +02:00
|
|
|
inContainer: (SOGoGCSFolder *) newContainer
|
2007-04-27 20:58:48 +02:00
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
NSString *newName;
|
2007-06-01 22:59:47 +02:00
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
newName = [objectRecord objectForKey: @"c_name"];
|
2008-07-05 00:25:27 +02:00
|
|
|
if ((self = [self initWithName: newName inContainer: newContainer]))
|
2007-04-27 20:58:48 +02:00
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
[self _setRecord: objectRecord];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
2007-04-27 20:58:48 +02:00
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
return self;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2008-07-05 00:25:27 +02:00
|
|
|
- (id) initWithName: (NSString *) newName
|
|
|
|
andContent: (NSString *) newContent
|
2008-07-09 17:42:22 +02:00
|
|
|
inContainer: (SOGoGCSFolder *) newContainer
|
2008-07-05 00:25:27 +02:00
|
|
|
{
|
|
|
|
if ((self = [self initWithName: newName inContainer: newContainer]))
|
|
|
|
{
|
|
|
|
ASSIGN (content, newContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
- (void) dealloc
|
2007-06-01 22:59:47 +02:00
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
[content release];
|
|
|
|
[creationDate release];
|
|
|
|
[lastModified release];
|
|
|
|
[super dealloc];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
/* accessors */
|
|
|
|
|
|
|
|
- (BOOL) isFolderish
|
2007-04-17 16:32:47 +02:00
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
return NO;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* content */
|
|
|
|
|
2007-06-01 22:59:47 +02:00
|
|
|
- (BOOL) isNew
|
2007-04-17 16:32:47 +02:00
|
|
|
{
|
2007-06-01 22:59:47 +02:00
|
|
|
return isNew;
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-07-14 18:47:10 +02:00
|
|
|
- (void) setIsNew: (BOOL) newIsNew
|
|
|
|
{
|
|
|
|
isNew = newIsNew;
|
|
|
|
}
|
|
|
|
|
2007-06-01 22:59:47 +02:00
|
|
|
- (NSString *) contentAsString
|
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
return content;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2007-06-01 22:59:47 +02:00
|
|
|
- (NSException *) saveContentString: (NSString *) newContent
|
2008-06-13 21:59:22 +02:00
|
|
|
baseVersion: (unsigned int) newVersion
|
2006-06-15 21:34:10 +02:00
|
|
|
{
|
|
|
|
/* Note: "iCal multifolder saves" are implemented in the apt subclass! */
|
2008-01-16 19:59:58 +01:00
|
|
|
GCSFolder *folder;
|
2006-06-15 21:34:10 +02:00
|
|
|
NSException *ex;
|
2008-06-13 21:59:22 +02:00
|
|
|
NSCalendarDate *now;
|
2007-06-01 22:59:47 +02:00
|
|
|
|
|
|
|
ex = nil;
|
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
now = [NSCalendarDate calendarDate];
|
|
|
|
if (!content)
|
|
|
|
ASSIGN (creationDate, now);
|
|
|
|
ASSIGN (lastModified, now);
|
|
|
|
ASSIGN (content, newContent);
|
|
|
|
version = newVersion;
|
2007-11-18 11:16:25 +01:00
|
|
|
|
2007-06-01 22:59:47 +02:00
|
|
|
folder = [container ocsFolder];
|
|
|
|
if (folder)
|
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
ex = [folder writeContent: newContent
|
|
|
|
toName: nameInContainer
|
|
|
|
baseVersion: newVersion];
|
2007-06-01 22:59:47 +02:00
|
|
|
if (ex)
|
|
|
|
[self errorWithFormat:@"write failed: %@", ex];
|
|
|
|
}
|
|
|
|
else
|
2006-06-15 21:34:10 +02:00
|
|
|
[self errorWithFormat:@"Did not find folder of content object."];
|
|
|
|
|
2007-06-01 22:59:47 +02:00
|
|
|
return ex;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
2007-06-01 22:59:47 +02:00
|
|
|
|
|
|
|
- (NSException *) saveContentString: (NSString *) newContent
|
|
|
|
{
|
|
|
|
return [self saveContentString: newContent baseVersion: 0];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
2007-06-01 22:59:47 +02:00
|
|
|
- (NSException *) delete
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
/* Note: "iCal multifolder saves" are implemented in the apt subclass! */
|
|
|
|
GCSFolder *folder;
|
|
|
|
NSException *ex;
|
|
|
|
|
|
|
|
// TODO: add precondition check? (or add DELETEAction?)
|
|
|
|
|
2008-06-13 21:59:22 +02:00
|
|
|
if ((folder = [container ocsFolder]) == nil) {
|
2006-06-15 21:34:10 +02:00
|
|
|
[self errorWithFormat:@"Did not find folder of content object."];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ex = [folder deleteContentWithName:[self nameInContainer]])) {
|
|
|
|
[self errorWithFormat:@"delete failed: %@", ex];
|
|
|
|
return ex;
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* actions */
|
|
|
|
|
2007-06-05 00:38:43 +02:00
|
|
|
// - (id) lookupName:
|
|
|
|
// {
|
|
|
|
// SoSelectorInvocation *invocation;
|
|
|
|
// NSString *name;
|
|
|
|
|
|
|
|
// name = [NSString stringWithFormat: @"%@:", [_key davMethodToObjC]];
|
|
|
|
|
|
|
|
// invocation = [[SoSelectorInvocation alloc]
|
|
|
|
// initWithSelectorNamed: name
|
|
|
|
// addContextParameter: YES];
|
|
|
|
// [invocation autorelease];
|
|
|
|
|
|
|
|
// return invocation;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
2007-06-01 22:59:47 +02:00
|
|
|
- (id) PUTAction: (WOContext *) _ctx
|
|
|
|
{
|
2008-07-09 17:42:22 +02:00
|
|
|
WORequest *rq;
|
|
|
|
NSException *error;
|
2006-06-15 21:34:10 +02:00
|
|
|
unsigned int baseVersion;
|
2008-07-09 17:42:22 +02:00
|
|
|
id etag, tmp;
|
|
|
|
BOOL needsLocation;
|
|
|
|
WOResponse *response;
|
|
|
|
|
|
|
|
error = [self matchesRequestConditionInContext: _ctx];
|
|
|
|
if (error)
|
|
|
|
response = (WOResponse *) error;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rq = [_ctx request];
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-07-09 17:42:22 +02:00
|
|
|
/* check whether its a request to the 'special' 'new' location */
|
2006-06-15 21:34:10 +02:00
|
|
|
/*
|
2008-07-09 17:42:22 +02:00
|
|
|
Note: this is kinda hack. The OGo ZideStore detects writes to 'new' as
|
|
|
|
object creations and will assign a server side identifier. Most
|
|
|
|
current GroupDAV clients rely on this behaviour, so we reproduce it
|
|
|
|
here.
|
|
|
|
A correct client would loop until it has a name which doesn't not
|
|
|
|
yet exist (by using if-none-match).
|
2006-06-15 21:34:10 +02:00
|
|
|
*/
|
2008-07-09 17:42:22 +02:00
|
|
|
needsLocation = NO;
|
|
|
|
|
|
|
|
tmp = [[self nameInContainer] stringByDeletingPathExtension];
|
|
|
|
if ([tmp isEqualToString: @"new"])
|
|
|
|
{
|
|
|
|
tmp = [self globallyUniqueObjectId];
|
|
|
|
needsLocation = YES;
|
2007-05-19 02:42:51 +02:00
|
|
|
|
2008-07-09 17:42:22 +02:00
|
|
|
[self debugWithFormat:
|
|
|
|
@"reassigned a new location for special new-location: %@", tmp];
|
|
|
|
|
|
|
|
/* kinda dangerous */
|
|
|
|
ASSIGNCOPY (nameInContainer, tmp);
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-07-09 17:42:22 +02:00
|
|
|
/* determine base version from etag in if-match header */
|
|
|
|
/*
|
|
|
|
Note: The -matchesRequestConditionInContext: already checks whether the
|
|
|
|
etag matches and returns an HTTP exception in case it doesn't.
|
|
|
|
We retrieve the etag again here to _ensure_ a transactionally save
|
|
|
|
commit.
|
|
|
|
(between the check and the update a change could have been done)
|
|
|
|
*/
|
|
|
|
tmp = [rq headerForKey: @"if-match"];
|
|
|
|
tmp = [self parseETagList: tmp];
|
|
|
|
etag = nil;
|
|
|
|
if ([tmp count] > 0) {
|
|
|
|
if ([tmp count] > 1) {
|
|
|
|
/*
|
|
|
|
Note: we would have to attempt a save for _each_ of the etags being
|
|
|
|
passed in! In practice most WebDAV clients submit exactly one
|
|
|
|
etag.
|
|
|
|
*/
|
|
|
|
[self warnWithFormat:
|
|
|
|
@"Got multiple if-match etags from client, only attempting to "
|
|
|
|
@"save with the first: %@", tmp];
|
|
|
|
}
|
|
|
|
|
|
|
|
etag = [tmp objectAtIndex: 0];
|
|
|
|
}
|
|
|
|
baseVersion = (isNew ? 0 : version);
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-07-09 17:42:22 +02:00
|
|
|
/* attempt a save */
|
|
|
|
|
|
|
|
error = [self saveContentString: [rq contentAsString]
|
|
|
|
baseVersion: baseVersion];
|
|
|
|
if (error)
|
|
|
|
response = (WOResponse *) error;
|
|
|
|
else
|
|
|
|
{
|
2008-07-09 18:02:42 +02:00
|
|
|
if (!isNew)
|
|
|
|
version++;
|
2008-07-09 17:42:22 +02:00
|
|
|
response = [_ctx response];
|
|
|
|
/* setup response */
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-07-09 17:42:22 +02:00
|
|
|
// TODO: this should be automatic in the SoDispatcher if we return nil?
|
|
|
|
[response setStatus: 201 /* Created */];
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-07-09 17:42:22 +02:00
|
|
|
etag = [self davEntityTag];
|
|
|
|
if (etag)
|
|
|
|
{
|
|
|
|
[response setHeader: etag forKey: @"etag"];
|
|
|
|
if (needsLocation)
|
|
|
|
[response setHeader: [self baseURLInContext:_ctx]
|
|
|
|
forKey: @"location"];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2008-07-09 17:42:22 +02:00
|
|
|
return response;
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* E-Tags */
|
|
|
|
|
2007-04-27 20:58:48 +02:00
|
|
|
- (id) davEntityTag
|
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
return [NSString stringWithFormat: @"\"gcs%.8d\"", version];
|
2006-06-15 21:34:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* WebDAV */
|
2007-12-12 16:57:40 +01:00
|
|
|
- (NSString *) davCreationDate
|
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
return [creationDate rfc822DateString];
|
2007-12-12 16:57:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) davLastModified
|
|
|
|
{
|
2008-06-13 21:59:22 +02:00
|
|
|
return [lastModified rfc822DateString];
|
2007-12-12 16:57:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) davContentLength
|
|
|
|
{
|
|
|
|
return [NSString stringWithFormat: @"%u",
|
2008-04-24 03:05:13 +02:00
|
|
|
[content lengthOfBytesUsingEncoding: NSUTF8StringEncoding]];
|
2007-12-12 16:57:40 +01:00
|
|
|
}
|
2006-06-15 21:34:10 +02:00
|
|
|
|
2007-04-27 20:58:48 +02:00
|
|
|
- (NSException *) davMoveToTargetObject: (id) _target
|
|
|
|
newName: (NSString *) _name
|
|
|
|
inContext: (id) _ctx
|
2006-06-15 21:34:10 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Note: even for new objects we won't get a new name but a preinstantiated
|
|
|
|
object representing the new one.
|
|
|
|
*/
|
|
|
|
[self logWithFormat:
|
|
|
|
@"TODO: move not implemented:\n target: %@\n new name: %@",
|
|
|
|
_target, _name];
|
|
|
|
return [NSException exceptionWithHTTPStatus:405 /* not allowed */
|
|
|
|
reason:@"this object cannot be copied via WebDAV"];
|
|
|
|
}
|
|
|
|
|
2007-04-27 20:58:48 +02:00
|
|
|
- (NSException *) davCopyToTargetObject: (id)_target
|
|
|
|
newName: (NSString *) _name
|
|
|
|
inContext: (id) _ctx
|
2006-06-15 21:34:10 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Note: even for new objects we won't get a new name but a preinstantiated
|
|
|
|
object representing the new one.
|
|
|
|
*/
|
|
|
|
[self logWithFormat:
|
|
|
|
@"TODO: copy not implemented:\n target: %@\n new name: %@",
|
|
|
|
_target, _name];
|
|
|
|
return [NSException exceptionWithHTTPStatus:405 /* not allowed */
|
|
|
|
reason:@"this object cannot be copied via WebDAV"];
|
|
|
|
}
|
|
|
|
|
2007-04-17 16:32:47 +02:00
|
|
|
/* acls */
|
|
|
|
|
2007-05-19 02:42:51 +02:00
|
|
|
- (NSArray *) aclUsers
|
2007-04-17 16:32:47 +02:00
|
|
|
{
|
2008-05-16 22:33:55 +02:00
|
|
|
NSMutableArray *pathArray;
|
|
|
|
|
|
|
|
pathArray = [NSMutableArray arrayWithArray: [container pathArrayToFolder]];
|
|
|
|
[pathArray addObject: nameInContainer];
|
|
|
|
|
|
|
|
return pathArray;
|
2007-04-17 16:32:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) aclsForUser: (NSString *) uid
|
|
|
|
{
|
2007-04-26 03:16:19 +02:00
|
|
|
NSMutableArray *acls;
|
2008-02-07 17:51:41 +01:00
|
|
|
NSArray *containerAcls;
|
2007-04-26 03:16:19 +02:00
|
|
|
|
|
|
|
acls = [NSMutableArray array];
|
2007-12-20 22:56:37 +01:00
|
|
|
/* this is unused... */
|
|
|
|
// ownAcls = [container aclsForUser: uid
|
|
|
|
// forObjectAtPath: [self pathArrayToSOGoObject]];
|
|
|
|
// [acls addObjectsFromArray: ownAcls];
|
2007-04-26 03:16:19 +02:00
|
|
|
containerAcls = [container aclsForUser: uid];
|
|
|
|
if ([containerAcls count] > 0)
|
|
|
|
{
|
2007-11-27 22:06:11 +01:00
|
|
|
[acls addObjectsFromArray: containerAcls];
|
|
|
|
if (isNew)
|
2007-06-01 22:59:47 +02:00
|
|
|
{
|
2007-11-27 22:06:11 +01:00
|
|
|
if ([containerAcls containsObject: SOGoRole_ObjectCreator])
|
2007-06-01 22:59:47 +02:00
|
|
|
[acls addObject: SOGoRole_ObjectEditor];
|
2007-11-27 22:06:11 +01:00
|
|
|
else
|
|
|
|
[acls removeObject: SOGoRole_ObjectEditor];
|
2007-06-01 22:59:47 +02:00
|
|
|
}
|
2007-04-26 03:16:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return acls;
|
2007-04-17 16:32:47 +02:00
|
|
|
}
|
|
|
|
|
2007-04-25 00:45:38 +02:00
|
|
|
- (void) setRoles: (NSArray *) roles
|
2007-04-17 16:32:47 +02:00
|
|
|
forUser: (NSString *) uid
|
|
|
|
{
|
|
|
|
return [container setRoles: roles
|
|
|
|
forUser: uid
|
|
|
|
forObjectAtPath: [self pathArrayToSoObject]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeAclsForUsers: (NSArray *) users
|
|
|
|
{
|
|
|
|
return [container removeAclsForUsers: users
|
|
|
|
forObjectAtPath: [self pathArrayToSoObject]];
|
|
|
|
}
|
|
|
|
|
2007-05-22 20:35:17 +02:00
|
|
|
- (NSString *) defaultUserID
|
|
|
|
{
|
|
|
|
return @"<default>";
|
|
|
|
}
|
|
|
|
|
2006-06-15 21:34:10 +02:00
|
|
|
/* message type */
|
|
|
|
|
2007-04-27 20:58:48 +02:00
|
|
|
- (NSString *) outlookMessageClass
|
|
|
|
{
|
2006-06-15 21:34:10 +02:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end /* SOGoContentObject */
|