2008-02-22 22:25:34 +01:00
/ * SOGoGCSFolder . m - this file is part of SOGo
*
* Copyright ( C ) 2004 -2005 SKYRIX Software AG
2014-05-02 19:35:21 +02:00
* Copyright ( C ) 2006 -2014 Inverse inc .
2008-02-22 22:25:34 +01: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 .
* /
2007-06-18 17:37:37 +02:00
2007-09-11 22:25:57 +02:00
# import < NGObjWeb / NSException + HTTP . h >
2007-07-22 22:40:34 +02:00
# import < NGObjWeb / SoObject + SoDAV . h >
2007-07-04 22:13:49 +02:00
# import < NGObjWeb / WOContext + SoObjects . h >
2007-10-14 18:07:22 +02:00
# import < NGObjWeb / WOApplication . h >
2008-02-22 22:25:34 +01:00
# import < NGExtensions / NSString + misc . h >
2007-06-18 17:37:37 +02:00
# import < NGExtensions / NSNull + misc . h >
# import < NGExtensions / NSObject + Logs . h >
2009-06-08 19:49:15 +02:00
# import < EOControl / EOFetchSpecification . h >
2007-06-18 17:37:37 +02:00
# import < EOControl / EOQualifier . h >
2007-04-17 16:30:12 +02:00
# import < GDLAccess / EOAdaptorChannel . h >
2009-01-21 18:01:06 +01:00
# import < GDLAccess / EOAdaptorContext . h >
2007-09-15 00:01:02 +02:00
# import < GDLContentStore / GCSChannelManager . h >
2007-02-09 22:21:35 +01:00
# import < GDLContentStore / GCSFolderManager . h >
# import < GDLContentStore / GCSFolder . h >
2007-09-15 00:01:02 +02:00
# import < GDLContentStore / NSURL + GCS . h >
2007-06-05 00:38:43 +02:00
# import < SaxObjC / XMLNamespaces . h >
2006-12-14 22:20:13 +01:00
2009-11-29 05:19:32 +01:00
# import "NSDictionary+Utilities.h"
2007-08-24 22:38:44 +02:00
# import "NSArray+Utilities.h"
2009-10-06 20:26:09 +02:00
# import "NSArray+DAV.h"
2008-05-03 01:11:21 +02:00
# import "NSObject+DAV.h"
2010-04-09 20:45:14 +02:00
# import "NSObject+Utilities.h"
2007-07-22 22:40:34 +02:00
# import "NSString+Utilities.h"
2009-06-19 16:49:47 +02:00
# import "NSString+DAV.h"
2007-07-22 22:40:34 +02:00
2009-06-18 22:58:46 +02:00
# import "DOMNode+SOGo.h"
2009-09-17 01:47:36 +02:00
# import "SOGoCache.h"
2007-09-15 01:16:48 +02:00
# import "SOGoContentObject.h"
2009-11-29 05:19:32 +01:00
# import "SOGoDomainDefaults.h"
2019-11-26 15:29:02 +01:00
# import "SOGoSource.h"
2007-11-20 20:15:26 +01:00
# import "SOGoParentFolder.h"
2007-04-26 03:16:19 +02:00
# import "SOGoPermissions.h"
2007-07-04 22:13:49 +02:00
# import "SOGoUser.h"
2009-11-29 05:19:32 +01:00
# import "SOGoUserSettings.h"
2010-10-15 20:30:08 +02:00
# import "SOGoUserManager.h"
2008-05-03 01:11:21 +02:00
# import "SOGoWebDAVAclManager.h"
2008-02-07 17:51:41 +01:00
# import "WORequest+SOGo.h"
2009-08-05 17:36:09 +02:00
# import "WOResponse+SOGo.h"
2007-06-18 17:37:37 +02:00
2007-11-07 16:58:43 +01:00
# import "SOGoGCSFolder.h"
2006-06-15 21:34:10 +02:00
2007-05-22 20:35:17 +02:00
static NSString * defaultUserID = @ "<default>" ;
2008-06-13 22:16:30 +02:00
static NSArray * childRecordFields = nil ;
2007-05-22 20:35:17 +02:00
2007-11-07 16:58:43 +01:00
@ implementation SOGoGCSFolder
2006-06-15 21:34:10 +02:00
2010-06-08 17:55:51 +02:00
+ ( void ) initialize
{
if ( ! childRecordFields )
{
childRecordFields = [ NSArray arrayWithObjects : @ "c_name" , @ "c_version" ,
@ "c_creationdate" , @ "c_lastmodified" ,
@ "c_component" , @ "c_content" , nil ] ;
[ childRecordFields retain ] ;
}
}
2008-05-03 01:11:21 +02:00
+ ( SOGoWebDAVAclManager * ) webdavAclManager
{
2008-12-15 23:27:45 +01:00
static SOGoWebDAVAclManager * aclManager = nil ;
2008-05-03 01:11:21 +02:00
2008-07-29 18:36:16 +02:00
if ( ! aclManager )
2008-05-03 01:11:21 +02:00
{
2008-07-29 18:36:16 +02:00
aclManager = [ SOGoWebDAVAclManager new ] ;
2010-01-15 00:19:19 +01:00
/ * [ aclManager registerDAVPermission : davElement ( @ "read" , @ "DAV:" )
2008-07-29 18:36:16 +02:00
abstract : YES
withEquivalent : SoPerm_WebDAVAccess
asChildOf : davElement ( @ "all" , @ "DAV:" ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "read-current-user-privilege-set" , @ "DAV:" )
abstract : YES
withEquivalent : SoPerm_WebDAVAccess
2010-01-15 00:19:19 +01:00
asChildOf : davElement ( @ "read" , @ "DAV:" ) ] ; * /
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "write" , @ "DAV:" )
2012-02-07 15:00:04 +01:00
abstract : NO
withEquivalent : SoPerm_AddDocumentsImagesAndFiles
2008-07-29 18:36:16 +02:00
asChildOf : davElement ( @ "all" , @ "DAV:" ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "bind" , @ "DAV:" )
abstract : NO
withEquivalent : SoPerm_AddDocumentsImagesAndFiles
asChildOf : davElement ( @ "write" , @ "DAV:" ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "unbind" , @ "DAV:" )
abstract : NO
withEquivalent : SoPerm_DeleteObjects
asChildOf : davElement ( @ "write" , @ "DAV:" ) ] ;
[ aclManager
2008-05-03 01:11:21 +02:00
registerDAVPermission : davElement ( @ "write-properties" , @ "DAV:" )
abstract : YES
withEquivalent : SoPerm_ChangePermissions / * hackish * /
asChildOf : davElement ( @ "write" , @ "DAV:" ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager
2008-05-03 01:11:21 +02:00
registerDAVPermission : davElement ( @ "write-content" , @ "DAV:" )
abstract : YES
withEquivalent : nil
asChildOf : davElement ( @ "write" , @ "DAV:" ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "admin" , @ "urn:inverse:params:xml:ns:inverse-dav" )
abstract : YES
withEquivalent : nil
asChildOf : davElement ( @ "all" , @ "DAV:" ) ] ;
[ aclManager
2008-05-03 01:11:21 +02:00
registerDAVPermission : davElement ( @ "read-acl" , @ "DAV:" )
abstract : YES
withEquivalent : SOGoPerm_ReadAcls
asChildOf : davElement ( @ "admin" , @ "urn:inverse:params:xml:ns:inverse-dav" ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager
2008-05-03 01:11:21 +02:00
registerDAVPermission : davElement ( @ "write-acl" , @ "DAV:" )
abstract : YES
withEquivalent : SoPerm_ChangePermissions
asChildOf : davElement ( @ "admin" , @ "urn:inverse:params:xml:ns:inverse-dav" ) ] ;
}
2008-07-29 18:36:16 +02:00
return aclManager ;
2008-05-03 01:11:21 +02:00
}
2007-09-15 00:01:02 +02:00
+ ( id ) folderWithSubscriptionReference : ( NSString * ) reference
inContainer : ( id ) aContainer
2007-09-11 22:25:57 +02:00
{
id newFolder ;
2007-09-15 00:01:02 +02:00
NSArray * elements , * pathElements ;
2011-04-05 15:50:09 +02:00
NSString * path , * objectPath , * login , * ocsName , * folderName ;
2010-04-20 23:30:17 +02:00
WOContext * localContext ;
BOOL localIsSubscription ;
2007-09-15 00:01:02 +02:00
elements = [ reference componentsSeparatedByString : @ ":" ] ;
2007-11-08 21:35:09 +01:00
login = [ elements objectAtIndex : 0 ] ;
2010-04-20 23:30:17 +02:00
localContext = [ [ WOApplication application ] context ] ;
2007-09-15 00:01:02 +02:00
objectPath = [ elements objectAtIndex : 1 ] ;
pathElements = [ objectPath componentsSeparatedByString : @ "/" ] ;
if ( [ pathElements count ] > 1 )
ocsName = [ pathElements objectAtIndex : 1 ] ;
else
ocsName = @ "personal" ;
2007-09-11 22:25:57 +02:00
2007-11-09 00:04:42 +01:00
path = [ NSString stringWithFormat : @ "/Users/%@/%@/%@" ,
login , [ pathElements objectAtIndex : 0 ] , ocsName ] ;
2010-09-20 19:18:37 +02:00
localIsSubscription = ! [ login isEqualToString :
[ aContainer ownerInContext : localContext ] ] ;
if ( localIsSubscription )
folderName = [ NSString stringWithFormat : @ "%@_%@" ,
[ login asCSSIdentifier ] , ocsName ] ;
else
folderName = ocsName ;
2007-11-09 00:04:42 +01:00
newFolder = [ self objectWithName : folderName inContainer : aContainer ] ;
[ newFolder setOCSPath : path ] ;
2007-11-08 21:35:09 +01:00
[ newFolder setOwner : login ] ;
2010-04-20 23:30:17 +02:00
[ newFolder setIsSubscription : localIsSubscription ] ;
2007-11-29 22:10:39 +01:00
if ( ! [ newFolder displayName ] )
2018-06-27 21:39:14 +02:00
newFolder = nil ;
2007-09-11 22:25:57 +02:00
return newFolder ;
2006-06-15 21:34:10 +02:00
}
2007-04-27 21:45:12 +02:00
- ( id ) init
{
if ( ( self = [ super init ] ) )
{
ocsPath = nil ;
ocsFolder = nil ;
2008-06-13 22:16:30 +02:00
childRecords = [ NSMutableDictionary new ] ;
2009-06-04 02:40:21 +02:00
userCanAccessAllObjects = NO ;
2007-04-27 21:45:12 +02:00
}
return self ;
}
- ( void ) dealloc
{
[ ocsFolder release ] ;
[ ocsPath release ] ;
2008-06-13 22:16:30 +02:00
[ childRecords release ] ;
2006-06-15 21:34:10 +02:00
[ super dealloc ] ;
}
/ * accessors * /
2010-03-10 22:53:26 +01:00
- ( void ) setFolderPropertyValue : ( id ) theValue
inCategory : ( NSString * ) theKey
2014-07-24 18:48:03 +02:00
settings : ( SOGoUserSettings * ) theSettings
2010-03-10 22:53:26 +01:00
{
NSMutableDictionary * folderSettings , * values ;
NSString * module ;
module = [ container nameInContainer ] ;
2014-07-24 18:48:03 +02:00
folderSettings = [ theSettings objectForKey : module ] ;
2010-03-10 22:53:26 +01:00
if ( ! folderSettings )
{
folderSettings = [ NSMutableDictionary dictionary ] ;
2014-07-24 18:48:03 +02:00
[ theSettings setObject : folderSettings forKey : module ] ;
2010-03-10 22:53:26 +01:00
}
values = [ folderSettings objectForKey : theKey ] ;
if ( theValue )
{
if ( ! values )
{
// Create the property dictionary
values = [ NSMutableDictionary dictionary ] ;
[ folderSettings setObject : values forKey : theKey ] ;
}
[ values setObject : theValue forKey : [ self folderReference ] ] ;
}
else if ( values )
{
// Remove the property for the folder
[ values removeObjectForKey : [ self folderReference ] ] ;
if ( [ values count ] = = 0 )
// Also remove the property dictionary when empty
[ folderSettings removeObjectForKey : theKey ] ;
}
2014-07-24 18:48:03 +02:00
[ theSettings synchronize ] ;
}
- ( void ) setFolderPropertyValue : ( id ) theValue
inCategory : ( NSString * ) theKey
{
SOGoUserSettings * settings ;
settings = [ [ context activeUser ] userSettings ] ;
[ self setFolderPropertyValue : theValue
inCategory : theKey
settings : settings ] ;
2010-03-10 22:53:26 +01:00
}
- ( id ) folderPropertyValueInCategory : ( NSString * ) theKey
2010-11-12 17:40:17 +01:00
{
return [ self folderPropertyValueInCategory : theKey
forUser : [ context activeUser ] ] ;
}
- ( id ) folderPropertyValueInCategory : ( NSString * ) theKey
forUser : ( SOGoUser * ) theUser
2010-03-10 22:53:26 +01:00
{
SOGoUserSettings * settings ;
NSDictionary * folderSettings ;
id value ;
2010-11-12 17:40:17 +01:00
settings = [ theUser userSettings ] ;
2010-03-10 22:53:26 +01:00
folderSettings = [ settings objectForKey : [ container nameInContainer ] ] ;
value = [ [ folderSettings objectForKey : theKey ]
objectForKey : [ self folderReference ] ] ;
return value ;
}
2014-10-09 21:10:20 +02:00
- ( NSString * ) _displayNameFromRow : ( NSDictionary * ) row
2007-09-15 00:01:02 +02:00
{
2014-10-09 21:10:20 +02:00
NSString * name , * primaryDN ;
2014-05-20 23:05:13 +02:00
2014-10-09 21:10:20 +02:00
name = nil ;
2007-11-20 20:15:26 +01:00
primaryDN = [ row objectForKey : @ "c_foldername" ] ;
2014-07-24 18:48:03 +02:00
2007-11-30 17:43:55 +01:00
if ( [ primaryDN length ] )
2007-09-15 00:01:02 +02:00
{
2014-07-24 18:48:03 +02:00
if ( [ primaryDN isEqualToString : [ container defaultFolderName ] ] )
2014-10-09 21:10:20 +02:00
name = [ self labelForKey : primaryDN
inContext : context ] ;
2014-07-24 18:48:03 +02:00
else
2014-10-09 21:10:20 +02:00
name = primaryDN ;
2007-09-15 00:01:02 +02:00
}
2014-10-09 21:10:20 +02:00
return name ;
2007-09-15 00:01:02 +02:00
}
2015-09-25 21:18:22 +02:00
- ( BOOL ) synchronize
{
NSNumber * synchronize ;
synchronize = [ self folderPropertyValueInCategory : @ "FolderSynchronize" ] ;
return [ synchronize boolValue ] ;
}
- ( void ) setSynchronize : ( BOOL ) new
{
NSNumber * synchronize ;
if ( new )
synchronize = [ NSNumber numberWithBool : YES ] ;
else
synchronize = nil ;
[ self setFolderPropertyValue : synchronize
inCategory : @ "FolderSynchronize" ] ;
}
2010-03-10 22:53:26 +01:00
/ * This method fetches the display name defined by the owner , but is also the
2014-12-19 01:34:05 +01:00
fallback when a subscriber has not redefined the display name yet in their
2010-03-10 22:53:26 +01:00
environment . * /
2014-10-09 21:10:20 +02:00
- ( NSString * ) _displayNameFromOwner
2007-09-15 00:01:02 +02:00
{
GCSChannelManager * cm ;
EOAdaptorChannel * fc ;
NSURL * folderLocation ;
2014-10-09 21:10:20 +02:00
NSString * name , * sql ;
2007-09-15 00:01:02 +02:00
NSArray * attrs ;
NSDictionary * row ;
2014-10-09 21:10:20 +02:00
name = nil ;
2007-09-15 00:01:02 +02:00
cm = [ GCSChannelManager defaultChannelManager ] ;
2014-10-09 21:10:20 +02:00
folderLocation = [ [ GCSFolderManager defaultFolderManager ] folderInfoLocation ] ;
2007-09-15 00:01:02 +02:00
fc = [ cm acquireOpenChannelForURL : folderLocation ] ;
if ( fc )
{
2014-06-16 17:00:39 +02:00
// We use an exception handler here in case the database is down when
// performing the query . This could have unexpected results .
NS_DURING
{
2014-10-09 21:10:20 +02:00
sql = [ NSString stringWithFormat : ( @ "SELECT c_foldername FROM %@"
@ " WHERE c_path = '%@'" ) ,
[ folderLocation gcsTableName ] , ocsPath ] ;
2014-06-16 17:00:39 +02:00
[ fc evaluateExpressionX : sql ] ;
attrs = [ fc describeResults : NO ] ;
row = [ fc fetchAttributes : attrs withZone : NULL ] ;
if ( row )
2014-10-09 21:10:20 +02:00
name = [ self _displayNameFromRow : row ] ;
2014-06-16 17:00:39 +02:00
[ fc cancelFetch ] ;
[ cm releaseChannel : fc ] ;
}
2018-06-27 21:39:19 +02:00
NS_HANDLER ;
2014-06-16 17:00:39 +02:00
NS_ENDHANDLER ;
2007-09-15 00:01:02 +02:00
}
2014-10-09 21:10:20 +02:00
return name ;
2007-09-15 00:01:02 +02:00
}
2014-10-09 21:10:20 +02:00
- ( NSString * ) _displayNameFromSubscriber
2010-03-10 22:53:26 +01:00
{
2014-08-25 18:15:05 +02:00
NSDictionary * ownerIdentity , * folderSubscriptionValues ;
2014-10-09 21:10:20 +02:00
NSString * name , * displayNameFormat ;
2014-08-25 18:15:05 +02:00
SOGoDomainDefaults * dd ;
2014-10-09 21:10:20 +02:00
name = [ self folderPropertyValueInCategory : @ "FolderDisplayNames" ] ;
if ( ! name )
2014-08-25 18:15:05 +02:00
{
2014-10-09 21:10:20 +02:00
name = [ self _displayNameFromOwner ] ;
2014-08-25 18:15:05 +02:00
// We MUST NOT use SOGoUser instances here ( by calling - primaryIdentity )
// as it ' ll load user defaults and user settings which is _very costly_
// since it involves JSON parsing and database requests
ownerIdentity = [ [ SOGoUserManager sharedUserManager ]
contactInfosForUserWithUIDorEmail : owner ] ;
2014-10-09 21:10:20 +02:00
folderSubscriptionValues = [ [ NSDictionary alloc ] initWithObjectsAndKeys : name , @ "FolderName" ,
2014-08-25 18:15:05 +02:00
[ ownerIdentity objectForKey : @ "cn" ] , @ "UserName" ,
[ ownerIdentity objectForKey : @ "c_email" ] , @ "Email" , nil ] ;
dd = [ [ context activeUser ] domainDefaults ] ;
displayNameFormat = [ dd subscriptionFolderFormat ] ;
2017-05-17 15:44:34 +02:00
// Use a format only if it was defined by the user
if ( displayNameFormat )
name = [ folderSubscriptionValues keysWithFormat : displayNameFormat ] ;
2014-08-25 18:15:05 +02:00
}
2014-10-09 21:10:20 +02:00
return name ;
2010-03-10 22:53:26 +01:00
}
2007-09-11 22:25:57 +02:00
- ( NSString * ) displayName
{
2007-11-30 17:43:55 +01:00
if ( ! displayName )
2010-03-10 22:53:26 +01:00
{
if ( activeUserIsOwner )
2015-11-04 00:29:50 +01:00
displayName = ( NSMutableString * ) [ self _displayNameFromOwner ] ;
2010-03-10 22:53:26 +01:00
else
{
2015-11-04 00:29:50 +01:00
displayName = ( NSMutableString * ) [ self _displayNameFromSubscriber ] ;
2010-03-10 22:53:26 +01:00
if ( ! displayName )
2015-11-04 00:29:50 +01:00
displayName = ( NSMutableString * ) [ self _displayNameFromOwner ] ;
2010-03-10 22:53:26 +01:00
}
2014-10-09 21:10:20 +02:00
[ displayName retain ] ;
2010-03-10 22:53:26 +01:00
}
2007-11-30 17:43:55 +01:00
2007-09-11 22:25:57 +02:00
return displayName ;
}
2007-11-07 16:58:43 +01:00
- ( void ) setOCSPath : ( NSString * ) _path
{
if ( ! [ ocsPath isEqualToString : _path ] )
{
if ( ocsPath )
[ self warnWithFormat : @ "GCS path is already set! '%@'" , _path ] ;
ASSIGN ( ocsPath , _path ) ;
}
}
- ( NSString * ) ocsPath
{
return ocsPath ;
}
- ( GCSFolderManager * ) folderManager
{
static GCSFolderManager * folderManager = nil ;
if ( ! folderManager )
folderManager = [ GCSFolderManager defaultFolderManager ] ;
return folderManager ;
}
- ( GCSFolder * ) ocsFolderForPath : ( NSString * ) _path
{
2017-01-31 21:59:58 +01:00
NSDictionary * record ;
SOGoCache * cache ;
cache = [ SOGoCache sharedCache ] ;
record = [ [ cache valueForKey : _path ] objectFromJSONString ] ;
2017-06-22 16:20:54 +02:00
// We check if we got a cache miss or a potentially bogus
// entry from the cache
if ( ! record || ! [ record objectForKey : @ "c_folder_type" ] )
2017-01-31 21:59:58 +01:00
{
record = [ [ self folderManager ] recordAtPath : _path ] ;
if ( ! record )
2018-06-27 21:39:19 +02:00
return nil ;
2017-01-31 21:59:58 +01:00
[ cache setValue : [ record jsonRepresentation ] forKey : _path ] ;
}
return [ [ self folderManager ] folderForRecord : record ] ;
2007-11-07 16:58:43 +01:00
}
- ( BOOL ) folderIsMandatory
{
return [ nameInContainer isEqualToString : @ "personal" ] ;
}
2008-04-22 01:03:48 +02:00
- ( NSString * ) folderReference
{
2008-05-16 22:33:55 +02:00
return [ NSString stringWithFormat : @ "%@:%@/%@" ,
owner ,
[ container nameInContainer ] ,
[ self realNameInContainer ] ] ;
}
2008-04-22 01:03:48 +02:00
2008-05-16 22:33:55 +02:00
- ( NSArray * ) pathArrayToFolder
{
NSArray * basePathElements ;
unsigned int max ;
2008-04-22 01:03:48 +02:00
2008-05-16 22:33:55 +02:00
basePathElements = [ [ self ocsPath ] componentsSeparatedByString : @ "/" ] ;
max = [ basePathElements count ] ;
2008-04-22 01:03:48 +02:00
2008-05-16 22:33:55 +02:00
return [ basePathElements subarrayWithRange : NSMakeRange ( 2 , max - 2 ) ] ;
2008-04-22 01:03:48 +02:00
}
- ( NSException * ) setDavDisplayName : ( NSString * ) newName
{
NSException * error ;
2010-03-10 22:53:26 +01:00
if ( [ newName length ] )
2008-04-22 01:03:48 +02:00
{
2019-10-28 19:39:39 +01:00
NS_DURING
{
[ self renameTo : newName ] ;
error = nil ;
}
NS_HANDLER
error = [ NSException exceptionWithHTTPStatus : 409
reason : @ "Existing name" ] ;
NS_ENDHANDLER ;
2008-04-22 01:03:48 +02:00
}
else
2019-10-28 19:39:39 +01:00
error = [ NSException exceptionWithHTTPStatus : 403
2010-03-10 22:53:26 +01:00
reason : @ "Empty string" ] ;
2008-04-22 01:03:48 +02:00
return error ;
}
2010-06-29 22:21:48 +02:00
- ( NSURL * ) publicDavURL
{
NSMutableArray * newPath ;
NSURL * davURL ;
2017-01-31 03:56:33 +01:00
unsigned int max , count ;
2010-06-29 22:21:48 +02:00
davURL = [ self realDavURL ] ;
newPath = [ NSMutableArray arrayWithArray : [ [ davURL path ] componentsSeparatedByString : @ "/" ] ] ;
[ newPath insertObject : @ "public" atIndex : 3 ] ;
2017-01-31 03:56:33 +01:00
max = [ newPath count ] ;
for ( count = 0 ; count < max ; count + + )
[ newPath replaceObjectAtIndex : count
withObject : [ [ newPath objectAtIndex : count ] stringByEscapingURL ] ] ;
2017-01-06 22:49:00 +01:00
davURL = [ NSURL URLWithString : [ newPath componentsJoinedByString : @ "/" ]
relativeToURL : davURL ] ;
2010-06-29 22:21:48 +02:00
return davURL ;
}
2010-06-05 06:44:02 +02:00
- ( NSURL * ) realDavURL
{
NSURL * realDavURL , * currentDavURL ;
NSString * appName , * publicParticle , * path ;
if ( isSubscription )
{
appName = [ [ context request ] applicationName ] ;
if ( [ self isInPublicZone ] )
publicParticle = @ "/public" ;
else
publicParticle = @ "" ;
path = [ NSString stringWithFormat : @ "/%@/dav%@/%@/%@/%@/" ,
appName , publicParticle ,
2017-01-31 03:56:33 +01:00
[ [ self ownerInContext : nil ] stringByEscapingURL ] ,
[ [ container nameInContainer ] stringByEscapingURL ] ,
[ [ self realNameInContainer ] stringByEscapingURL ] ] ;
2010-06-05 06:44:02 +02:00
currentDavURL = [ self davURL ] ;
2017-01-06 22:49:00 +01:00
realDavURL = [ NSURL URLWithString : path relativeToURL : currentDavURL ] ;
2010-06-05 06:44:02 +02:00
}
else
realDavURL = [ self davURL ] ;
return realDavURL ;
}
2007-04-27 21:45:12 +02:00
- ( GCSFolder * ) ocsFolder
{
2006-09-29 20:26:29 +02:00
GCSFolder * folder ;
2011-04-14 20:41:10 +02:00
SOGoUser * user ;
2007-07-04 22:13:49 +02:00
NSString * userLogin ;
2006-09-29 20:26:29 +02:00
if ( ! ocsFolder )
2007-06-29 23:58:23 +02:00
{
ocsFolder = [ self ocsFolderForPath : [ self ocsPath ] ] ;
2011-04-14 20:41:10 +02:00
user = [ context activeUser ] ;
userLogin = [ user login ] ;
2007-06-29 23:58:23 +02:00
if ( ! ocsFolder
2007-11-07 16:58:43 +01:00
&& [ userLogin isEqualToString : [ self ownerInContext : context ] ]
2011-04-14 20:41:10 +02:00
&& [ user canAuthenticate ]
2007-06-29 23:58:23 +02:00
&& [ self folderIsMandatory ]
&& [ self create ] )
ocsFolder = [ self ocsFolderForPath : [ self ocsPath ] ] ;
[ ocsFolder retain ] ;
}
2006-09-29 20:26:29 +02:00
if ( [ ocsFolder isNotNull ] )
folder = ocsFolder ;
else
folder = nil ;
return folder ;
2006-06-15 21:34:10 +02:00
}
2007-02-09 22:21:35 +01:00
- ( BOOL ) create
{
NSException * result ;
2011-04-04 15:01:20 +02:00
result = [ [ self folderManager ] createFolderOfType : [ self folderType ]
withName : displayName
atPath : ocsPath ] ;
2007-02-09 22:21:35 +01:00
2008-02-06 17:20:59 +01:00
if ( ! result
2009-01-09 18:32:30 +01:00
&& [ [ context request ] handledByDefaultHandler ] )
2008-02-06 17:20:59 +01:00
[ self sendFolderAdvisoryTemplate : @ "Addition" ] ;
2007-12-03 15:13:10 +01:00
2007-02-09 22:21:35 +01:00
return ( result = = nil ) ;
}
2007-03-21 15:27:04 +01:00
- ( NSException * ) delete
{
2007-09-11 22:25:57 +02:00
NSException * error ;
2010-10-08 21:53:04 +02:00
SOGoUserSettings * us ;
NSMutableDictionary * moduleSettings ;
2007-09-11 22:25:57 +02:00
2007-10-14 18:07:22 +02:00
// We just fetch our displayName since our table will use it !
[ self displayName ] ;
2007-09-11 22:25:57 +02:00
if ( [ nameInContainer isEqualToString : @ "personal" ] )
error = [ NSException exceptionWithHTTPStatus : 403
2007-09-15 00:01:02 +02:00
reason : @ "folder 'personal' cannot be deleted" ] ;
2007-09-11 22:25:57 +02:00
else
error = [ [ self folderManager ] deleteFolderAtPath : ocsPath ] ;
2010-10-08 21:53:04 +02:00
if ( ! error )
{
us = [ [ SOGoUser userWithLogin : owner ] userSettings ] ;
moduleSettings = [ us objectForKey : [ container nameInContainer ] ] ;
[ self removeFolderSettings : moduleSettings
withReference : [ self folderReference ] ] ;
[ us synchronize ] ;
2017-01-31 21:59:58 +01:00
[ [ SOGoCache sharedCache ] removeValueForKey : ocsPath ] ;
2010-10-08 21:53:04 +02:00
if ( [ [ context request ] handledByDefaultHandler ] )
[ self sendFolderAdvisoryTemplate : @ "Removal" ] ;
}
2007-12-03 15:13:10 +01:00
2007-09-11 22:25:57 +02:00
return error ;
2007-03-21 15:27:04 +01:00
}
2010-03-10 22:53:26 +01:00
- ( void ) _ownerRenameTo : ( NSString * ) newName
2007-09-15 00:01:02 +02:00
{
GCSChannelManager * cm ;
EOAdaptorChannel * fc ;
NSURL * folderLocation ;
NSString * sql ;
2018-08-31 04:09:17 +02:00
if ( [ [ self container ] hasLocalSubFolderNamed : newName ] )
[ NSException raise : NSInvalidArgumentException
format : @ "That name already exists" ] ;
2007-09-15 00:01:02 +02:00
cm = [ GCSChannelManager defaultChannelManager ] ;
2018-08-31 04:09:17 +02:00
folderLocation = [ [ GCSFolderManager defaultFolderManager ] folderInfoLocation ] ;
2007-09-15 00:01:02 +02:00
fc = [ cm acquireOpenChannelForURL : folderLocation ] ;
if ( fc )
{
2010-03-10 22:53:26 +01:00
# warning GDLContentStore should provide methods for renaming folders
2018-08-31 04:09:17 +02:00
sql = [ NSString stringWithFormat : ( @ "UPDATE %@ SET c_foldername = '%@'"
@ " WHERE c_path = '%@'" ) ,
[ folderLocation gcsTableName ] ,
[ newName stringByReplacingString : @ "'" withString : @ "''" ] ,
ocsPath ] ;
2007-09-15 00:01:02 +02:00
[ fc evaluateExpressionX : sql ] ;
[ cm releaseChannel : fc ] ;
// sql = [ sql stringByAppendingFormat : @ " WHERE %@ = '%@'" ,
// uidColumnName , [ self uid ] ] ;
}
}
2010-03-10 22:53:26 +01:00
- ( void ) _subscriberRenameTo : ( NSString * ) newName
{
if ( [ newName length ] )
[ self setFolderPropertyValue : newName
inCategory : @ "FolderDisplayNames" ] ;
}
- ( void ) renameTo : ( NSString * ) newName
{
2019-10-28 19:39:39 +01:00
if ( ! displayName )
[ self displayName ] ;
if ( [ displayName isEqualToString : newName ] )
return ;
2010-03-10 22:53:26 +01:00
# warning SOGoFolder should have the corresponding method
[ displayName release ] ;
displayName = nil ;
2010-09-17 20:30:10 +02:00
if ( activeUserIsOwner )
2010-03-10 22:53:26 +01:00
[ self _ownerRenameTo : newName ] ;
else
[ self _subscriberRenameTo : newName ] ;
}
2010-07-15 01:11:37 +02:00
/ * Returns an empty string to indicate that the filter is empty and nil when
the query should not even be performed . * /
2010-06-01 20:12:01 +02:00
- ( NSString * ) aclSQLListingFilter
2007-06-29 23:58:23 +02:00
{
2010-06-01 20:12:01 +02:00
NSString * filter , * login ;
NSArray * roles ;
2010-07-15 01:11:37 +02:00
SOGoUser * activeUser ;
2010-06-01 20:12:01 +02:00
2010-07-15 01:11:37 +02:00
activeUser = [ context activeUser ] ;
login = [ activeUser login ] ;
2010-06-01 20:12:01 +02:00
if ( activeUserIsOwner
2010-07-15 01:11:37 +02:00
|| [ [ self ownerInContext : nil ] isEqualToString : login ]
|| ( [ activeUser respondsToSelector : @ selector ( isSuperUser ) ]
&& [ activeUser isSuperUser ] ) )
2010-06-01 20:12:01 +02:00
filter = @ "" ;
else
2007-06-29 23:58:23 +02:00
{
2010-06-01 20:12:01 +02:00
roles = [ self aclsForUser : login ] ;
if ( [ roles containsObject : SOGoRole_ObjectViewer ]
|| [ roles containsObject : SOGoRole_ObjectEditor ] )
filter = @ "" ;
else
filter = nil ;
2007-06-29 23:58:23 +02:00
}
2008-02-12 16:48:53 +01:00
2010-06-01 20:12:01 +02:00
return filter ;
}
2012-04-13 01:44:39 +02:00
- ( NSString * ) componentSQLFilter
{
return nil ;
}
2010-06-01 20:12:01 +02:00
- ( NSArray * ) toOneRelationshipKeys
{
NSArray * records , * names ;
2012-04-13 01:44:39 +02:00
NSString * sqlFilter , * compFilter ;
EOQualifier * aclQualifier , * componentQualifier , * qualifier ;
2010-06-01 20:12:01 +02:00
sqlFilter = [ self aclSQLListingFilter ] ;
if ( sqlFilter )
{
if ( [ sqlFilter length ] > 0 )
2012-04-13 01:44:39 +02:00
aclQualifier = [ EOQualifier qualifierWithQualifierFormat : sqlFilter ] ;
else
aclQualifier = nil ;
compFilter = [ self componentSQLFilter ] ;
if ( [ compFilter length ] > 0 )
{
componentQualifier
= [ EOQualifier qualifierWithQualifierFormat : compFilter ] ;
if ( aclQualifier )
{
qualifier = [ [ EOAndQualifier alloc ] initWithQualifiers :
aclQualifier ,
2012-10-18 17:34:47 +02:00
componentQualifier ,
nil ] ;
2012-04-13 01:44:39 +02:00
[ qualifier autorelease ] ;
}
else
qualifier = componentQualifier ;
}
2010-06-01 20:12:01 +02:00
else
2012-04-13 01:44:39 +02:00
qualifier = aclQualifier ;
2010-06-01 20:12:01 +02:00
records = [ [ self ocsFolder ] fetchFields : childRecordFields
matchingQualifier : qualifier ] ;
if ( ! [ records isNotNull ] )
{
[ self errorWithFormat : @ "(%s): fetch failed!" , __PRETTY _FUNCTION __ ] ;
return nil ;
}
if ( [ records isKindOfClass : [ NSException class ] ] )
return records ;
names = [ records objectsForKey : @ "c_name" notFoundMarker : nil ] ;
[ childRecords release ] ;
childRecords = [ [ NSMutableDictionary alloc ] initWithObjects : records
forKeys : names ] ;
}
else
names = [ NSArray array ] ;
2008-06-13 22:16:30 +02:00
return names ;
2006-06-15 21:34:10 +02:00
}
2006-08-09 23:32:39 +02:00
2008-06-13 22:16:30 +02:00
- ( NSDictionary * ) _recordForObjectName : ( NSString * ) objectName
2007-02-21 22:11:40 +01:00
{
2008-06-13 22:16:30 +02:00
NSArray * records ;
2007-02-21 22:11:40 +01:00
EOQualifier * qualifier ;
2008-06-13 22:16:30 +02:00
NSDictionary * record ;
2007-02-21 22:11:40 +01:00
qualifier
= [ EOQualifier qualifierWithQualifierFormat :
[ NSString stringWithFormat : @ "c_name='%@'" , objectName ] ] ;
2008-06-13 22:16:30 +02:00
records = [ [ self ocsFolder ] fetchFields : childRecordFields
2007-02-21 22:11:40 +01:00
matchingQualifier : qualifier ] ;
2008-06-13 22:16:30 +02:00
if ( ! [ records isKindOfClass : [ NSException class ] ]
&& [ records count ] )
record = [ records objectAtIndex : 0 ] ;
else
record = nil ;
return record ;
}
2011-03-07 19:58:14 +01:00
- ( void ) removeChildRecordWithName : ( NSString * ) childName
{
[ childRecords removeObjectForKey : childName ] ;
}
2008-06-13 22:16:30 +02:00
- ( Class ) objectClassForComponentName : ( NSString * ) componentName
{
[ self subclassResponsibility : _cmd ] ;
return Nil ;
}
- ( Class ) objectClassForContent : ( NSString * ) content
{
[ self subclassResponsibility : _cmd ] ;
return Nil ;
}
2009-10-06 20:26:09 +02:00
- ( id ) createChildComponentWithRecord : ( NSDictionary * ) record
2008-06-13 22:16:30 +02:00
{
Class klazz ;
klazz = [ self objectClassForComponentName :
2009-10-06 20:26:09 +02:00
[ record objectForKey : @ "c_component" ] ] ;
2008-06-13 22:16:30 +02:00
return [ klazz objectWithRecord : record inContainer : self ] ;
}
2009-10-06 20:26:09 +02:00
- ( id ) createChildComponentWithName : ( NSString * ) newName
andContent : ( NSString * ) newContent
2008-06-13 22:16:30 +02:00
{
Class klazz ;
NSDictionary * record ;
unsigned int now ;
NSNumber * nowNumber ;
klazz = [ self objectClassForContent : newContent ] ;
now = [ [ NSCalendarDate calendarDate ] timeIntervalSince1970 ] ;
nowNumber = [ NSNumber numberWithUnsignedInt : now ] ;
record = [ NSDictionary dictionaryWithObjectsAndKeys : newName , @ "c_name" ,
newContent , @ "c_content" ,
nowNumber , @ "c_creationdate" ,
nowNumber , @ "c_lastmodified" , nil ] ;
return [ klazz objectWithRecord : record inContainer : self ] ;
}
- ( id ) lookupName : ( NSString * ) key
inContext : ( WOContext * ) localContext
acquire : ( BOOL ) acquire
{
id obj ;
NSDictionary * record ;
WORequest * request ;
2010-07-15 16:33:10 +02:00
obj = [ super lookupName : key inContext : localContext acquire : acquire ] ;
2008-06-13 22:16:30 +02:00
if ( ! obj )
{
record = [ childRecords objectForKey : key ] ;
if ( ! record )
{
record = [ self _recordForObjectName : key ] ;
if ( record )
[ childRecords setObject : record forKey : key ] ;
}
if ( record )
2009-10-06 20:26:09 +02:00
obj = [ self createChildComponentWithRecord : record ] ;
2008-06-13 22:16:30 +02:00
else
{
request = [ localContext request ] ;
if ( [ [ request method ] isEqualToString : @ "PUT" ] )
2008-07-14 18:47:10 +02:00
{
2009-10-06 20:26:09 +02:00
obj = [ self createChildComponentWithName : key
andContent : [ request contentAsString ] ] ;
2008-07-14 18:47:10 +02:00
[ obj setIsNew : YES ] ;
}
2008-06-13 22:16:30 +02:00
}
2009-09-17 01:47:36 +02:00
if ( obj )
[ [ SOGoCache sharedCache ]
registerObject : obj withName : key inContainer : self ] ;
2008-06-13 22:16:30 +02:00
}
return obj ;
2007-02-21 22:11:40 +01:00
}
2007-09-15 01:16:48 +02:00
- ( void ) deleteEntriesWithIds : ( NSArray * ) ids
{
unsigned int count , max ;
2014-02-04 22:25:52 +01:00
NSEnumerator * names ;
NSString * currentID , * currentName ;
2007-09-15 01:16:48 +02:00
SOGoContentObject * deleteObject ;
max = [ ids count ] ;
for ( count = 0 ; count < max ; count + + )
{
currentID = [ ids objectAtIndex : count ] ;
2014-02-04 22:25:52 +01:00
names = [ [ currentID componentsSeparatedByString : @ "/" ] objectEnumerator ] ;
2015-10-31 07:10:03 +01:00
deleteObject = ( SOGoContentObject * ) self ;
2014-02-04 22:25:52 +01:00
while ( ( currentName = [ names nextObject ] ) )
{
deleteObject = [ deleteObject lookupName : currentName
2008-06-13 22:16:30 +02:00
inContext : context
acquire : NO ] ;
2014-02-04 22:25:52 +01:00
}
2007-11-04 20:51:09 +01:00
if ( ! [ deleteObject isKindOfClass : [ NSException class ] ] )
2007-11-18 11:16:25 +01:00
{
if ( [ deleteObject respondsToSelector : @ selector ( prepareDelete ) ] )
[ deleteObject prepareDelete ] ;
[ deleteObject delete ] ;
}
2007-09-15 01:16:48 +02:00
}
}
2011-05-30 23:21:39 +02:00
- ( NSString * ) davCollectionTag
2009-06-08 19:16:09 +02:00
{
2011-05-30 23:21:39 +02:00
NSCalendarDate * lmDate ;
2009-06-08 19:16:09 +02:00
2011-05-30 23:21:39 +02:00
lmDate = [ [ self ocsFolder ] lastModificationDate ] ;
2009-06-08 19:16:09 +02:00
2011-05-30 23:21:39 +02:00
return [ NSString stringWithFormat : @ "%d" ,
2011-07-14 15:08:29 +02:00
( lmDate ? ( int ) [ lmDate timeIntervalSince1970 ]
2011-05-30 23:21:39 +02:00
: -1 ) ] ;
2009-06-08 19:16:09 +02:00
}
2009-08-27 23:14:54 +02:00
- ( BOOL ) userIsSubscriber : ( NSString * ) subscribingUser
{
SOGoUser * sogoUser ;
NSDictionary * moduleSettings ;
NSArray * folderSubscription ;
2010-10-08 21:53:04 +02:00
sogoUser = [ SOGoUser userWithLogin : subscribingUser ] ;
2009-08-27 23:14:54 +02:00
moduleSettings = [ [ sogoUser userSettings ]
objectForKey : [ container nameInContainer ] ] ;
folderSubscription = [ moduleSettings objectForKey : @ "SubscribedFolders" ] ;
return [ folderSubscription containsObject : [ self folderReference ] ] ;
}
2012-04-18 19:39:11 +02:00
- ( BOOL ) subscribeUserOrGroup : ( NSString * ) theIdentifier
reallyDo : ( BOOL ) reallyDo
2014-07-24 18:48:03 +02:00
response : ( WOResponse * ) theResponse
2007-12-05 00:28:52 +01:00
{
2012-11-06 14:05:23 +01:00
NSMutableDictionary * moduleSettings , * folderShowAlarms ;
2010-10-08 21:53:04 +02:00
NSMutableArray * folderSubscription ;
2019-12-04 10:37:08 +01:00
NSString * subscriptionPointer , * domain ;
2012-04-18 19:39:11 +02:00
NSMutableArray * allUsers ;
2009-11-29 05:19:32 +01:00
SOGoUserSettings * us ;
2020-07-01 22:58:16 +02:00
SOGoUser * sogoUser ;
2012-04-18 19:39:11 +02:00
NSDictionary * dict ;
2009-08-27 23:14:54 +02:00
BOOL rc ;
2012-04-18 19:39:11 +02:00
int i ;
2019-12-04 10:37:08 +01:00
domain = [ [ context activeUser ] domain ] ;
dict = [ [ SOGoUserManager sharedUserManager ] contactInfosForUserWithUIDorEmail : theIdentifier
inDomain : domain ] ;
2014-08-25 18:15:05 +02:00
2019-11-26 15:29:02 +01:00
if ( dict && [ [ dict objectForKey : @ "isGroup" ] boolValue ] )
2012-04-18 19:39:11 +02:00
{
2019-11-26 15:29:02 +01:00
id < SOGoSource > source ;
2012-04-18 19:39:11 +02:00
2019-11-26 15:29:02 +01:00
source = [ [ SOGoUserManager sharedUserManager ] sourceWithID : [ dict objectForKey : @ "SOGoSource" ] ] ;
2019-12-04 10:37:08 +01:00
if ( [ source conformsToProtocol : @ protocol ( SOGoMembershipSource ) ] )
2019-11-26 15:29:02 +01:00
{
2020-05-26 15:25:25 +02:00
NSArray * members ;
members = [ ( id < SOGoMembershipSource > ) ( source ) membersForGroupWithUID : [ dict objectForKey : @ "c_uid" ] ] ;
2020-07-01 22:58:16 +02:00
allUsers = [ NSMutableArray arrayWithArray : members ] ;
2012-04-18 19:39:11 +02:00
2019-11-26 15:29:02 +01:00
// We remove the active user from the group ( if present ) in order to
// not subscribe him to their own resource !
2020-07-01 22:58:16 +02:00
[ allUsers removeObject : [ context activeUser ] ] ;
2019-11-26 15:29:02 +01:00
}
2020-05-26 15:25:25 +02:00
else
{
2020-06-03 13:46:57 +02:00
[ self errorWithFormat : @ "Inconsistency (subscribeUserOrGroup:reallyDo:response:) error - got group identifier (%@) from a source (%@) that does not support groups (%@)." , theIdentifier , [ dict objectForKey : @ "SOGoSource" ] , NSStringFromClass ( [ source class ] ) ] ;
2020-05-26 15:25:25 +02:00
return NO ;
}
2012-04-18 19:39:11 +02:00
}
else
{
2020-07-01 22:58:16 +02:00
sogoUser = [ SOGoUser userWithLogin : theIdentifier roles : nil ] ;
if ( sogoUser )
allUsers = [ NSArray arrayWithObject : sogoUser ] ;
2012-04-18 19:39:11 +02:00
else
allUsers = [ NSArray array ] ;
}
2014-08-25 18:15:05 +02:00
2012-04-18 19:39:11 +02:00
rc = NO ;
2014-08-25 18:15:05 +02:00
2014-07-24 18:48:03 +02:00
// This is consumed by SOGo Integrator during folder subscription since v24 .0 .6
if ( theResponse )
2014-08-25 18:15:05 +02:00
[ theResponse appendContentString : [ self displayName ] ] ;
2007-12-05 00:28:52 +01:00
2012-04-18 19:39:11 +02:00
for ( i = 0 ; i < [ allUsers count ] ; i + + )
2007-12-05 00:28:52 +01:00
{
2020-07-01 22:58:16 +02:00
sogoUser = [ allUsers objectAtIndex : i ] ;
us = [ sogoUser userSettings ] ;
2009-11-29 05:19:32 +01:00
moduleSettings = [ us objectForKey : [ container nameInContainer ] ] ;
2009-03-23 20:04:31 +01:00
if ( ! ( moduleSettings
2009-07-01 16:03:58 +02:00
&& [ moduleSettings isKindOfClass : [ NSMutableDictionary class ] ] ) )
{
moduleSettings = [ NSMutableDictionary dictionary ] ;
2009-11-29 05:19:32 +01:00
[ us setObject : moduleSettings forKey : [ container nameInContainer ] ] ;
2009-07-01 16:03:58 +02:00
}
2009-03-23 20:04:31 +01:00
2014-08-25 18:15:05 +02:00
folderSubscription = [ moduleSettings objectForKey : @ "SubscribedFolders" ] ;
2008-04-22 01:03:48 +02:00
subscriptionPointer = [ self folderReference ] ;
2017-05-30 15:26:30 +02:00
// We used to set "show alarms" for any type of folder , so we remove it
// here and let the subclass handle it ( SOGoAppointmentFolder ) .
2012-11-06 14:05:23 +01:00
folderShowAlarms = [ moduleSettings objectForKey : @ "FolderShowAlarms" ] ;
2017-05-30 15:26:30 +02:00
if ( folderShowAlarms )
[ folderShowAlarms removeObjectForKey : subscriptionPointer ] ;
2010-10-08 21:53:04 +02:00
2007-12-05 00:28:52 +01:00
if ( reallyDo )
2010-10-08 21:53:04 +02:00
{
if ( ! ( folderSubscription
&& [ folderSubscription isKindOfClass : [ NSMutableArray class ] ] ) )
{
folderSubscription = [ NSMutableArray array ] ;
[ moduleSettings setObject : folderSubscription
forKey : @ "SubscribedFolders" ] ;
}
2014-10-09 21:10:20 +02:00
[ self setFolderPropertyValue : [ self _displayNameFromSubscriber ]
2014-07-24 18:48:03 +02:00
inCategory : @ "FolderDisplayNames"
settings : us ] ;
2010-10-08 21:53:04 +02:00
[ folderSubscription addObjectUniquely : subscriptionPointer ] ;
}
2007-12-05 00:28:52 +01:00
else
2009-07-01 16:03:58 +02:00
{
2010-10-08 21:53:04 +02:00
[ self removeFolderSettings : moduleSettings
withReference : subscriptionPointer ] ;
2009-07-01 16:03:58 +02:00
[ folderSubscription removeObject : subscriptionPointer ] ;
2012-04-18 19:39:11 +02:00
}
2007-12-05 00:28:52 +01:00
2009-11-29 05:19:32 +01:00
[ us synchronize ] ;
2010-10-08 21:53:04 +02:00
2009-08-27 23:14:54 +02:00
rc = YES ;
2007-12-05 00:28:52 +01:00
}
2009-08-27 23:14:54 +02:00
return rc ;
}
2010-10-08 21:53:04 +02:00
- ( void ) removeFolderSettings : ( NSMutableDictionary * ) moduleSettings
withReference : ( NSString * ) reference
{
NSMutableDictionary * refDict ;
refDict = [ moduleSettings objectForKey : @ "FolderDisplayNames" ] ;
[ refDict removeObjectForKey : reference ] ;
}
2009-08-27 23:14:54 +02:00
- ( NSArray * ) _parseDAVDelegatedUsers
{
id < DOMDocument > document ;
id < DOMNamedNodeMap > attrs ;
id o ;
document = [ [ context request ] contentAsDOMDocument ] ;
attrs = [ [ document documentElement ] attributes ] ;
o = [ attrs namedItem : @ "users" ] ;
if ( o ) return [ [ o nodeValue ] componentsSeparatedByString : @ "," ] ;
return nil ;
2008-02-25 22:59:25 +01:00
}
2009-08-27 23:14:54 +02:00
- ( WOResponse * ) _davSubscribe : ( BOOL ) reallyDo
2008-02-25 22:59:25 +01:00
{
WOResponse * response ;
2008-11-18 01:06:37 +01:00
SOGoUser * currentUser ;
2009-08-27 23:14:54 +02:00
NSArray * delegatedUsers ;
NSString * userLogin ;
int count , max ;
2008-02-25 22:59:25 +01:00
2009-08-27 23:14:54 +02:00
response = [ context response ] ;
2009-01-21 17:20:11 +01:00
[ response setHeader : @ "text/plain; charset=utf-8"
2009-07-01 16:03:58 +02:00
forKey : @ "Content-Type" ] ;
2014-07-24 18:48:03 +02:00
[ response setStatus : 200 ] ;
2009-01-21 17:20:11 +01:00
2009-08-27 23:14:54 +02:00
currentUser = [ context activeUser ] ;
delegatedUsers = [ self _parseDAVDelegatedUsers ] ;
2008-02-25 22:59:25 +01:00
2009-08-27 23:14:54 +02:00
max = [ delegatedUsers count ] ;
if ( max )
2008-02-25 22:59:25 +01:00
{
2009-08-27 23:14:54 +02:00
if ( [ currentUser isSuperUser ] )
2009-07-01 16:03:58 +02:00
{
2009-08-27 23:14:54 +02:00
/ * We trust the passed user ID here as it might generate tons or
LDAP call but more importantly , cache propagation calls that will
create contention on GDNC . * /
for ( count = 0 ; count < max ; count + + )
2012-04-18 19:39:11 +02:00
[ self subscribeUserOrGroup : [ delegatedUsers objectAtIndex : count ]
2014-07-24 18:48:03 +02:00
reallyDo : reallyDo
response : response ] ;
2009-07-01 16:03:58 +02:00
}
2008-11-18 01:06:37 +01:00
else
2009-07-01 16:03:58 +02:00
{
2009-08-27 23:14:54 +02:00
[ response setStatus : 403 ] ;
[ response appendContentString : @ "You cannot subscribe another user"
@ " to any folder unless you are a super-user." ] ;
2009-07-01 16:03:58 +02:00
}
2008-11-18 01:06:37 +01:00
}
2008-02-25 22:59:25 +01:00
else
{
2009-08-27 23:14:54 +02:00
userLogin = [ currentUser login ] ;
if ( [ owner isEqualToString : userLogin ] )
{
[ response setStatus : 403 ] ;
[ response appendContentString :
@ "You cannot (un)subscribe to a folder that you own!" ] ;
}
else
2014-07-24 18:48:03 +02:00
[ self subscribeUserOrGroup : userLogin
reallyDo : reallyDo
response : response ] ;
2008-02-25 22:59:25 +01:00
}
2007-12-05 00:28:52 +01:00
return response ;
}
2008-02-25 22:59:25 +01:00
- ( id < WOActionResults > ) davSubscribe : ( WOContext * ) queryContext
2007-12-05 00:28:52 +01:00
{
2009-08-27 23:14:54 +02:00
return [ self _davSubscribe : YES ] ;
2007-12-05 00:28:52 +01:00
}
2008-02-25 22:59:25 +01:00
- ( id < WOActionResults > ) davUnsubscribe : ( WOContext * ) queryContext
2007-12-05 00:28:52 +01:00
{
2009-08-27 23:14:54 +02:00
return [ self _davSubscribe : NO ] ;
2007-12-05 00:28:52 +01:00
}
2009-06-18 22:58:46 +02:00
- ( NSDictionary * ) davSQLFieldsTable
{
static NSMutableDictionary * davSQLFieldsTable = nil ;
if ( ! davSQLFieldsTable )
{
davSQLFieldsTable = [ NSMutableDictionary new ] ;
[ davSQLFieldsTable setObject : @ "c_version" forKey : @ "{DAV:}getetag" ] ;
2020-10-07 14:01:00 +02:00
[ davSQLFieldsTable setObject : @ "c_version" forKey : @ "{http://calendarserver.org/ns/}getetag" ] ;
2009-06-24 01:41:25 +02:00
[ davSQLFieldsTable setObject : @ "" forKey : @ "{DAV:}getcontenttype" ] ;
2009-07-14 16:36:24 +02:00
[ davSQLFieldsTable setObject : @ "" forKey : @ "{DAV:}resourcetype" ] ;
2009-06-18 22:58:46 +02:00
}
return davSQLFieldsTable ;
}
- ( NSDictionary * ) _davSQLFieldsForProperties : ( NSArray * ) properties
{
NSMutableDictionary * davSQLFields ;
NSDictionary * davSQLFieldsTable ;
NSString * sqlField , * property ;
unsigned int count , max ;
davSQLFieldsTable = [ self davSQLFieldsTable ] ;
max = [ properties count ] ;
davSQLFields = [ NSMutableDictionary dictionaryWithCapacity : max ] ;
for ( count = 0 ; count < max ; count + + )
{
property = [ properties objectAtIndex : count ] ;
sqlField = [ davSQLFieldsTable objectForKey : property ] ;
if ( sqlField )
[ davSQLFields setObject : sqlField forKey : property ] ;
else
[ self errorWithFormat : @ "DAV property '%@' has no matching SQL field,"
2009-07-01 16:03:58 +02:00
@ " response could be incomplete" , property ] ;
2009-06-18 22:58:46 +02:00
}
return davSQLFields ;
}
2012-10-22 16:09:13 +02:00
- ( NSDictionary * ) parseDAVRequestedProperties : ( id < DOMElement > ) propElement
2009-06-18 22:58:46 +02:00
{
NSArray * properties ;
NSDictionary * sqlFieldsTable ;
2012-10-22 16:09:13 +02:00
properties = [ ( NGDOMNodeWithChildren * ) propElement flatPropertyNameOfSubElements ] ;
2009-06-18 22:58:46 +02:00
sqlFieldsTable = [ self _davSQLFieldsForProperties : properties ] ;
return sqlFieldsTable ;
}
2009-06-19 22:14:19 +02:00
/ * make this a public method ? * /
- ( NSArray * ) _fetchFields : ( NSArray * ) fields
withQualifier : ( EOQualifier * ) qualifier
ignoreDeleted : ( BOOL ) ignoreDeleted
{
GCSFolder * folder ;
EOFetchSpecification * fetchSpec ;
folder = [ self ocsFolder ] ;
if ( qualifier )
fetchSpec = [ EOFetchSpecification
2009-07-01 16:03:58 +02:00
fetchSpecificationWithEntityName : [ folder folderName ]
qualifier : qualifier
sortOrderings : nil ] ;
2009-06-19 22:14:19 +02:00
else
fetchSpec = nil ;
return [ folder fetchFields : fields fetchSpecification : fetchSpec
ignoreDeleted : ignoreDeleted ] ;
}
2009-07-07 22:56:09 +02:00
- ( NSString * ) additionalWebdavSyncFilters
{
return @ "" ;
}
2014-01-10 20:09:02 +01:00
//
// Method used to get all changes since a particular sync token
//
// It ' ll return standard properties ( c_name , c_creationdate , etc . . . )
// of new , modified and deleted components .
//
- ( NSArray * ) syncTokenFieldsWithProperties : ( NSDictionary * ) properties
matchingSyncToken : ( NSString * ) syncToken
2014-01-20 16:13:16 +01:00
fromDate : ( NSCalendarDate * ) theStartDate
2015-09-09 16:20:31 +02:00
initialLoad : ( BOOL ) initialLoadInProgress
2009-06-19 16:49:47 +02:00
{
/ * TODO :
- validation :
- synctoken and return "DAV:valid-sync-token" as error if needed
- properties
- database errors * /
2009-06-19 22:14:19 +02:00
NSMutableArray * fields , * mRecords ;
NSArray * records ;
2009-06-19 16:49:47 +02:00
EOQualifier * qualifier ;
2009-06-24 01:41:25 +02:00
NSEnumerator * addFields ;
2009-07-07 22:56:09 +02:00
NSString * currentField , * filter ;
2009-08-05 17:36:09 +02:00
int syncTokenInt ;
2009-06-19 16:49:47 +02:00
fields = [ NSMutableArray arrayWithObjects : @ "c_name" , @ "c_component" ,
2014-12-22 18:39:58 +01:00
@ "c_creationdate" , @ "c_lastmodified" , nil ] ;
if ( [ [ self folderType ] isEqualToString : @ "Appointment" ] )
{
[ fields addObject : @ "c_enddate" ] ;
[ fields addObject : @ "c_cycleenddate" ] ;
}
2009-06-24 01:41:25 +02:00
addFields = [ [ properties allValues ] objectEnumerator ] ;
while ( ( currentField = [ addFields nextObject ] ) )
if ( [ currentField length ] )
[ fields addObjectUniquely : currentField ] ;
2009-06-19 16:49:47 +02:00
2009-08-05 17:36:09 +02:00
if ( [ syncToken length ] )
2009-06-19 22:14:19 +02:00
{
2009-08-05 17:36:09 +02:00
syncTokenInt = [ syncToken intValue ] ;
2014-01-20 16:13:16 +01:00
2009-06-19 22:14:19 +02:00
qualifier = [ EOQualifier qualifierWithQualifierFormat :
2009-08-05 17:36:09 +02:00
@ "c_lastmodified > %d" , syncTokenInt ] ;
2014-01-20 16:13:16 +01:00
if ( theStartDate )
{
EOQualifier * sinceDateQualifier = [ EOQualifier qualifierWithQualifierFormat :
2014-12-22 18:39:58 +01:00
@ "(c_enddate > %d OR c_enddate = NULL) OR (c_iscycle = 1 and (c_cycleenddate > %d OR c_cycleenddate = NULL))" ,
( int ) [ theStartDate timeIntervalSince1970 ] ,
( int ) [ theStartDate timeIntervalSince1970 ] ] ;
2014-01-20 16:13:16 +01:00
qualifier = [ [ EOAndQualifier alloc ] initWithQualifiers : sinceDateQualifier , qualifier ,
nil ] ;
[ qualifier autorelease ] ;
}
2009-06-19 22:14:19 +02:00
mRecords = [ NSMutableArray arrayWithArray : [ self _fetchFields : fields
2009-08-05 17:36:09 +02:00
withQualifier : qualifier
ignoreDeleted : YES ] ] ;
2015-09-11 01:10:50 +02:00
if ( ! initialLoadInProgress )
2015-09-09 16:20:31 +02:00
{
qualifier = [ EOQualifier qualifierWithQualifierFormat :
@ "c_lastmodified > %d and c_deleted == 1" ,
syncTokenInt ] ;
fields = [ NSMutableArray arrayWithObjects : @ "c_name" , @ "c_lastmodified" , @ "c_deleted" , nil ] ;
[ mRecords addObjectsFromArray : [ self _fetchFields : fields
withQualifier : qualifier
ignoreDeleted : NO ] ] ;
}
2009-06-19 22:14:19 +02:00
records = mRecords ;
}
2009-06-19 16:49:47 +02:00
else
2009-07-07 22:56:09 +02:00
{
filter = [ self additionalWebdavSyncFilters ] ;
if ( [ filter length ] )
qualifier = [ EOQualifier qualifierWithQualifierFormat : filter ] ;
else
qualifier = nil ;
2014-01-20 16:13:16 +01:00
if ( theStartDate )
{
EOQualifier * sinceDateQualifier = [ EOQualifier qualifierWithQualifierFormat :
2014-12-22 18:39:58 +01:00
@ "(c_enddate > %d OR c_enddate = NULL) OR (c_iscycle = 1 and (c_cycleenddate > %d OR c_cycleenddate = NULL))" ,
( int ) [ theStartDate timeIntervalSince1970 ] ,
( int ) [ theStartDate timeIntervalSince1970 ] ] ;
2014-01-20 16:13:16 +01:00
qualifier = [ [ EOAndQualifier alloc ] initWithQualifiers : sinceDateQualifier , qualifier ,
nil ] ;
[ qualifier autorelease ] ;
}
records = [ self _fetchFields : fields
withQualifier : qualifier
2009-07-07 22:56:09 +02:00
ignoreDeleted : YES ] ;
}
2009-06-19 16:49:47 +02:00
2014-01-20 16:13:16 +01:00
2009-06-19 22:14:19 +02:00
return records ;
2009-06-19 16:49:47 +02:00
}
2009-06-24 01:41:25 +02:00
- ( NSArray * ) _davPropstatsWithProperties : ( NSArray * ) davProperties
2009-06-19 16:49:47 +02:00
andMethodSelectors : ( SEL * ) selectors
fromRecord : ( NSDictionary * ) record
{
SOGoContentObject * sogoObject ;
unsigned int count , max ;
NSMutableArray * properties200 , * properties404 , * propstats ;
NSDictionary * propContent ;
id result ;
propstats = [ NSMutableArray arrayWithCapacity : 2 ] ;
max = [ davProperties count ] ;
properties200 = [ NSMutableArray arrayWithCapacity : max ] ;
properties404 = [ NSMutableArray arrayWithCapacity : max ] ;
2009-10-06 20:26:09 +02:00
sogoObject = [ self createChildComponentWithRecord : record ] ;
2009-06-19 16:49:47 +02:00
for ( count = 0 ; count < max ; count + + )
{
if ( selectors [ count ]
&& [ sogoObject respondsToSelector : selectors [ count ] ] )
2009-10-06 20:26:09 +02:00
result = [ sogoObject performSelector : selectors [ count ] ] ;
2009-06-19 16:49:47 +02:00
else
result = nil ;
if ( result )
{
propContent = [ [ davProperties objectAtIndex : count ]
2009-07-01 16:03:58 +02:00
asWebDAVTupleWithContent : result ] ;
2009-06-19 16:49:47 +02:00
[ properties200 addObject : propContent ] ;
}
else
{
propContent = [ [ davProperties objectAtIndex : count ]
2009-10-06 20:26:09 +02:00
asWebDAVTuple ] ;
2009-06-19 16:49:47 +02:00
[ properties404 addObject : propContent ] ;
}
}
if ( [ properties200 count ] )
2009-10-06 20:26:09 +02:00
[ propstats addObject : [ properties200
asDAVPropstatWithStatus : @ "HTTP/1.1 200 OK" ] ] ;
2009-06-19 16:49:47 +02:00
if ( [ properties404 count ] )
2009-10-06 20:26:09 +02:00
[ propstats addObject : [ properties404
asDAVPropstatWithStatus : @ "HTTP/1.1 404 Not Found" ] ] ;
2009-06-19 16:49:47 +02:00
return propstats ;
}
2013-09-24 15:29:46 +02:00
/ *
draft -1 :
< ? xml version = "1.0" encoding = "utf-8" ? >
< D : multistatus xmlns : D = "DAV:" >
< D : sync - response >
< D : href > / SOGo / dav / sogo2 / Calendar / personal / 351 dc1af -2 aa3 -4 d14 -9704 - eadbcfecaf7e . ics < / D : href >
< D : status > HTTP / 1.1 200 OK < / D : status >
< D : propstat >
< D : prop >
< D : getetag > & quot ; gcs00000001 & quot ; < / D : getetag > < / D : prop >
< D : status > HTTP / 1.1 200 OK < / D : status >
< / D : propstat >
< / D : sync - response >
< D : sync - token > 1322100412 < / D : sync - token >
< / D : multistatus >
draft -2 and up :
< ? xml version = "1.0" encoding = "utf-8" ? >
< multistatus xmlns = "DAV:" >
< response >
< href > / caldav . php / user1 / home / DAYPARTY -77 C6 -4 FB7 - BDD3 -6882 E2F1BE74 . ics < / href >
< propstat >
< prop >
< getetag > "165746adbab8bc0c8336a63cc5332ff2" < / getetag >
< getlastmodified > Dow , 01 Jan 2000 00 : 00 : 00 GMT < / getlastmodified >
< / prop >
< status > HTTP / 1.1 200 OK < / status >
< / propstat >
< / response >
< sync - token > urn : , 1322100412 < / sync - token >
< / multistatus >
* /
2009-06-19 16:49:47 +02:00
- ( NSDictionary * ) _syncResponseWithProperties : ( NSArray * ) properties
andMethodSelectors : ( SEL * ) selectors
fromRecord : ( NSDictionary * ) record
withToken : ( int ) syncToken
andBaseURL : ( NSString * ) baseURL
{
static NSString * status [ ] = { @ "HTTP/1.1 404 Not Found" ,
2009-10-06 20:26:09 +02:00
@ "HTTP/1.1 201 Created" ,
@ "HTTP/1.1 200 OK" } ;
2009-06-19 16:49:47 +02:00
NSMutableArray * children ;
NSString * href ;
unsigned int statusIndex ;
children = [ NSMutableArray arrayWithCapacity : 3 ] ;
href = [ NSString stringWithFormat : @ "%@%@" ,
2009-10-06 20:26:09 +02:00
baseURL , [ record objectForKey : @ "c_name" ] ] ;
2009-06-19 16:49:47 +02:00
[ children addObject : davElementWithContent ( @ "href" , XMLNS_WEBDAV ,
href ) ] ;
if ( syncToken )
{
if ( [ [ record objectForKey : @ "c_deleted" ] intValue ] > 0 )
statusIndex = 0 ;
else
{
if ( [ [ record objectForKey : @ "c_creationdate" ] intValue ]
>= syncToken )
statusIndex = 1 ;
else
statusIndex = 2 ;
}
}
else
statusIndex = 1 ;
2009-07-01 16:03:58 +02:00
// NSLog ( @ "webdav sync: %@ (%@)" , href , status [ statusIndex ] ) ;
2009-06-19 16:49:47 +02:00
[ children addObject : davElementWithContent ( @ "status" , XMLNS_WEBDAV ,
status [ statusIndex ] ) ] ;
if ( statusIndex )
[ children
2009-06-24 01:41:25 +02:00
addObjectsFromArray : [ self _davPropstatsWithProperties : properties
2009-10-06 20:26:09 +02:00
andMethodSelectors : selectors
fromRecord : record ] ] ;
2009-06-19 16:49:47 +02:00
2013-09-24 15:29:46 +02:00
return davElementWithContent ( @ "response" , XMLNS_WEBDAV , children ) ;
2009-06-19 16:49:47 +02:00
}
- ( void ) _appendComponentProperties : ( NSArray * ) properties
fromRecords : ( NSArray * ) records
matchingSyncToken : ( int ) syncToken
toResponse : ( WOResponse * ) response
{
NSMutableArray * syncResponses ;
NSDictionary * multistatus , * record ;
unsigned int count , max , now ;
int newToken , currentLM ;
NSString * baseURL , * newTokenStr ;
SEL * selectors ;
max = [ properties count ] ;
2010-06-23 16:47:20 +02:00
selectors = NSZoneMalloc ( NULL , max * sizeof ( SEL ) ) ;
2009-06-19 16:49:47 +02:00
for ( count = 0 ; count < max ; count + + )
selectors [ count ]
= SOGoSelectorForPropertyGetter ( [ properties objectAtIndex : count ] ) ;
now = ( unsigned int ) [ [ NSDate date ] timeIntervalSince1970 ] ;
newToken = 0 ;
2009-10-21 23:17:11 +02:00
baseURL = [ self davURLAsString ] ;
2009-12-22 21:33:47 +01:00
# warning review this when fixing http : // www . scalableogo . org / bugs / view . php ? id = 276
if ( ! [ baseURL hasSuffix : @ "/" ] )
baseURL = [ NSString stringWithFormat : @ "%@/" , baseURL ] ;
2009-06-19 16:49:47 +02:00
max = [ records count ] ;
syncResponses = [ NSMutableArray arrayWithCapacity : max + 1 ] ;
for ( count = 0 ; count < max ; count + + )
{
record = [ records objectAtIndex : count ] ;
currentLM = [ [ record objectForKey : @ "c_lastmodified" ] intValue ] ;
if ( newToken < currentLM )
newToken = currentLM ;
[ syncResponses addObject : [ self _syncResponseWithProperties : properties
2009-08-05 17:36:09 +02:00
andMethodSelectors : selectors
fromRecord : record
withToken : syncToken
andBaseURL : baseURL ] ] ;
2009-06-19 16:49:47 +02:00
}
NSZoneFree ( NULL , selectors ) ;
2014-05-02 19:35:21 +02:00
/ * If we haven ' t gotten any result to return , let ' s use the previously
supplied sync - token * /
if ( max = = 0 )
newToken = syncToken ;
2009-06-19 16:49:47 +02:00
/ * If the most recent c_lastmodified is "now" , we need to return "now - 1"
in order to make sure during the next sync that every records that might
get added at the same moment are not lost . * /
2014-05-02 19:35:21 +02:00
else if ( ! newToken || newToken = = now )
2009-06-19 16:49:47 +02:00
newToken = now - 1 ;
newTokenStr = [ NSString stringWithFormat : @ "%d" , newToken ] ;
[ syncResponses addObject : davElementWithContent ( @ "sync-token" ,
XMLNS_WEBDAV ,
newTokenStr ) ] ;
multistatus = davElementWithContent ( @ "multistatus" , XMLNS_WEBDAV ,
syncResponses ) ;
[ response
appendContentString : [ multistatus asWebDavStringWithNamespaces : nil ] ] ;
}
2010-06-23 16:47:20 +02:00
- ( BOOL ) _isValidSyncToken : ( NSString * ) syncToken
{
unichar * characters ;
int count , max , value ;
BOOL valid ;
2011-05-30 23:21:39 +02:00
NSCalendarDate * lmDate ;
2010-06-23 16:47:20 +02:00
max = [ syncToken length ] ;
if ( max > 0 )
{
characters = NSZoneMalloc ( NULL , max * sizeof ( unichar ) ) ;
[ syncToken getCharacters : characters ] ;
if ( max = = 2
&& characters [ 0 ] = = ' - '
&& characters [ 1 ] = = ' 1 ' )
valid = YES ;
else
{
2011-05-30 23:21:39 +02:00
lmDate = [ [ self ocsFolder ] lastModificationDate ] ;
2010-06-23 16:47:20 +02:00
valid = YES ;
value = 0 ;
for ( count = 0 ; valid && count < max ; count + + )
{
if ( characters [ count ] < ' 0 '
|| characters [ count ] > ' 9 ' )
valid = NO ;
else
value = value * 10 + characters [ count ] - ' 0 ' ;
}
2011-05-30 23:21:39 +02:00
valid | = ( value <= ( int ) [ lmDate timeIntervalSince1970 ] ) ;
2010-06-23 16:47:20 +02:00
}
NSZoneFree ( NULL , characters ) ;
}
else
valid = YES ;
return valid ;
}
2009-06-19 16:49:47 +02:00
- ( WOResponse * ) davSyncCollection : ( WOContext * ) localContext
{
WOResponse * r ;
id < DOMDocument > document ;
2012-10-22 16:09:13 +02:00
id < DOMElement > documentElement , propElement ;
2009-06-19 16:49:47 +02:00
NSString * syncToken ;
NSDictionary * properties ;
NSArray * records ;
r = [ context response ] ;
2010-01-15 00:19:19 +01:00
[ r prepareDAVResponse ] ;
2009-06-19 16:49:47 +02:00
document = [ [ context request ] contentAsDOMDocument ] ;
2012-10-22 16:09:13 +02:00
documentElement = [ document documentElement ] ;
syncToken = [ ( NGDOMNode * )
[ ( NGDOMNodeWithChildren * )
documentElement firstElementWithTag : @ "sync-token"
inNamespace : XMLNS_WEBDAV ]
textValue ] ;
2010-06-23 16:47:20 +02:00
if ( [ self _isValidSyncToken : syncToken ] )
{
2012-10-22 16:09:13 +02:00
propElement = [ ( NGDOMNodeWithChildren * ) documentElement
firstElementWithTag : @ "prop" inNamespace : XMLNS_WEBDAV ] ;
2010-06-23 16:47:20 +02:00
properties = [ self parseDAVRequestedProperties : propElement ] ;
2014-01-10 20:09:02 +01:00
records = [ self syncTokenFieldsWithProperties : properties
2014-01-20 16:13:16 +01:00
matchingSyncToken : syncToken
2015-09-09 16:20:31 +02:00
fromDate : nil
initialLoad : NO ] ;
2010-06-23 16:47:20 +02:00
[ self _appendComponentProperties : [ properties allKeys ]
fromRecords : records
matchingSyncToken : [ syncToken intValue ]
toResponse : r ] ;
}
2009-08-05 17:36:09 +02:00
else
[ r appendDAVError : davElement ( @ "valid-sync-token" , XMLNS_WEBDAV ) ] ;
2009-06-19 16:49:47 +02:00
return r ;
}
2009-06-04 02:40:21 +02:00
/ * handling acls from quick tables * /
- ( void ) initializeQuickTablesAclsInContext : ( WOContext * ) localContext
{
NSString * login ;
2010-07-15 01:11:37 +02:00
SOGoUser * activeUser ;
2009-06-04 02:40:21 +02:00
2010-07-15 01:11:37 +02:00
activeUser = [ localContext activeUser ] ;
2009-06-04 02:40:21 +02:00
if ( activeUserIsOwner )
userCanAccessAllObjects = activeUserIsOwner ;
else
{
2010-07-15 01:11:37 +02:00
login = [ activeUser login ] ;
2009-06-04 02:40:21 +02:00
/ * we only grant "userCanAccessAllObjects" for role "ObjectEraser" and
not "ObjectCreator" because the latter doesn ' t imply we can read
properties from subobjects or even know their existence . * /
2009-08-18 19:36:20 +02:00
userCanAccessAllObjects
2010-07-15 01:11:37 +02:00
= ( [ [ self ownerInContext : localContext ] isEqualToString : login ]
|| ( [ activeUser respondsToSelector : @ selector ( isSuperUser ) ]
&& [ activeUser isSuperUser ] ) ) ;
2009-06-04 02:40:21 +02:00
}
}
2007-04-17 16:30:12 +02:00
/ * acls as a container * /
2007-05-19 02:49:05 +02:00
- ( NSArray * ) aclUsersForObjectAtPath : ( NSArray * ) objectPathArray ;
2007-04-17 16:30:12 +02:00
{
EOQualifier * qualifier ;
NSString * qs ;
2008-02-22 22:25:34 +01:00
NSArray * records , * uids ;
2007-04-17 16:30:12 +02:00
qs = [ NSString stringWithFormat : @ "c_object = '/%@'" ,
2009-07-01 16:03:58 +02:00
[ objectPathArray componentsJoinedByString : @ "/" ] ] ;
2007-04-17 16:30:12 +02:00
qualifier = [ EOQualifier qualifierWithQualifierFormat : qs ] ;
2007-05-19 02:49:05 +02:00
records = [ [ self ocsFolder ] fetchAclMatchingQualifier : qualifier ] ;
2008-02-22 22:25:34 +01:00
uids = [ [ records valueForKey : @ "c_uid" ] uniqueObjects ] ;
2007-04-17 16:30:12 +02:00
2008-02-22 22:25:34 +01:00
return uids ;
2007-04-17 16:30:12 +02:00
}
2009-09-29 20:17:12 +02:00
- ( NSArray * ) _aclsFromUserRoles : ( NSArray * ) records
matchingUID : ( NSString * ) uid
2007-04-17 16:30:12 +02:00
{
2009-09-29 20:17:12 +02:00
int count , max ;
NSDictionary * record ;
2007-04-26 03:16:19 +02:00
NSMutableArray * acls ;
2009-09-29 20:17:12 +02:00
NSString * currentUID ;
2007-04-17 16:30:12 +02:00
2007-04-26 03:16:19 +02:00
acls = [ NSMutableArray array ] ;
2009-09-29 20:17:12 +02:00
max = [ records count ] ;
for ( count = 0 ; count < max ; count + + )
{
record = [ records objectAtIndex : count ] ;
currentUID = [ record valueForKey : @ "c_uid" ] ;
if ( [ currentUID isEqualToString : uid ] )
[ acls addObject : [ record valueForKey : @ "c_role" ] ] ;
}
return acls ;
}
- ( NSArray * ) _aclsFromGroupRoles : ( NSArray * ) records
matchingUID : ( NSString * ) uid
{
int count , max ;
2020-05-26 15:25:25 +02:00
NSDictionary * record , * dict ;
2019-12-04 10:37:08 +01:00
NSString * currentUID , * domain ;
2009-09-29 20:17:12 +02:00
NSMutableArray * acls ;
2009-05-03 19:50:57 +02:00
2009-09-29 20:17:12 +02:00
acls = [ NSMutableArray array ] ;
2009-09-10 22:01:24 +02:00
2009-09-29 20:17:12 +02:00
max = [ records count ] ;
for ( count = 0 ; count < max ; count + + )
2009-09-10 22:01:24 +02:00
{
2009-09-29 20:17:12 +02:00
record = [ records objectAtIndex : count ] ;
currentUID = [ record valueForKey : @ "c_uid" ] ;
if ( [ currentUID hasPrefix : @ "@" ] )
2009-07-01 16:03:58 +02:00
{
2019-12-04 10:37:08 +01:00
domain = [ [ context activeUser ] domain ] ;
2020-05-26 15:25:25 +02:00
dict = [ [ SOGoUserManager sharedUserManager ] contactInfosForUserWithUIDorEmail : currentUID
inDomain : domain ] ;
2019-11-26 15:29:02 +01:00
if ( dict )
{
2020-06-03 13:46:57 +02:00
id < SOGoSource > source ;
source = [ [ SOGoUserManager sharedUserManager ] sourceWithID : [ dict objectForKey : @ "SOGoSource" ] ] ;
if ( [ source conformsToProtocol : @ protocol ( SOGoMembershipSource ) ] )
2020-05-26 15:25:25 +02:00
{
2020-06-03 13:46:57 +02:00
if ( [ ( id < SOGoMembershipSource > ) ( source ) groupWithUIDHasMemberWithUID : currentUID memberUid : uid ] )
[ acls addObject : [ record valueForKey : @ "c_role" ] ] ;
2020-05-26 15:25:25 +02:00
}
else
{
2020-06-03 13:46:57 +02:00
[ self errorWithFormat : @ "Inconsistency (_aclsFromGroupRoles:matchingUID:) error - got group identifier (%@) from a source (%@) that does not support groups (%@)." , currentUID , [ dict objectForKey : @ "SOGoSource" ] , NSStringFromClass ( [ source class ] ) ] ;
2020-05-26 15:25:25 +02:00
return [ NSArray array ] ;
}
2019-11-26 15:29:02 +01:00
}
2009-07-01 16:03:58 +02:00
}
2009-05-03 19:50:57 +02:00
}
2009-07-01 16:03:58 +02:00
2009-09-29 20:17:12 +02:00
return acls ;
}
- ( NSArray * ) _fetchAclsForUser : ( NSString * ) uid
forObjectAtPath : ( NSString * ) objectPath
{
EOQualifier * qualifier ;
NSArray * records , * acls ;
NSString * qs ;
// We look for the exact uid or any uid that begins with "@" ( corresponding to groups )
qs = [ NSString stringWithFormat : @ "(c_object = '/%@') AND (c_uid = '%@' OR c_uid LIKE '@%%')" ,
objectPath , uid ] ;
qualifier = [ EOQualifier qualifierWithQualifierFormat : qs ] ;
records = [ [ self ocsFolder ] fetchAclMatchingQualifier : qualifier ] ;
acls = [ self _aclsFromUserRoles : records matchingUID : uid ] ;
if ( ! [ acls count ] )
acls = [ self _aclsFromGroupRoles : records matchingUID : uid ] ;
2008-02-22 22:25:34 +01:00
return [ acls uniqueObjects ] ;
2007-04-17 16:30:12 +02:00
}
2007-04-27 21:45:12 +02:00
- ( void ) _cacheRoles : ( NSArray * ) roles
2009-07-01 16:03:58 +02:00
forUser : ( NSString * ) uid
2007-04-27 21:45:12 +02:00
forObjectAtPath : ( NSString * ) objectPath
{
NSMutableDictionary * aclsForObject ;
2010-10-15 20:30:08 +02:00
aclsForObject = [ [ SOGoCache sharedCache ] aclsForPath : objectPath ] ;
2007-04-27 21:45:12 +02:00
if ( ! aclsForObject )
{
aclsForObject = [ NSMutableDictionary dictionary ] ;
}
if ( roles )
2010-10-15 20:30:08 +02:00
{
[ aclsForObject setObject : roles forKey : uid ] ;
}
2007-04-27 21:45:12 +02:00
else
2010-10-15 20:30:08 +02:00
{
[ aclsForObject removeObjectForKey : uid ] ;
}
// We update our distributed cache
[ [ SOGoCache sharedCache ] setACLs : aclsForObject
forPath : objectPath ] ;
2007-04-27 21:45:12 +02:00
}
2010-06-02 18:39:33 +02:00
- ( NSArray * ) _realAclsForUser : ( NSString * ) uid
forObjectAtPath : ( NSArray * ) objectPathArray
2007-04-27 21:45:12 +02:00
{
NSArray * acls ;
2010-06-02 18:39:33 +02:00
NSString * objectPath ;
2007-04-27 21:45:12 +02:00
NSDictionary * aclsForObject ;
objectPath = [ objectPathArray componentsJoinedByString : @ "/" ] ;
2010-10-15 20:30:08 +02:00
aclsForObject = [ [ SOGoCache sharedCache ] aclsForPath : objectPath ] ;
2007-04-27 21:45:12 +02:00
if ( aclsForObject )
acls = [ aclsForObject objectForKey : uid ] ;
else
acls = nil ;
if ( ! acls )
{
acls = [ self _fetchAclsForUser : uid forObjectAtPath : objectPath ] ;
2010-09-17 22:37:20 +02:00
if ( ! acls )
2009-07-01 16:03:58 +02:00
acls = [ NSArray array ] ;
2007-04-27 21:45:12 +02:00
[ self _cacheRoles : acls forUser : uid forObjectAtPath : objectPath ] ;
}
2010-06-02 18:39:33 +02:00
return acls ;
}
- ( NSArray * ) aclsForUser : ( NSString * ) uid
forObjectAtPath : ( NSArray * ) objectPathArray
{
NSArray * acls ;
NSString * module ;
SOGoDomainDefaults * dd ;
acls = [ self _realAclsForUser : uid forObjectAtPath : objectPathArray ] ;
if ( ! ( [ acls count ] || [ uid isEqualToString : @ "anonymous" ] ) )
acls = [ self _realAclsForUser : defaultUserID
forObjectAtPath : objectPathArray ] ;
2007-04-27 21:45:12 +02:00
2008-12-30 23:25:30 +01:00
// If we still don ' t have ACLs defined for this particular resource ,
2009-11-29 05:19:32 +01:00
// let ' s go get the domain defaults , if any .
2013-01-15 19:33:45 +01:00
if ( ! [ acls count ] && ! [ uid isEqualToString : @ "anonymous" ] )
2008-12-30 23:25:30 +01:00
{
2009-11-29 05:19:32 +01:00
dd = [ [ context activeUser ] domainDefaults ] ;
module = [ container nameInContainer ] ;
if ( [ module isEqualToString : @ "Calendar" ] )
acls = [ dd calendarDefaultRoles ] ;
else if ( [ module isEqualToString : @ "Contacts" ] )
acls = [ dd contactsDefaultRoles ] ;
2008-12-30 23:25:30 +01:00
}
2009-06-04 01:06:52 +02:00
2007-04-27 21:45:12 +02:00
return acls ;
}
2007-04-17 16:30:12 +02:00
- ( void ) removeAclsForUsers : ( NSArray * ) users
forObjectAtPath : ( NSArray * ) objectPathArray
{
EOQualifier * qualifier ;
2019-12-04 10:37:08 +01:00
NSString * uid , * uids , * qs , * objectPath , * domain ;
2016-09-26 22:22:44 +02:00
NSMutableArray * usersAndGroups , * groupsMembers ;
2007-04-27 21:45:12 +02:00
NSMutableDictionary * aclsForObject ;
2019-11-26 15:29:02 +01:00
2009-05-06 23:57:21 +02:00
unsigned int i ;
2007-04-17 16:30:12 +02:00
if ( [ users count ] > 0 )
{
2009-05-06 23:57:21 +02:00
usersAndGroups = [ NSMutableArray arrayWithArray : users ] ;
2016-09-26 22:22:44 +02:00
groupsMembers = [ NSMutableArray array ] ;
2009-05-06 23:57:21 +02:00
for ( i = 0 ; i < [ usersAndGroups count ] ; i + + )
2009-07-01 16:03:58 +02:00
{
2019-11-26 15:29:02 +01:00
NSDictionary * dict ;
2009-07-01 16:03:58 +02:00
uid = [ usersAndGroups objectAtIndex : i ] ;
2019-12-04 10:37:08 +01:00
domain = [ [ context activeUser ] domain ] ;
dict = [ [ SOGoUserManager sharedUserManager ] contactInfosForUserWithUIDorEmail : uid
inDomain : domain ] ;
2019-11-26 15:29:02 +01:00
if ( dict && [ [ dict objectForKey : @ "isGroup" ] boolValue ] )
2009-07-01 16:03:58 +02:00
{
2019-11-26 15:29:02 +01:00
id < SOGoSource > source ;
source = [ [ SOGoUserManager sharedUserManager ] sourceWithID : [ dict objectForKey : @ "SOGoSource" ] ] ;
2019-12-04 10:37:08 +01:00
if ( [ source conformsToProtocol : @ protocol ( SOGoMembershipSource ) ] )
2016-09-26 22:22:44 +02:00
{
2020-05-26 15:25:25 +02:00
NSArray * members ;
2020-07-01 22:58:16 +02:00
SOGoUser * user ;
2019-11-26 15:29:02 +01:00
unsigned int j ;
// Fetch members to remove them from the cache along the group
2019-12-04 10:37:08 +01:00
members = [ ( id < SOGoMembershipSource > ) ( source ) membersForGroupWithUID : uid ] ;
2019-11-26 15:29:02 +01:00
for ( j = 0 ; j < [ members count ] ; j + + )
{
user = [ members objectAtIndex : j ] ;
2020-07-01 22:58:16 +02:00
[ groupsMembers addObject : [ user login ] ] ;
2019-11-26 15:29:02 +01:00
}
if ( ! [ uid hasPrefix : @ "@" ] )
// Prefix the UID with the character "@" when dealing with a group
[ usersAndGroups replaceObjectAtIndex : i
withObject : [ NSString stringWithFormat : @ "@%@" , uid ] ] ;
2016-09-26 22:22:44 +02:00
}
2020-05-26 15:25:25 +02:00
else
{
2020-06-03 13:46:57 +02:00
[ self errorWithFormat : @ "Inconsistency error (removeAclsForUsers:forObjectAtPath:) - got group identifier (%@) from a source (%@) that does not support groups (%@)." , uid , [ dict objectForKey : @ "SOGoSource" ] , NSStringFromClass ( [ source class ] ) ] ;
2020-05-26 15:25:25 +02:00
return ;
}
2009-07-01 16:03:58 +02:00
}
}
2007-04-27 21:45:12 +02:00
objectPath = [ objectPathArray componentsJoinedByString : @ "/" ] ;
2010-10-15 20:30:08 +02:00
aclsForObject = [ [ SOGoCache sharedCache ] aclsForPath : objectPath ] ;
2007-04-27 21:45:12 +02:00
if ( aclsForObject )
2010-10-15 20:30:08 +02:00
{
2016-09-26 22:22:44 +02:00
// Remove users , groups and groups members from the cache
2010-10-15 20:30:08 +02:00
[ aclsForObject removeObjectsForKeys : usersAndGroups ] ;
2016-09-26 22:22:44 +02:00
[ aclsForObject removeObjectsForKeys : groupsMembers ] ;
2010-10-15 20:30:08 +02:00
[ [ SOGoCache sharedCache ] setACLs : aclsForObject
forPath : objectPath ] ;
}
2009-05-06 23:57:21 +02:00
uids = [ usersAndGroups componentsJoinedByString : @ "') OR (c_uid = '" ] ;
2007-04-17 16:30:12 +02:00
qs = [ NSString
2010-01-15 00:19:19 +01:00
stringWithFormat : @ "(c_object = '/%@') AND ((c_uid = '%@'))" ,
objectPath , uids ] ;
2007-04-17 16:30:12 +02:00
qualifier = [ EOQualifier qualifierWithQualifierFormat : qs ] ;
[ [ self ocsFolder ] deleteAclMatchingQualifier : qualifier ] ;
}
}
2007-05-18 01:09:46 +02:00
- ( void ) _commitRoles : ( NSArray * ) roles
2009-07-01 16:03:58 +02:00
forUID : ( NSString * ) uid
forObject : ( NSString * ) objectPath
2007-04-17 16:30:12 +02:00
{
EOAdaptorChannel * channel ;
GCSFolder * folder ;
2007-04-25 00:45:38 +02:00
NSEnumerator * userRoles ;
2007-05-18 01:09:46 +02:00
NSString * SQL , * currentRole ;
2007-04-27 21:45:12 +02:00
2007-04-17 16:30:12 +02:00
folder = [ self ocsFolder ] ;
channel = [ folder acquireAclChannel ] ;
2008-11-26 17:26:32 +01:00
[ [ channel adaptorContext ] beginTransaction ] ;
2007-04-25 00:45:38 +02:00
userRoles = [ roles objectEnumerator ] ;
2008-07-04 18:06:09 +02:00
while ( ( currentRole = [ userRoles nextObject ] ) )
2007-04-25 00:45:38 +02:00
{
2016-03-10 22:34:06 +01:00
if ( [ GCSFolderManager singleStoreMode ] )
SQL = [ NSString stringWithFormat : @ "INSERT INTO %@"
@ " (c_object, c_uid, c_role, c_folder_id)"
@ " VALUES ('/%@', '%@', '%@', %@)" ,
[ folder aclTableName ] ,
objectPath , uid , currentRole , [ folder folderId ] ] ;
else
SQL = [ NSString stringWithFormat : @ "INSERT INTO %@"
@ " (c_object, c_uid, c_role)"
@ " VALUES ('/%@', '%@', '%@')" ,
[ folder aclTableName ] ,
objectPath , uid , currentRole ] ;
2009-07-07 22:56:09 +02:00
[ channel evaluateExpressionX : SQL ] ;
2007-04-25 00:45:38 +02:00
}
2007-04-17 16:30:12 +02:00
2008-11-26 17:26:32 +01:00
[ [ channel adaptorContext ] commitTransaction ] ;
2007-04-17 16:30:12 +02:00
[ folder releaseChannel : channel ] ;
}
2007-05-18 01:09:46 +02:00
- ( void ) setRoles : ( NSArray * ) roles
forUser : ( NSString * ) uid
forObjectAtPath : ( NSArray * ) objectPathArray
{
2019-12-04 10:37:08 +01:00
NSString * objectPath , * aUID , * domain ;
2007-05-18 01:09:46 +02:00
NSMutableArray * newRoles ;
2016-09-26 22:22:44 +02:00
objectPath = [ objectPathArray componentsJoinedByString : @ "/" ] ;
2016-10-20 16:27:26 +02:00
// We make sure we don ' t get unescaped uid - like foo % 40 bar . com
// or for groups - like % 40 team
uid = [ uid stringByUnescapingURL ] ;
2009-05-03 19:50:57 +02:00
aUID = uid ;
if ( ! [ uid hasPrefix : @ "@" ] )
{
2019-11-26 15:29:02 +01:00
NSDictionary * dict ;
2019-12-04 10:37:08 +01:00
domain = [ [ context activeUser ] domain ] ;
dict = [ [ SOGoUserManager sharedUserManager ] contactInfosForUserWithUIDorEmail : uid
inDomain : domain ] ;
2019-11-26 15:29:02 +01:00
if ( [ [ dict objectForKey : @ "isGroup" ] boolValue ] )
2016-09-26 22:22:44 +02:00
{
aUID = [ NSString stringWithFormat : @ "@%@" , uid ] ;
// Remove all roles when defining ACLs for a group
[ [ SOGoCache sharedCache ] setACLs : nil
forPath : objectPath ] ;
}
2009-05-03 19:50:57 +02:00
}
[ self removeAclsForUsers : [ NSArray arrayWithObject : aUID ]
2009-07-01 16:03:58 +02:00
forObjectAtPath : objectPathArray ] ;
2007-05-18 01:09:46 +02:00
newRoles = [ NSMutableArray arrayWithArray : roles ] ;
2010-06-01 20:12:01 +02:00
[ newRoles removeObject : SoRole_Authenticated ] ;
[ newRoles removeObject : SoRole_Anonymous ] ;
[ newRoles removeObject : SOGoRole_PublicUser ] ;
2007-05-18 01:09:46 +02:00
[ newRoles removeObject : SOGoRole_AuthorizedSubscriber ] ;
[ newRoles removeObject : SOGoRole_None ] ;
2011-10-14 15:32:10 +02:00
2007-05-18 01:09:46 +02:00
if ( ! [ newRoles count ] )
[ newRoles addObject : SOGoRole_None ] ;
2016-09-26 22:22:44 +02:00
[ self _cacheRoles : newRoles forUser : aUID
2011-10-14 15:32:10 +02:00
forObjectAtPath : objectPath ] ;
2009-05-03 19:50:57 +02:00
[ self _commitRoles : newRoles forUID : aUID forObject : objectPath ] ;
2007-05-18 01:09:46 +02:00
}
2007-04-17 16:30:12 +02:00
/ * acls * /
2007-05-19 02:49:05 +02:00
- ( NSArray * ) aclUsers
2007-04-17 16:30:12 +02:00
{
2008-05-16 22:33:55 +02:00
return [ self aclUsersForObjectAtPath : [ self pathArrayToFolder ] ] ;
2007-04-17 16:30:12 +02:00
}
- ( NSArray * ) aclsForUser : ( NSString * ) uid
{
2007-06-01 23:03:50 +02:00
NSMutableArray * acls ;
NSArray * ownAcls , * containerAcls ;
acls = [ NSMutableArray array ] ;
2008-05-16 22:33:55 +02:00
ownAcls = [ self aclsForUser : uid forObjectAtPath : [ self pathArrayToFolder ] ] ;
2007-06-01 23:03:50 +02:00
[ acls addObjectsFromArray : ownAcls ] ;
if ( [ container respondsToSelector : @ selector ( aclsForUser : ) ] )
{
containerAcls = [ container aclsForUser : uid ] ;
if ( [ containerAcls count ] > 0 )
2009-07-01 16:03:58 +02:00
{
2007-06-01 23:03:50 +02:00
# warning this should be checked
2009-07-01 16:03:58 +02:00
if ( [ containerAcls containsObject : SOGoRole_ObjectEraser ] )
[ acls addObject : SOGoRole_ObjectEraser ] ;
}
2007-06-01 23:03:50 +02:00
}
return acls ;
2007-04-17 16:30:12 +02:00
}
2007-04-25 00:45:38 +02:00
- ( void ) setRoles : ( NSArray * ) roles
2007-04-17 16:30:12 +02:00
forUser : ( NSString * ) uid
{
2016-09-26 21:22:49 +02:00
return [ self setRoles : roles
forUser : uid
forObjectAtPath : [ self pathArrayToFolder ] ] ;
2007-04-17 16:30:12 +02:00
}
- ( void ) removeAclsForUsers : ( NSArray * ) users
{
return [ self removeAclsForUsers : users
2009-07-01 16:03:58 +02:00
forObjectAtPath : [ self pathArrayToFolder ] ] ;
2007-04-17 16:30:12 +02:00
}
2007-05-22 20:35:17 +02:00
- ( NSString * ) defaultUserID
{
return defaultUserID ;
}
2006-06-15 21:34:10 +02:00
/ * description * /
2007-07-12 17:55:06 +02:00
- ( void ) appendAttributesToDescription : ( NSMutableString * ) _ms
{
2006-06-15 21:34:10 +02:00
[ super appendAttributesToDescription : _ms ] ;
2009-07-01 16:03:58 +02:00
2006-06-15 21:34:10 +02:00
[ _ms appendFormat : @ " ocs=%@" , [ self ocsPath ] ] ;
}
2010-08-12 16:02:21 +02:00
/ * tmp : multiget * /
- ( NSArray * ) _fetchComponentsWithNames : ( NSArray * ) cNames
fields : ( NSArray * ) fields
{
NSArray * records ;
NSString * sqlFilter ;
NSMutableString * filterString ;
EOQualifier * qualifier ;
sqlFilter = [ self aclSQLListingFilter ] ;
if ( sqlFilter )
{
filterString = [ NSMutableString stringWithCapacity : 8192 ] ;
[ filterString appendFormat : @ "(c_name='%@')" ,
[ cNames componentsJoinedByString : @ "' OR c_name='" ] ] ;
if ( [ sqlFilter length ] > 0 )
[ filterString appendFormat : @ " AND (%@)" , sqlFilter ] ;
qualifier = [ EOQualifier qualifierWithQualifierFormat : filterString ] ;
records = [ [ self ocsFolder ] fetchFields : fields
matchingQualifier : qualifier ] ;
if ( ! [ records isNotNull ] )
{
[ self errorWithFormat : @ "(%s): fetch failed!" , __PRETTY _FUNCTION __ ] ;
return nil ;
}
}
else
records = [ NSArray array ] ;
return records ;
}
# define maxQuerySize 2500
# define baseQuerySize 160
# define idQueryOverhead 13
- ( NSArray * ) _fetchComponentsMatchingObjectNames : ( NSArray * ) cNames
fields : ( NSArray * ) fields
{
NSMutableArray * components ;
NSArray * records ;
NSMutableArray * currentNames ;
unsigned int count , max , currentSize , queryNameLength ;
NSString * currentName ;
// NSLog ( @ "fetching components matching names" ) ;
currentNames = [ NSMutableArray array ] ;
currentSize = baseQuerySize ;
max = [ cNames count ] ;
components = [ NSMutableArray arrayWithCapacity : max ] ;
for ( count = 0 ; count < max ; count + + )
{
currentName = [ cNames objectAtIndex : count ] ;
queryNameLength = idQueryOverhead + [ currentName length ] ;
if ( ( currentSize + queryNameLength )
> maxQuerySize )
{
records = [ self _fetchComponentsWithNames : currentNames fields : fields ] ;
[ components addObjectsFromArray : records ] ;
[ currentNames removeAllObjects ] ;
currentSize = baseQuerySize ;
}
[ currentNames addObject : currentName ] ;
currentSize + = queryNameLength ;
}
records = [ self _fetchComponentsWithNames : currentNames fields : fields ] ;
[ components addObjectsFromArray : records ] ;
// NSLog ( @ "/fetching components matching names" ) ;
return components ;
}
- ( NSDictionary * ) _deduceObjectNamesFromURLs : ( NSArray * ) urls
{
unsigned int count , max ;
2010-08-20 16:07:32 +02:00
NSString * url , * currentURL , * componentURLPath , * cName , * baseURLString ;
2010-08-12 16:02:21 +02:00
NSMutableDictionary * cNames ;
NSURL * componentURL , * baseURL ;
max = [ urls count ] ;
cNames = [ NSMutableDictionary dictionaryWithCapacity : max ] ;
baseURL = [ self davURL ] ;
baseURLString = [ self davURLAsString ] ;
for ( count = 0 ; count < max ; count + + )
{
2010-08-20 16:07:32 +02:00
currentURL
= [ [ urls objectAtIndex : count ] stringByReplacingString : @ "%40"
withString : @ "@" ] ;
2010-08-12 16:02:21 +02:00
url = [ NSString stringWithFormat : @ "%@/%@" ,
2010-08-20 16:07:32 +02:00
[ currentURL stringByDeletingLastPathComponent ] ,
[ [ currentURL lastPathComponent ] stringByEscapingURL ] ] ;
2010-08-12 16:02:21 +02:00
componentURL = [ [ NSURL URLWithString : url relativeToURL : baseURL ]
standardizedURL ] ;
componentURLPath = [ componentURL absoluteString ] ;
if ( [ componentURLPath rangeOfString : baseURLString ] . location
! = NSNotFound )
{
cName = [ [ urls objectAtIndex : count ] lastPathComponent ] ;
[ cNames setObject : [ urls objectAtIndex : count ] forKey : cName ] ;
}
}
return cNames ;
}
- ( NSDictionary * ) _fetchComponentsMatchingURLs : ( NSArray * ) urls
fields : ( NSArray * ) fields
{
NSMutableDictionary * components ;
NSDictionary * cnames , * record ;
NSString * recordURL ;
NSArray * records ;
unsigned int count , max ;
components = [ NSMutableDictionary dictionary ] ;
cnames = [ self _deduceObjectNamesFromURLs : urls ] ;
records = [ self _fetchComponentsMatchingObjectNames : [ cnames allKeys ]
fields : fields ] ;
max = [ records count ] ;
for ( count = 0 ; count < max ; count + + )
{
record = [ records objectAtIndex : count ] ;
recordURL = [ cnames objectForKey : [ record objectForKey : @ "c_name" ] ] ;
if ( recordURL )
[ components setObject : record forKey : recordURL ] ;
}
return components ;
}
# warning the two following methods should be replaced with the new dav rendering mechanism
- ( NSString * ) _nodeTagForProperty : ( NSString * ) property
{
[ self subclassResponsibility : _cmd ] ;
return nil ;
}
- ( NSString * ) _nodeTag : ( NSString * ) property
{
static NSMutableDictionary * tags = nil ;
NSString * nodeTag ;
if ( ! tags )
tags = [ NSMutableDictionary new ] ;
nodeTag = [ tags objectForKey : property ] ;
if ( ! nodeTag )
{
nodeTag = [ self _nodeTagForProperty : property ] ;
[ tags setObject : nodeTag forKey : property ] ;
}
return nodeTag ;
}
- ( NSString * * ) _properties : ( NSString * * ) properties
count : ( unsigned int ) propertiesCount
ofObject : ( NSDictionary * ) object
{
SOGoContentObject * sogoObject ;
NSString * * currentProperty ;
NSString * * values , * * currentValue ;
SEL methodSel ;
// NSLog ( @ "_properties:ofObject:: %@" , [ NSDate date ] ) ;
values = NSZoneMalloc ( NULL ,
( propertiesCount + 1 ) * sizeof ( NSString * ) ) ;
* ( values + propertiesCount ) = nil ;
// c = [ self objectClassForComponentName : [ object objectForKey : @ "c_component" ] ] ;
sogoObject = [ self createChildComponentWithRecord : object ] ;
currentProperty = properties ;
currentValue = values ;
while ( * currentProperty )
{
methodSel = SOGoSelectorForPropertyGetter ( * currentProperty ) ;
if ( methodSel && [ sogoObject respondsToSelector : methodSel ] )
* currentValue = [ [ sogoObject performSelector : methodSel ]
2016-04-06 17:19:18 +02:00
safeStringByEscapingXMLString ] ;
2010-08-12 16:02:21 +02:00
currentProperty + + ;
currentValue + + ;
}
// NSLog ( @ "/_properties:ofObject:: %@" , [ NSDate date ] ) ;
return values ;
}
- ( NSArray * ) _propstats : ( NSString * * ) properties
count : ( unsigned int ) propertiesCount
ofObject : ( NSDictionary * ) object
{
NSMutableArray * propstats , * properties200 , * properties404 , * propDict ;
NSString * * property , * * values , * * currentValue ;
NSString * propertyValue , * nodeTag ;
// NSLog ( @ "_propstats:ofObject:: %@" , [ NSDate date ] ) ;
propstats = [ NSMutableArray array ] ;
properties200 = [ NSMutableArray array ] ;
properties404 = [ NSMutableArray array ] ;
values = [ self _properties : properties count : propertiesCount
ofObject : object ] ;
currentValue = values ;
property = properties ;
while ( * property )
{
nodeTag = [ self _nodeTag : * property ] ;
if ( * currentValue )
{
2014-09-19 20:34:20 +02:00
// Make sure the sent value is sanitized .
NSString * sanitizedValue ;
2014-09-24 20:14:25 +02:00
sanitizedValue = [ * currentValue safeString ] ;
2010-08-12 16:02:21 +02:00
propertyValue = [ NSString stringWithFormat : @ "<%@>%@</%@>" ,
2014-09-19 20:34:20 +02:00
nodeTag , sanitizedValue , nodeTag ] ;
2010-08-12 16:02:21 +02:00
propDict = properties200 ;
}
else
{
propertyValue = [ NSString stringWithFormat : @ "<%@/>" , nodeTag ] ;
propDict = properties404 ;
}
[ propDict addObject : propertyValue ] ;
property + + ;
currentValue + + ;
}
free ( values ) ;
if ( [ properties200 count ] )
[ propstats addObject : [ NSDictionary dictionaryWithObjectsAndKeys :
properties200 , @ "properties" ,
@ "HTTP/1.1 200 OK" , @ "status" ,
nil ] ] ;
if ( [ properties404 count ] )
[ propstats addObject : [ NSDictionary dictionaryWithObjectsAndKeys :
properties404 , @ "properties" ,
@ "HTTP/1.1 404 Not Found" , @ "status" ,
nil ] ] ;
// NSLog ( @ "/_propstats:ofObject:: %@" , [ NSDate date ] ) ;
return propstats ;
}
- ( void ) _appendPropstat : ( NSDictionary * ) propstat
toBuffer : ( NSMutableString * ) r
{
NSArray * properties ;
unsigned int count , max ;
[ r appendString : @ "<D:propstat><D:prop>" ] ;
properties = [ propstat objectForKey : @ "properties" ] ;
max = [ properties count ] ;
for ( count = 0 ; count < max ; count + + )
[ r appendString : [ properties objectAtIndex : count ] ] ;
[ r appendString : @ "</D:prop><D:status>" ] ;
[ r appendString : [ propstat objectForKey : @ "status" ] ] ;
[ r appendString : @ "</D:status></D:propstat>" ] ;
}
# warning We need to use the new DAV utilities here . . .
# warning this is baddddd because we return a single - valued dictionary containing \
a cname which may not event exist . . . the logic behind appendObject : . . . should be \
rethought , especially since we may start using SQL views
- ( void ) appendObject : ( NSDictionary * ) object
properties : ( NSString * * ) properties
count : ( unsigned int ) propertiesCount
withBaseURL : ( NSString * ) baseURL
toBuffer : ( NSMutableString * ) r
{
NSArray * propstats ;
unsigned int count , max ;
[ r appendFormat : @ "<D:response><D:href>" ] ;
[ r appendString : baseURL ] ;
2011-11-17 20:16:46 +01:00
[ r appendString : [ [ object objectForKey : @ "c_name" ] stringByEscapingURL ] ] ;
2010-08-12 16:02:21 +02:00
[ r appendString : @ "</D:href>" ] ;
// NSLog ( @ "(appendPropstats...): %@" , [ NSDate date ] ) ;
propstats = [ self _propstats : properties count : propertiesCount
ofObject : object ] ;
max = [ propstats count ] ;
for ( count = 0 ; count < max ; count + + )
[ self _appendPropstat : [ propstats objectAtIndex : count ]
toBuffer : r ] ;
// NSLog ( @ "/(appendPropstats...): %@" , [ NSDate date ] ) ;
[ r appendString : @ "</D:response>" ] ;
}
- ( void ) appendMissingObjectRef : ( NSString * ) href
toBuffer : ( NSMutableString * ) r
{
[ r appendString : @ "<D:response><D:href>" ] ;
[ r appendString : href ] ;
[ r appendString : @ "</D:href><D:status>HTTP/1.1 404 Not Found</D:status></D:response>" ] ;
}
- ( void ) _appendComponentProperties : ( NSDictionary * ) properties
matchingURLs : ( id < DOMNodeList > ) refs
toResponse : ( WOResponse * ) response
{
NSObject < DOMElement > * element ;
NSDictionary * currentComponent , * components ;
NSString * currentURL , * baseURL , * currentField ;
NSString * * propertiesArray ;
NSMutableArray * urls , * fields ;
NSMutableString * buffer ;
unsigned int count , max , propertiesCount ;
NSEnumerator * addFields ;
baseURL = [ self davURLAsString ] ;
2012-04-13 01:44:56 +02:00
# warning review this when bug #276
2010-08-12 16:02:21 +02:00
if ( ! [ baseURL hasSuffix : @ "/" ] )
baseURL = [ NSString stringWithFormat : @ "%@/" , baseURL ] ;
urls = [ NSMutableArray array ] ;
max = [ refs length ] ;
for ( count = 0 ; count < max ; count + + )
{
element = [ refs objectAtIndex : count ] ;
2011-11-17 20:16:46 +01:00
currentURL = [ [ [ element firstChild ] nodeValue ] stringByUnescapingURL ] ;
2010-08-12 16:02:21 +02:00
[ urls addObject : currentURL ] ;
}
propertiesArray = [ [ properties allKeys ] asPointersOfObjects ] ;
propertiesCount = [ properties count ] ;
fields = [ NSMutableArray arrayWithObjects : @ "c_name" , @ "c_component" , nil ] ;
addFields = [ [ properties allValues ] objectEnumerator ] ;
while ( ( currentField = [ addFields nextObject ] ) )
if ( [ currentField length ] )
[ fields addObjectUniquely : currentField ] ;
components = [ self _fetchComponentsMatchingURLs : urls fields : fields ] ;
max = [ urls count ] ;
// NSLog ( @ "adding properties with url" ) ;
buffer = [ NSMutableString stringWithCapacity : max * 512 ] ;
for ( count = 0 ; count < max ; count + + )
{
2011-04-05 15:50:09 +02:00
currentURL = [ urls objectAtIndex : count ] ;
currentComponent = [ components objectForKey : currentURL ] ;
2010-08-12 16:02:21 +02:00
if ( currentComponent )
[ self appendObject : currentComponent
properties : propertiesArray
count : propertiesCount
withBaseURL : baseURL
toBuffer : buffer ] ;
else
[ self appendMissingObjectRef : currentURL
toBuffer : buffer ] ;
}
[ response appendContentString : buffer ] ;
// NSLog ( @ "/adding properties with url" ) ;
NSZoneFree ( NULL , propertiesArray ) ;
}
- ( WOResponse * ) performMultigetInContext : ( WOContext * ) queryContext
inNamespace : ( NSString * ) namespace
{
WOResponse * r ;
id < DOMDocument > document ;
2012-10-22 16:09:13 +02:00
id < DOMElement > documentElement , propElement ;
2010-08-12 16:02:21 +02:00
r = [ context response ] ;
[ r prepareDAVResponse ] ;
[ r appendContentString :
[ NSString stringWithFormat : @ "<D:multistatus xmlns:D=\" DAV : \ ""
@ " xmlns:C=\" % @ \ ">" , namespace ] ] ;
document = [ [ queryContext request ] contentAsDOMDocument ] ;
2012-10-22 16:09:13 +02:00
documentElement = [ document documentElement ] ;
propElement = [ ( NGDOMNodeWithChildren * )
documentElement firstElementWithTag : @ "prop"
inNamespace : @ "DAV:" ] ;
2010-08-12 16:02:21 +02:00
[ self _appendComponentProperties : [ self parseDAVRequestedProperties : propElement ]
matchingURLs : [ documentElement getElementsByTagName : @ "href" ]
toResponse : r ] ;
[ r appendContentString : @ "</D:multistatus>" ] ;
return r ;
}
2006-06-15 21:34:10 +02:00
@ end / * SOGoFolder * /