2006-06-15 21:34:10 +02:00
/ *
2019-11-27 23:00:28 +01:00
Copyright ( C ) 2007 -2019 Inverse inc .
2008-12-30 20:48:33 +01:00
Copyright ( C ) 2004 -2005 SKYRIX Software AG
2006-06-15 21:34:10 +02:00
2011-04-25 12:31:08 +02:00
This file is part of SOGo .
2006-06-15 21:34:10 +02:00
2011-04-25 12:31:08 +02:00
SOGo is free software ; you can redistribute it and / or modify it under
2006-06-15 21:34:10 +02:00
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation ; either version 2 , or ( at your option ) any
later version .
2011-04-25 12:31:08 +02:00
SOGo is distributed in the hope that it will be useful , but WITHOUT ANY
2006-06-15 21:34:10 +02:00
WARRANTY ; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE . See the GNU Lesser General Public
License for more details .
You should have received a copy of the GNU Lesser General Public
License along with OGo ; see the file COPYING . If not , write to the
Free Software Foundation , 59 Temple Place - Suite 330 , Boston , MA
02111 -1307 , USA .
* /
2007-08-07 20:37:31 +02:00
# import < Foundation / NSCalendarDate . h >
# import < NGObjWeb / NSException + HTTP . h >
# import < NGObjWeb / SoObject + SoDAV . h >
2016-02-10 20:46:11 +01:00
# import < NGObjWeb / WOApplication . h >
2007-08-07 20:37:31 +02:00
# import < NGObjWeb / WOContext + SoObjects . h >
# import < NGExtensions / NSString + misc . h >
# import < GDLContentStore / GCSFolder . h >
# import < EOControl / EOQualifier . h >
2014-09-12 14:34:15 +02:00
# import < NGCards / iCalAlarm . h >
2008-06-30 20:52:20 +02:00
# import < NGCards / iCalFreeBusy . h >
2007-08-07 20:37:31 +02:00
# import < NGCards / iCalDateTime . h >
# import < NGCards / iCalRecurrenceCalculator . h >
2009-10-21 23:17:11 +02:00
# import < NGCards / iCalTimeZone . h >
2011-01-14 03:54:33 +01:00
# import < NGCards / iCalTimeZonePeriod . h >
2014-09-12 14:34:15 +02:00
# import < NGCards / iCalToDo . h >
2007-08-07 20:37:31 +02:00
# import < NGCards / NSString + NGCards . h >
2019-11-27 23:00:28 +01:00
# import < NGExtensions / NSCalendarDate + misc . h >
2006-10-11 20:48:25 +02:00
# import < NGExtensions / NGCalendarDateRange . h >
2007-08-07 20:37:31 +02:00
# import < NGExtensions / NSNull + misc . h >
# import < NGExtensions / NSObject + Logs . h >
2007-03-10 00:10:43 +01:00
# import < SaxObjC / XMLNamespaces . h >
2006-10-11 20:48:25 +02:00
2009-06-18 22:58:46 +02:00
# import < SOGo / DOMNode + SOGo . h >
2008-05-03 01:08:15 +02:00
# import < SOGo / NSArray + Utilities . h >
2009-11-29 05:19:32 +01:00
# import < SOGo / NSDictionary + Utilities . h >
2008-05-03 01:08:15 +02:00
# import < SOGo / NSObject + DAV . h >
# import < SOGo / NSString + Utilities . h >
2011-11-30 04:10:06 +01:00
# import < SOGo / SOGoBuild . h >
2008-01-16 19:57:58 +01:00
# import < SOGo / SOGoCache . h >
2009-11-29 05:19:32 +01:00
# import < SOGo / SOGoDomainDefaults . h >
2006-12-14 22:20:13 +01:00
# import < SOGo / SOGoPermissions . h >
2007-03-07 22:27:19 +01:00
# import < SOGo / SOGoUser . h >
2009-11-29 05:19:32 +01:00
# import < SOGo / SOGoUserSettings . h >
2008-06-30 20:52:20 +02:00
# import < SOGo / SOGoUserFolder . h >
2009-11-29 05:19:32 +01:00
# import < SOGo / SOGoUserManager . h >
2008-05-03 01:08:15 +02:00
# import < SOGo / SOGoWebDAVAclManager . h >
2009-06-09 22:00:28 +02:00
# import < SOGo / SOGoWebDAVValue . h >
2009-07-01 21:27:44 +02:00
# import < SOGo / WORequest + SOGo . h >
2010-01-15 00:19:19 +01:00
# import < SOGo / WOResponse + SOGo . h >
2019-11-26 15:29:02 +01:00
# import < SOGo / SOGoSource . h >
2006-11-02 22:53:27 +01:00
2014-09-12 14:34:15 +02:00
# import "iCalCalendar+SOGo.h"
2010-04-21 16:35:58 +02:00
# import "iCalRepeatableEntityObject+SOGo.h"
2011-04-16 03:35:06 +02:00
# import "iCalEvent+SOGo.h"
2009-07-20 20:29:09 +02:00
# import "iCalPerson+SOGo.h"
2006-09-27 00:27:34 +02:00
# import "SOGoAppointmentObject.h"
2007-11-07 16:58:43 +01:00
# import "SOGoAppointmentFolders.h"
2008-06-30 20:52:20 +02:00
# import "SOGoFreeBusyObject.h"
2006-10-11 20:48:25 +02:00
# import "SOGoTaskObject.h"
2015-10-31 07:10:03 +01:00
# import "SOGoWebAppointmentFolder.h"
2006-10-11 20:48:25 +02:00
2008-04-22 01:03:48 +02:00
# define defaultColor @ "#AAAAAA"
2010-08-12 16:02:21 +02:00
@ interface SOGoGCSFolder ( SOGoPrivate )
- ( void ) appendObject : ( NSDictionary * ) object
properties : ( NSString * * ) properties
count : ( unsigned int ) propertiesCount
withBaseURL : ( NSString * ) baseURL
toBuffer : ( NSMutableString * ) r ;
@ end
2006-06-15 21:34:10 +02:00
@ implementation SOGoAppointmentFolder
2008-06-30 20:52:20 +02:00
static NSNumber * sharedYes = nil ;
2014-09-12 14:34:15 +02:00
static Class iCalEventK = nil ;
2006-06-15 21:34:10 +02:00
2006-08-16 00:04:37 +02:00
+ ( void ) initialize
{
2009-07-07 22:57:00 +02:00
static BOOL didInit = NO ;
2009-11-29 05:19:32 +01:00
2009-06-03 23:38:46 +02:00
if ( ! didInit )
{
didInit = YES ;
sharedYes = [ [ NSNumber numberWithBool : YES ] retain ] ;
2009-11-29 05:19:32 +01:00
[ iCalEntityObject initializeSOGoExtensions ] ;
2013-01-25 16:21:28 +01:00
iCalEventK = [ iCalEvent class ] ;
2009-06-03 23:38:46 +02:00
}
2007-04-11 21:08:58 +02:00
}
2008-05-03 01:08:15 +02:00
+ ( SOGoWebDAVAclManager * ) webdavAclManager
{
2008-12-15 23:27:45 +01:00
static SOGoWebDAVAclManager * aclManager = nil ;
2008-06-30 20:52:20 +02:00
NSString * nsI ;
2008-05-03 01:08:15 +02:00
2008-07-29 18:36:16 +02:00
if ( ! aclManager )
2008-05-03 01:08:15 +02:00
{
nsI = @ "urn:inverse:params:xml:ns:inverse-dav" ;
2008-07-29 18:36:16 +02:00
aclManager = [ SOGoWebDAVAclManager new ] ;
[ aclManager registerDAVPermission : davElement ( @ "read" , XMLNS_WEBDAV )
2010-02-02 22:26:23 +01:00
abstract : YES
withEquivalent : SoPerm_WebDAVAccess
asChildOf : davElement ( @ "all" , XMLNS_WEBDAV ) ] ;
[ aclManager
registerDAVPermission : davElement ( @ "read-current-user-privilege-set" , XMLNS_WEBDAV )
abstract : YES
withEquivalent : SoPerm_WebDAVAccess
asChildOf : davElement ( @ "read" , XMLNS_WEBDAV ) ] ;
2010-01-15 00:19:19 +01:00
[ aclManager registerDAVPermission : davElement ( @ "read-free-busy" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : SOGoCalendarPerm_ReadFreeBusy
asChildOf : davElement ( @ "all" , XMLNS_WEBDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "write" , XMLNS_WEBDAV )
2010-02-02 22:26:23 +01:00
abstract : YES
withEquivalent : nil
asChildOf : davElement ( @ "all" , XMLNS_WEBDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "bind" , XMLNS_WEBDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : SoPerm_AddDocumentsImagesAndFiles
asChildOf : davElement ( @ "write" , XMLNS_WEBDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "schedule" ,
XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "bind" , XMLNS_WEBDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "schedule-post" ,
XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-post-vevent" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-post" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-post-vtodo" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-post" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-post-vjournal" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-post" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-post-vfreebusy" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-post" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "schedule-deliver" ,
XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-deliver-vevent" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-deliver" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-deliver-vtodo" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-deliver" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-deliver-vjournal" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-deliver" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-deliver-vfreebusy" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-deliver" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "schedule-respond" ,
XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-respond-vevent" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-respond" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission :
davElement ( @ "schedule-respond-vtodo" , XMLNS_CALDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : nil
asChildOf : davElement ( @ "schedule-respond" , XMLNS_CALDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "unbind" , XMLNS_WEBDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : SoPerm_DeleteObjects
asChildOf : davElement ( @ "write" , XMLNS_WEBDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager
2008-06-30 20:52:20 +02:00
registerDAVPermission : davElement ( @ "write-properties" , XMLNS_WEBDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : SoPerm_ChangePermissions / * hackish * /
asChildOf : davElement ( @ "write" , XMLNS_WEBDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager
2008-06-30 20:52:20 +02:00
registerDAVPermission : davElement ( @ "write-content" , XMLNS_WEBDAV )
2010-02-02 22:26:23 +01:00
abstract : NO
withEquivalent : SoPerm_AddDocumentsImagesAndFiles
asChildOf : davElement ( @ "write" , XMLNS_WEBDAV ) ] ;
2014-06-19 22:08:15 +02:00
/ * read - acl and write - acl are defined in RFC3744 * /
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "admin" , nsI )
2010-02-02 22:26:23 +01:00
abstract : YES
withEquivalent : nil
asChildOf : davElement ( @ "all" , XMLNS_WEBDAV ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "read-acl" , XMLNS_WEBDAV )
2010-02-02 22:26:23 +01:00
abstract : YES
withEquivalent : SOGoPerm_ReadAcls
asChildOf : davElement ( @ "admin" , nsI ) ] ;
2008-07-29 18:36:16 +02:00
[ aclManager registerDAVPermission : davElement ( @ "write-acl" , XMLNS_WEBDAV )
2010-02-02 22:26:23 +01:00
abstract : YES
withEquivalent : SoPerm_ChangePermissions
asChildOf : davElement ( @ "admin" , nsI ) ] ;
2014-06-19 22:08:15 +02:00
/ * Default permissions for calendars . These are very important so that DAV client can
detect permission changes on calendars and reload all items , if necessary * /
/ * Public ones * /
[ aclManager registerDAVPermission : davElement ( @ "viewwhole-public-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_ViewWholePublicRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "viewdant-public-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_ViewDAndTOfPublicRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "modify-public-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_ModifyPublicRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "respondto-public-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_RespondToPublicRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
/ * Private ones * /
[ aclManager registerDAVPermission : davElement ( @ "viewwhole-private-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_ViewWholePrivateRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "viewdant-private-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_ViewDAndTOfPrivateRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "modify-private-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_ModifyPrivateRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "respondto-private-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_RespondToPrivateRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
/ * Condifential ones * /
[ aclManager registerDAVPermission : davElement ( @ "viewwhole-confidential-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_ViewWholeConfidentialRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "viewdant-confidential-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_ViewDAndTOfConfidentialRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "modify-confidential-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_ModifyConfidentialRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
[ aclManager registerDAVPermission : davElement ( @ "respondto-confidential-records" , nsI )
abstract : YES
withEquivalent : SOGoCalendarPerm_RespondToConfidentialRecords
asChildOf : davElement ( @ "admin" , nsI ) ] ;
2008-05-03 01:08:15 +02:00
}
2008-07-29 18:36:16 +02:00
return aclManager ;
2008-05-03 01:08:15 +02:00
}
2007-04-11 21:08:58 +02:00
- ( id ) initWithName : ( NSString * ) name
inContainer : ( id ) newContainer
{
2009-11-29 05:19:32 +01:00
SOGoUser * user ;
2007-04-11 21:08:58 +02:00
if ( ( self = [ super initWithName : name inContainer : newContainer ] ) )
{
2009-11-29 05:19:32 +01:00
user = [ context activeUser ] ;
timeZone = [ [ user userDefaults ] timeZone ] ;
2007-11-26 18:40:44 +01:00
aclMatrix = [ NSMutableDictionary new ] ;
stripFields = nil ;
uidToFilename = nil ;
2009-06-04 02:40:21 +02:00
memset ( userCanAccessObjectsClassifiedAs , NO ,
iCalAccessClassCount * sizeof ( BOOL ) ) ;
2009-11-29 05:19:32 +01:00
2015-01-26 21:45:42 +01:00
davCalendarStartTimeLimit = [ [ user domainDefaults ] davCalendarStartTimeLimit ] ;
2009-11-29 05:19:32 +01:00
davTimeLimitSeconds = davCalendarStartTimeLimit * 86400 ;
/ * 86400 / 2 = 43200. We hardcode that value in order to avoid
integer and float confusion . * /
davTimeHalfLimitSeconds = davCalendarStartTimeLimit * 43200 ;
2012-04-13 01:40:05 +02:00
componentSet = nil ;
2015-01-26 21:45:42 +01:00
baseCalDAVURL = nil ;
basePublicCalDAVURL = nil ;
2007-04-11 21:08:58 +02:00
}
return self ;
2006-06-15 21:34:10 +02:00
}
2006-08-16 00:04:37 +02:00
- ( void ) dealloc
{
2007-11-26 18:40:44 +01:00
[ aclMatrix release ] ;
[ stripFields release ] ;
2007-04-11 21:08:58 +02:00
[ uidToFilename release ] ;
2012-04-13 01:40:05 +02:00
[ componentSet release ] ;
2015-01-26 21:45:42 +01:00
[ baseCalDAVURL release ] ;
[ basePublicCalDAVURL release ] ;
2006-06-15 21:34:10 +02:00
[ super dealloc ] ;
}
2008-06-13 22:22:51 +02:00
- ( Class ) objectClassForComponentName : ( NSString * ) componentName
{
Class objectClass ;
if ( [ componentName isEqualToString : @ "vevent" ] )
objectClass = [ SOGoAppointmentObject class ] ;
else if ( [ componentName isEqualToString : @ "vtodo" ] )
objectClass = [ SOGoTaskObject class ] ;
else
objectClass = Nil ;
return objectClass ;
}
2008-04-22 01:03:48 +02:00
- ( NSString * ) calendarColor
{
NSString * color ;
2010-03-10 22:53:26 +01:00
color = [ self folderPropertyValueInCategory : @ "FolderColors" ] ;
2008-04-22 01:03:48 +02:00
if ( ! color )
color = defaultColor ;
return color ;
}
- ( void ) setCalendarColor : ( NSString * ) newColor
{
2010-03-10 22:53:26 +01:00
if ( ! [ newColor length ] )
newColor = nil ;
[ self setFolderPropertyValue : newColor
inCategory : @ "FolderColors" ] ;
2008-04-22 01:03:48 +02:00
}
2009-07-21 20:06:55 +02:00
- ( BOOL ) showCalendarAlarms
{
2010-03-10 22:53:26 +01:00
NSNumber * showAlarms ;
showAlarms = [ self folderPropertyValueInCategory : @ "FolderShowAlarms" ] ;
return ( showAlarms ? [ showAlarms boolValue ] : YES ) ;
2009-07-21 20:06:55 +02:00
}
- ( void ) setShowCalendarAlarms : ( BOOL ) new
{
2010-03-10 22:53:26 +01:00
NSNumber * showAlarms ;
2009-08-18 03:03:05 +02:00
if ( new )
2010-03-10 22:53:26 +01:00
showAlarms = nil ;
2009-08-18 03:03:05 +02:00
else
2010-03-10 22:53:26 +01:00
showAlarms = [ NSNumber numberWithBool : NO ] ;
[ self setFolderPropertyValue : showAlarms
inCategory : @ "FolderShowAlarms" ] ;
2009-07-21 20:06:55 +02:00
}
- ( BOOL ) showCalendarTasks
{
2010-03-10 22:53:26 +01:00
NSNumber * showTasks ;
showTasks = [ self folderPropertyValueInCategory : @ "FolderShowTasks" ] ;
return ( showTasks ? [ showTasks boolValue ] : YES ) ;
2009-07-21 20:06:55 +02:00
}
- ( void ) setShowCalendarTasks : ( BOOL ) new
{
2010-03-10 22:53:26 +01:00
NSNumber * showTasks ;
/ * the default value is "YES" , so we keep only those with a value of "NO" . . . * /
2009-08-18 03:03:05 +02:00
if ( new )
2010-03-10 22:53:26 +01:00
showTasks = nil ;
2009-08-18 03:03:05 +02:00
else
2010-03-10 22:53:26 +01:00
showTasks = [ NSNumber numberWithBool : NO ] ;
[ self setFolderPropertyValue : showTasks
inCategory : @ "FolderShowTasks" ] ;
2009-07-21 20:06:55 +02:00
}
2017-05-30 15:26:30 +02:00
- ( BOOL ) subscribeUserOrGroup : ( NSString * ) theIdentifier
reallyDo : ( BOOL ) reallyDo
response : ( WOResponse * ) theResponse
{
NSMutableDictionary * moduleSettings , * folderShowAlarms , * freeBusyExclusions ;
2019-12-04 10:37:08 +01:00
NSString * subscriptionPointer , * domain ;
2017-05-30 15:26:30 +02:00
NSMutableArray * allUsers ;
SOGoUserSettings * us ;
2020-07-01 22:58:16 +02:00
SOGoUser * sogoUser ;
2017-05-30 15:26:30 +02:00
NSDictionary * dict ;
BOOL rc ;
int i ;
rc = [ super subscribeUserOrGroup : theIdentifier reallyDo : reallyDo response : theResponse ] ;
if ( rc )
{
2019-11-26 15:29:02 +01:00
# warning Duplicated code from SOGoGCSFolder subscribeUserOrGroup
2019-12-04 10:37:08 +01:00
domain = [ [ context activeUser ] domain ] ;
dict = [ [ SOGoUserManager sharedUserManager ] contactInfosForUserWithUIDorEmail : theIdentifier
inDomain : domain ] ;
2019-11-26 22:20:28 +01:00
if ( dict && [ [ dict objectForKey : @ "isGroup" ] boolValue ] )
{
id < SOGoSource > source ;
source = [ [ SOGoUserManager sharedUserManager ] sourceWithID : [ dict objectForKey : @ "SOGoSource" ] ] ;
2019-12-04 10:37:08 +01:00
if ( [ source conformsToProtocol : @ protocol ( SOGoMembershipSource ) ] )
2019-11-26 22:20:28 +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 ] ;
2019-11-26 22:20:28 +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 22:20:28 +01:00
}
2020-05-26 15:25:25 +02:00
else
{
2020-05-28 20:02:09 +02:00
[ self errorWithFormat : @ "Inconsistency 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 ;
}
2019-11-26 22:20:28 +01:00
}
else
{
2020-07-01 22:58:16 +02:00
sogoUser = [ SOGoUser userWithLogin : theIdentifier roles : nil ] ;
if ( sogoUser )
allUsers = [ NSArray arrayWithObject : sogoUser ] ;
2019-11-26 22:20:28 +01:00
else
allUsers = [ NSArray array ] ;
}
2017-05-30 15:26:30 +02:00
for ( i = 0 ; i < [ allUsers count ] ; i + + )
{
2020-07-01 22:58:16 +02:00
sogoUser = [ allUsers objectAtIndex : i ] ;
us = [ sogoUser userSettings ] ;
2017-05-30 15:26:30 +02:00
moduleSettings = [ us objectForKey : [ container nameInContainer ] ] ;
if ( ! ( moduleSettings
&& [ moduleSettings isKindOfClass : [ NSMutableDictionary class ] ] ) )
{
moduleSettings = [ NSMutableDictionary dictionary ] ;
[ us setObject : moduleSettings forKey : [ container nameInContainer ] ] ;
}
subscriptionPointer = [ self folderReference ] ;
folderShowAlarms = [ moduleSettings objectForKey : @ "FolderShowAlarms" ] ;
freeBusyExclusions = [ moduleSettings objectForKey : @ "FreeBusyExclusions" ] ;
if ( reallyDo )
{
if ( ! ( folderShowAlarms
&& [ folderShowAlarms isKindOfClass : [ NSMutableDictionary class ] ] ) )
{
folderShowAlarms = [ NSMutableDictionary dictionary ] ;
[ moduleSettings setObject : folderShowAlarms
forKey : @ "FolderShowAlarms" ] ;
}
// By default , we disable alarms on subscribed calendars
[ folderShowAlarms setObject : [ NSNumber numberWithBool : NO ]
forKey : subscriptionPointer ] ;
}
else
{
[ folderShowAlarms removeObjectForKey : subscriptionPointer ] ;
[ freeBusyExclusions removeObjectForKey : subscriptionPointer ] ;
}
[ us synchronize ] ;
rc = YES ;
}
}
return rc ;
}
2014-12-11 16:01:21 +01:00
//
// If the user is the owner of the calendar , by default we include the freebusy information .
//
2017-01-26 17:52:58 +01:00
// If the user is NOT the owner of the calendar , by default we exclude the freebusy information .
2014-12-11 16:01:21 +01:00
//
2014-12-23 16:24:16 +01:00
// We must include the freebusy information of other users if we are actually looking at their freebusy information
// but we aren ' t necessarily subscribed to their calendars .
//
2010-05-06 21:30:14 +02:00
- ( BOOL ) includeInFreeBusy
{
NSNumber * excludeFromFreeBusy ;
2017-04-27 15:02:46 +02:00
NSString * userLogin , * ownerInContext ;
2017-01-26 17:52:58 +01:00
BOOL is_owner ;
2014-12-11 16:01:21 +01:00
userLogin = [ [ context activeUser ] login ] ;
2017-04-27 15:02:46 +02:00
ownerInContext = [ [ self container ] ownerInContext : context ] ;
is_owner = [ userLogin isEqualToString : ownerInContext ] ;
2010-05-06 21:30:14 +02:00
2017-04-27 15:02:46 +02:00
if ( is_owner )
excludeFromFreeBusy
= [ self folderPropertyValueInCategory : @ "FreeBusyExclusions"
forUser : [ context activeUser ] ] ;
else
excludeFromFreeBusy
= [ self folderPropertyValueInCategory : @ "FreeBusyExclusions"
forUser : [ SOGoUser userWithLogin : ownerInContext ] ] ;
2018-09-13 21:56:31 +02:00
// User has no setting for freebusy inclusion / exclusion ,
2017-05-30 15:26:30 +02:00
// * include it if it ' s a personal folder ;
// * exclude it if it ' s a subscription .
2017-04-27 15:02:46 +02:00
if ( ! excludeFromFreeBusy )
2017-05-30 15:26:30 +02:00
{
if ( [ self isSubscription ] )
return NO ;
else
return YES ;
}
2014-12-23 16:25:53 +01:00
2017-04-27 15:02:46 +02:00
return ! [ excludeFromFreeBusy boolValue ] ;
2010-05-06 21:30:14 +02:00
}
- ( void ) setIncludeInFreeBusy : ( BOOL ) newInclude
{
NSNumber * excludeFromFreeBusy ;
excludeFromFreeBusy = [ NSNumber numberWithBool : ! newInclude ] ;
[ self setFolderPropertyValue : excludeFromFreeBusy
inCategory : @ "FreeBusyExclusions" ] ;
}
2012-07-10 02:29:13 +02:00
- ( BOOL ) _notificationValueForKey : ( NSString * ) theKey
defaultDomainKey : ( NSString * ) theDomainKey
{
SOGoUser * ownerUser ;
NSNumber * notify ;
ownerUser = [ SOGoUser userWithLogin : self -> owner ] ;
notify = [ self folderPropertyValueInCategory : theKey
forUser : ownerUser ] ;
if ( ! notify && theDomainKey )
notify = [ NSNumber numberWithBool : [ [ [ context activeUser ] domainDefaults ]
boolForKey : theDomainKey ] ] ;
return [ notify boolValue ] ;
}
//
// We MUST keep the ' NO ' value here , because we will always
// fallback to the domain defaults otherwise .
//
2012-07-12 17:03:38 +02:00
- ( void ) _setNotificationValue : ( BOOL ) b
2012-07-10 02:29:13 +02:00
forKey : ( NSString * ) theKey
{
[ self setFolderPropertyValue : [ NSNumber numberWithBool : b ]
inCategory : theKey ] ;
}
- ( BOOL ) notifyOnPersonalModifications
{
return [ self _notificationValueForKey : @ "NotifyOnPersonalModifications"
defaultDomainKey : @ "SOGoNotifyOnPersonalModifications" ] ;
}
- ( void ) setNotifyOnPersonalModifications : ( BOOL ) b
{
[ self _setNotificationValue : b forKey : @ "NotifyOnPersonalModifications" ] ;
}
- ( BOOL ) notifyOnExternalModifications
{
return [ self _notificationValueForKey : @ "NotifyOnExternalModifications"
defaultDomainKey : @ "SOGoNotifyOnExternalModifications" ] ;
}
- ( void ) setNotifyOnExternalModifications : ( BOOL ) b
{
[ self _setNotificationValue : b forKey : @ "NotifyOnExternalModifications" ] ;
}
- ( BOOL ) notifyUserOnPersonalModifications
{
return [ self _notificationValueForKey : @ "NotifyUserOnPersonalModifications"
defaultDomainKey : nil ] ;
}
- ( void ) setNotifyUserOnPersonalModifications : ( BOOL ) b
{
[ self _setNotificationValue : b forKey : @ "NotifyUserOnPersonalModifications" ] ;
}
- ( NSString * ) notifiedUserOnPersonalModifications
{
SOGoUser * ownerUser ;
ownerUser = [ SOGoUser userWithLogin : self -> owner ] ;
return [ self folderPropertyValueInCategory : @ "NotifiedUserOnPersonalModifications"
forUser : ownerUser ] ;
}
- ( void ) setNotifiedUserOnPersonalModifications : ( NSString * ) theUser
{
[ self setFolderPropertyValue : theUser
inCategory : @ "NotifiedUserOnPersonalModifications" ] ;
}
2006-06-15 21:34:10 +02:00
/ * selection * /
2006-08-16 00:04:37 +02:00
- ( NSArray * ) calendarUIDs
{
2006-06-15 21:34:10 +02:00
/ * this is used for group calendars ( this folder just returns itself ) * /
NSString * s ;
s = [ [ self container ] nameInContainer ] ;
2007-04-11 21:08:58 +02:00
// [ self logWithFormat : @ "CAL UID: %@" , s ] ;
2006-06-15 21:34:10 +02:00
return [ s isNotNull ] ? [ NSArray arrayWithObjects : & s count : 1 ] : nil ;
}
2008-06-13 22:22:51 +02:00
/ * fetching * /
2008-03-18 18:26:34 +01:00
2008-06-13 22:22:51 +02:00
- ( NSString * ) _sqlStringRangeFrom : ( NSCalendarDate * ) _startDate
to : ( NSCalendarDate * ) _endDate
2012-04-19 15:17:16 +02:00
cycle : ( BOOL ) _isCycle
2006-09-27 00:27:34 +02:00
{
2012-04-19 15:17:16 +02:00
NSString * format ;
2008-06-13 22:22:51 +02:00
unsigned int start , end ;
2006-09-27 00:27:34 +02:00
2008-06-13 22:22:51 +02:00
start = ( unsigned int ) [ _startDate timeIntervalSince1970 ] ;
end = ( unsigned int ) [ _endDate timeIntervalSince1970 ] ;
2006-09-27 00:27:34 +02:00
2009-06-09 19:50:25 +02:00
// vTODOs don ' t necessarily have start / end dates
2012-04-19 15:17:16 +02:00
if ( _isCycle )
format = ( @ "(c_startdate = NULL OR c_startdate <= %u)"
@ " AND (c_cycleenddate = NULL OR c_cycleenddate >= %u)" ) ;
else
format = ( @ "(c_startdate = NULL OR c_startdate <= %u)"
@ " AND (c_enddate = NULL OR c_enddate >= %u)" ) ;
return [ NSString stringWithFormat : format , end , start ] ;
2008-03-18 18:26:34 +01:00
}
2010-06-01 20:12:01 +02:00
- ( NSString * ) aclSQLListingFilter
2008-03-18 18:26:34 +01:00
{
2010-06-01 20:12:01 +02:00
NSString * filter ;
2009-06-16 23:35:23 +02:00
NSMutableArray * grantedClasses , * deniedClasses ;
NSNumber * classNumber ;
unsigned int grantedCount ;
iCalAccessClass currentClass ;
2015-12-30 15:22:08 +01:00
WOContext * localContext ;
/ * FIXME : The stored context from initialisation may have changed
by setContext by other operations in OpenChange library ,
so we keep tighly to use the current session one . Without
this , the login is set to nil and a NSException is raised
at [ SOGoAppointmentFolder : roleForComponentsWithAccessClass : forUser ]
inside [ SOGoAppointmentFolder : initializeQuickTablesAclsInContext ] . * /
localContext = [ [ WOApplication application ] context ] ;
[ self initializeQuickTablesAclsInContext : localContext ] ;
2010-06-01 20:12:01 +02:00
grantedClasses = [ NSMutableArray arrayWithCapacity : 3 ] ;
deniedClasses = [ NSMutableArray arrayWithCapacity : 3 ] ;
for ( currentClass = 0 ;
currentClass < iCalAccessClassCount ; currentClass + + )
2008-03-18 18:26:34 +01:00
{
2010-06-01 20:12:01 +02:00
classNumber = [ NSNumber numberWithInt : currentClass ] ;
if ( userCanAccessObjectsClassifiedAs [ currentClass ] )
[ grantedClasses addObject : classNumber ] ;
2009-06-17 17:19:33 +02:00
else
2010-06-01 20:12:01 +02:00
[ deniedClasses addObject : classNumber ] ;
2008-03-18 18:26:34 +01:00
}
2010-06-01 20:12:01 +02:00
grantedCount = [ grantedClasses count ] ;
if ( grantedCount = = 3 )
2014-02-06 20:21:36 +01:00
{
// User have access to all three classifications
filter = @ "" ;
}
2010-06-01 20:12:01 +02:00
else if ( grantedCount = = 2 )
2014-02-06 20:21:36 +01:00
{
// User has access to all but one of the classifications
filter = [ NSString stringWithFormat : @ "c_classification != %@" ,
[ deniedClasses objectAtIndex : 0 ] ] ;
}
2010-06-01 20:12:01 +02:00
else if ( grantedCount = = 1 )
2014-02-06 20:21:36 +01:00
{
// User has access to only one classification
filter = [ NSString stringWithFormat : @ "c_classification = %@" ,
[ grantedClasses objectAtIndex : 0 ] ] ;
}
2010-06-01 20:12:01 +02:00
else
2014-02-06 20:21:36 +01:00
{
// User has access to no classification
filter = nil ;
}
2008-03-18 18:26:34 +01:00
2010-06-01 20:12:01 +02:00
return filter ;
2008-03-18 18:26:34 +01:00
}
2012-04-13 01:44:39 +02:00
- ( NSString * ) componentSQLFilter
{
NSString * filter ;
if ( [ self showCalendarTasks ] )
filter = nil ;
else
filter = @ "c_component != 'vtodo'" ;
return filter ;
}
2012-04-12 22:24:15 +02:00
- ( BOOL ) _checkIfWeCanRememberRecords : ( NSArray * ) fields
{
return ( [ fields containsObject : @ "c_name" ]
&& [ fields containsObject : @ "c_version" ]
&& [ fields containsObject : @ "c_lastmodified" ]
&& [ fields containsObject : @ "c_creationdate" ]
&& [ fields containsObject : @ "c_component" ] ) ;
}
- ( void ) _rememberRecords : ( NSArray * ) records
{
NSEnumerator * recordsEnum ;
NSDictionary * currentRecord ;
recordsEnum = [ records objectEnumerator ] ;
while ( ( currentRecord = [ recordsEnum nextObject ] ) )
[ childRecords setObject : currentRecord
forKey : [ currentRecord objectForKey : @ "c_name" ] ] ;
}
2012-04-13 16:04:42 +02:00
# warning filters should make use of EOQualifier
2008-06-13 22:22:51 +02:00
- ( NSArray * ) bareFetchFields : ( NSArray * ) fields
2009-06-02 17:28:42 +02:00
from : ( NSCalendarDate * ) startDate
to : ( NSCalendarDate * ) endDate
title : ( NSString * ) title
2009-06-17 20:07:23 +02:00
component : ( NSString * ) component
2009-06-02 17:28:42 +02:00
additionalFilters : ( NSString * ) filters
2008-03-18 18:26:34 +01:00
{
2008-06-13 22:22:51 +02:00
EOQualifier * qualifier ;
GCSFolder * folder ;
2012-04-12 22:24:15 +02:00
NSMutableArray * baseWhere ;
NSString * where , * privacySQLString ;
2010-06-01 20:12:01 +02:00
NSArray * records ;
2008-03-18 18:26:34 +01:00
2008-06-13 22:22:51 +02:00
folder = [ self ocsFolder ] ;
2012-04-12 22:24:15 +02:00
baseWhere = [ NSMutableArray arrayWithCapacity : 32 ] ;
2008-06-13 22:22:51 +02:00
if ( startDate && endDate )
2012-04-19 15:17:16 +02:00
[ baseWhere addObject : [ self _sqlStringRangeFrom : startDate to : endDate
cycle : NO ] ] ;
2008-06-13 22:22:51 +02:00
if ( [ title length ] )
2012-04-12 22:24:15 +02:00
[ baseWhere
addObject : [ NSString stringWithFormat : @ "c_title isCaseInsensitiveLike: '%%%@%%'" ,
2016-12-09 16:45:44 +01:00
[ title asSafeSQLString ] ] ] ;
2008-03-18 18:26:34 +01:00
2009-06-17 20:07:23 +02:00
if ( component )
2012-04-13 01:45:23 +02:00
{
if ( [ component isEqualToString : @ "vtodo" ] && ! [ self showCalendarTasks ] )
return [ NSArray array ] ;
else
[ baseWhere addObject : [ NSString stringWithFormat : @ "c_component = '%@'" ,
component ] ] ;
}
else if ( ! [ self showCalendarTasks ] )
[ baseWhere addObject : @ "c_component != 'vtodo'" ] ;
2012-04-12 22:24:15 +02:00
2009-06-16 23:35:23 +02:00
if ( [ filters length ] )
2012-04-12 22:24:15 +02:00
[ baseWhere addObject : filters ] ;
2008-03-18 18:26:34 +01:00
2010-06-01 20:12:01 +02:00
privacySQLString = [ self aclSQLListingFilter ] ;
if ( privacySQLString )
{
if ( [ privacySQLString length ] )
2012-04-12 22:24:15 +02:00
[ baseWhere addObject : privacySQLString ] ;
2009-06-16 23:35:23 +02:00
2010-06-01 20:12:01 +02:00
/ * sql is empty when we fetch everything ( all parameters are nil ) * /
2012-04-12 22:24:15 +02:00
if ( [ baseWhere count ] > 0 )
2011-11-28 17:37:04 +01:00
{
2012-04-12 22:24:15 +02:00
where = [ baseWhere componentsJoinedByString : @ " AND " ] ;
qualifier = [ EOQualifier qualifierWithQualifierFormat : where ] ;
2011-11-28 17:37:04 +01:00
}
2010-06-01 20:12:01 +02:00
else
2011-11-28 17:37:04 +01:00
qualifier = nil ;
2006-09-27 00:27:34 +02:00
2010-06-01 20:12:01 +02:00
/ * fetch non - recurrent apts first * /
records = [ folder fetchFields : fields matchingQualifier : qualifier ] ;
}
2009-09-24 16:29:24 +02:00
else
2010-06-01 20:12:01 +02:00
records = [ NSArray array ] ;
2012-01-27 16:21:51 +01:00
if ( [ self _checkIfWeCanRememberRecords : fields ] )
2012-04-12 22:24:15 +02:00
[ self _rememberRecords : records ] ;
2008-03-18 18:26:34 +01:00
2010-06-01 20:12:01 +02:00
return records ;
2008-03-18 18:26:34 +01:00
}
2011-01-14 03:54:33 +01:00
/ * *
* Set the timezone of the event start and end dates to the user ' s timezone .
2015-04-26 13:33:03 +02:00
* @ param theRecord a dictionary with the attributes of the event .
2011-01-14 03:54:33 +01:00
* @ return a copy of theRecord with adjusted dates .
* /
2014-09-12 14:34:15 +02:00
- ( NSMutableDictionary * ) _fixupRecord : ( NSDictionary * ) theRecord
2008-05-16 17:52:19 +02:00
{
2011-01-14 03:54:33 +01:00
NSMutableDictionary * record ;
2008-06-19 20:31:18 +02:00
static NSString * fields [ ] = { @ "c_startdate" , @ "startDate" ,
@ "c_enddate" , @ "endDate" } ;
unsigned int count ;
NSCalendarDate * date ;
NSNumber * dateValue ;
2013-01-21 20:11:38 +01:00
BOOL isAllDay ;
2016-04-11 21:55:12 +02:00
NSInteger offset ;
2008-06-19 20:31:18 +02:00
2013-01-21 20:11:38 +01:00
isAllDay = [ [ theRecord objectForKey : @ "c_isallday" ] boolValue ] ;
2011-01-14 03:54:33 +01:00
record = [ [ theRecord mutableCopy ] autorelease ] ;
2008-06-19 20:31:18 +02:00
for ( count = 0 ; count < 2 ; count + + )
{
2011-01-14 03:54:33 +01:00
dateValue = [ theRecord objectForKey : fields [ count * 2 ] ] ;
2008-06-19 20:31:18 +02:00
if ( dateValue )
{
2008-08-10 19:14:56 +02:00
date = [ NSCalendarDate dateWithTimeIntervalSince1970 : [ dateValue unsignedIntValue ] ] ;
2008-06-19 20:31:18 +02:00
if ( date )
{
[ date setTimeZone : timeZone ] ;
2013-01-21 20:11:38 +01:00
if ( isAllDay )
2011-03-10 23:21:53 +01:00
{
// Since there ' s no timezone associated to all - day events ,
// their time must be adjusted for the user ' s timezone .
offset = [ timeZone secondsFromGMTForDate : date ] ;
date = ( NSCalendarDate * ) [ date dateByAddingYears : 0 months : 0 days : 0 hours : 0 minutes : 0
seconds : - offset ] ;
[ record setObject : [ NSNumber numberWithInt : [ dateValue intValue ] - offset ] forKey : fields [ count * 2 ] ] ;
}
2011-01-14 03:54:33 +01:00
[ record setObject : date forKey : fields [ count * 2 + 1 ] ] ;
2008-06-19 20:31:18 +02:00
}
}
else
2008-07-16 23:47:18 +02:00
[ self logWithFormat : @ "missing '%@' in record?" , fields [ count * 2 ] ] ;
2008-06-19 20:31:18 +02:00
}
2008-05-16 17:52:19 +02:00
2011-01-14 03:54:33 +01:00
return record ;
2008-05-16 17:52:19 +02:00
}
2011-04-25 12:31:08 +02:00
//
//
//
2014-09-12 14:34:15 +02:00
- ( NSArray * ) _fixupRecords : ( NSArray * ) theRecords
2006-10-17 21:57:14 +02:00
{
2008-06-13 22:22:51 +02:00
// TODO : is the result supposed to be sorted by date ?
NSMutableArray * ma ;
unsigned count , max ;
2014-09-12 14:34:15 +02:00
id row ;
2006-10-17 21:57:14 +02:00
2009-03-16 22:21:43 +01:00
if ( theRecords )
2006-10-17 21:57:14 +02:00
{
2009-03-16 22:21:43 +01:00
max = [ theRecords count ] ;
2008-06-13 22:22:51 +02:00
ma = [ NSMutableArray arrayWithCapacity : max ] ;
for ( count = 0 ; count < max ; count + + )
{
2014-09-12 14:34:15 +02:00
row = [ self _fixupRecord : [ theRecords objectAtIndex : count ] ] ;
2008-06-13 22:22:51 +02:00
if ( row )
[ ma addObject : row ] ;
}
2006-10-17 21:57:14 +02:00
}
else
2008-06-13 22:22:51 +02:00
ma = nil ;
return ma ;
}
2011-01-14 03:54:33 +01:00
/ * *
* Adjust the timezone of the start and end dates to the user ' s timezone .
* The event is recurrent and the dates must first be adjusted with respect to
* the event ' s timezone .
* @ param theRecord
* @ param theCycle
* @ param theFirstCycle
* @ param theEventTimeZone
* @ see fixupRecord :
* @ return a copy of theRecord with adjusted dates .
* /
- ( NSMutableDictionary * ) fixupCycleRecord : ( NSDictionary * ) theRecord
cycleRange : ( NGCalendarDateRange * ) theCycle
firstInstanceCalendarDateRange : ( NGCalendarDateRange * ) theFirstCycle
withEventTimeZone : ( iCalTimeZone * ) theEventTimeZone
{
NSMutableDictionary * record ;
2008-07-17 23:12:43 +02:00
NSNumber * dateSecs ;
2011-01-14 03:54:33 +01:00
id date ;
int secondsOffsetFromGMT ;
record = [ [ theRecord mutableCopy ] autorelease ] ;
date = [ theCycle startDate ] ;
2011-02-23 17:33:29 +01:00
if ( theEventTimeZone )
{
secondsOffsetFromGMT = ( int ) [ [ theEventTimeZone periodForDate : date ] secondsOffsetFromGMT ] ;
date = [ date dateByAddingYears : 0 months : 0 days : 0 hours : 0 minutes : 0 seconds : - secondsOffsetFromGMT ] ;
}
2011-01-14 03:54:33 +01:00
[ date setTimeZone : timeZone ] ;
[ record setObject : date forKey : @ "startDate" ] ;
dateSecs = [ NSNumber numberWithInt : [ date timeIntervalSince1970 ] ] ;
[ record setObject : dateSecs forKey : @ "c_startdate" ] ;
2013-01-21 20:11:38 +01:00
if ( [ [ record valueForKey : @ "c_isallday" ] boolValue ] )
{
// Refer to all - day recurrence id by their GMT - based start date
date = [ theCycle startDate ] ;
secondsOffsetFromGMT = ( int ) [ [ date timeZone ] secondsFromGMTForDate : date ] ;
date = [ date dateByAddingYears : 0 months : 0 days : 0 hours : 0 minutes : 0 seconds : secondsOffsetFromGMT ] ;
dateSecs = [ NSNumber numberWithInt : [ date timeIntervalSince1970 ] ] ;
}
2011-01-14 03:54:33 +01:00
[ record setObject : dateSecs forKey : @ "c_recurrence_id" ] ;
2016-10-24 22:31:59 +02:00
date = [ record valueForKey : @ "c_enddate" ] ;
if ( [ date isNotNull ] )
2011-02-23 17:33:29 +01:00
{
2016-10-24 22:31:59 +02:00
date = [ theCycle endDate ] ;
if ( theEventTimeZone )
{
secondsOffsetFromGMT = ( int ) [ [ theEventTimeZone periodForDate : date ] secondsOffsetFromGMT ] ;
date = [ date dateByAddingYears : 0 months : 0 days : 0 hours : 0 minutes : 0 seconds : - secondsOffsetFromGMT ] ;
}
[ date setTimeZone : timeZone ] ;
[ record setObject : date forKey : @ "endDate" ] ;
dateSecs = [ NSNumber numberWithInt : [ date timeIntervalSince1970 ] ] ;
[ record setObject : dateSecs forKey : @ "c_enddate" ] ;
2011-02-23 17:33:29 +01:00
}
2016-10-24 22:31:59 +02:00
else
[ record removeObjectForKey : @ "endDate" ] ;
2008-06-13 22:22:51 +02:00
2011-01-14 03:54:33 +01:00
return record ;
2008-06-13 22:22:51 +02:00
}
2014-09-12 14:34:15 +02:00
//
//
//
2008-07-12 00:28:12 +02:00
- ( int ) _indexOfRecordMatchingDate : ( NSCalendarDate * ) matchDate
inArray : ( NSArray * ) recordArray
{
int count , max , recordIndex ;
NSDictionary * currentRecord ;
recordIndex = -1 ;
count = 0 ;
max = [ recordArray count ] ;
while ( recordIndex = = -1 && count < max )
{
currentRecord = [ recordArray objectAtIndex : count ] ;
if ( [ [ currentRecord objectForKey : @ "startDate" ]
2012-06-04 17:29:38 +02:00
compare : matchDate ] = = NSOrderedSame )
2008-07-12 00:28:12 +02:00
recordIndex = count ;
2008-07-14 17:14:40 +02:00
else
count + + ;
2008-07-12 00:28:12 +02:00
}
return recordIndex ;
}
2014-09-12 14:34:15 +02:00
//
//
//
2008-07-12 00:28:12 +02:00
- ( void ) _fixExceptionRecord : ( NSMutableDictionary * ) recRecord
fromRow : ( NSDictionary * ) row
{
NSArray * objects ;
static NSArray * fields = nil ;
if ( ! fields )
{
fields = [ NSArray arrayWithObjects : @ "c_name" , nil ] ;
[ fields retain ] ;
}
objects = [ row objectsForKeys : fields notFoundMarker : @ "" ] ;
[ recRecord setObjects : objects forKeys : fields ] ;
}
2014-09-12 14:34:15 +02:00
//
//
//
- ( void ) _computeAlarmForRow : ( NSMutableDictionary * ) row
master : ( iCalEntityObject * ) master
{
iCalEntityObject * component ;
iCalAlarm * alarm ;
if ( ! [ master recurrenceId ] )
{
component = [ master copy ] ;
[ component setStartDate : [ NSCalendarDate dateWithTimeIntervalSince1970 : [ [ row objectForKey : @ "c_startdate" ] intValue ] ] ] ;
if ( [ component isKindOfClass : [ iCalEvent class ] ] )
{
[ ( iCalEvent * ) component setEndDate : [ NSCalendarDate dateWithTimeIntervalSince1970 : [ [ row objectForKey : @ "c_enddate" ] intValue ] ] ] ;
}
else
{
[ ( iCalToDo * ) component setDue : [ NSCalendarDate dateWithTimeIntervalSince1970 : [ [ row objectForKey : @ "c_enddate" ] intValue ] ] ] ;
}
}
else
{
component = master ;
RETAIN ( component ) ;
}
// Check if we have any alarm , that could happen for recurrence exceptions with no
// alarm defined .
if ( [ [ component alarms ] count ] )
{
2016-11-02 23:16:45 +01:00
alarm = [ component firstSupportedAlarm ] ;
2014-09-12 14:34:15 +02:00
[ row setObject : [ NSNumber numberWithInt : [ [ alarm nextAlarmDate ] timeIntervalSince1970 ] ]
forKey : @ "c_nextalarm" ] ;
}
RELEASE ( component ) ;
}
//
//
//
2008-07-12 00:28:12 +02:00
- ( void ) _appendCycleException : ( iCalRepeatableEntityObject * ) component
2008-12-30 15:47:58 +01:00
firstInstanceCalendarDateRange : ( NGCalendarDateRange * ) fir
2008-07-12 00:28:12 +02:00
fromRow : ( NSDictionary * ) row
forRange : ( NGCalendarDateRange * ) dateRange
2014-09-12 14:34:15 +02:00
withTimeZone : ( NSTimeZone * ) tz
toArray : ( NSMutableArray * ) ma
2008-07-12 00:28:12 +02:00
{
2016-08-05 20:53:38 +02:00
NGCalendarDateRange * recurrenceIdRange ;
2016-10-24 22:31:59 +02:00
NSCalendarDate * recurrenceId , * masterEndDate , * endDate ;
2008-07-12 00:28:12 +02:00
NSMutableDictionary * newRecord ;
NGCalendarDateRange * newRecordRange ;
2013-02-15 21:17:08 +01:00
NSNumber * dateSecs ;
2016-08-05 20:53:38 +02:00
id master ;
int recordIndex , secondsOffsetFromGMT ;
NSTimeInterval delta ;
2008-07-12 00:28:12 +02:00
newRecord = nil ;
recurrenceId = [ component recurrenceId ] ;
2013-01-21 20:11:38 +01:00
2012-07-20 21:07:03 +02:00
if ( ! recurrenceId )
{
[ self errorWithFormat : @ "ignored component with an empty EXCEPTION-ID" ] ;
return ;
}
2008-12-30 15:47:58 +01:00
2012-06-04 17:29:38 +02:00
if ( tz )
{
// The following adjustment is necessary for floating all - day events .
// For example , the recurrence - id 20120523 T000000Z for timezone -0400
// will become 20120523 T000400Z
secondsOffsetFromGMT = [ tz secondsFromGMTForDate : recurrenceId ] ;
recurrenceId = ( NSCalendarDate * ) [ recurrenceId dateByAddingYears : 0 months : 0 days : 0 hours : 0 minutes : 0
seconds : - secondsOffsetFromGMT ] ;
2013-01-21 20:11:38 +01:00
[ recurrenceId setTimeZone : tz ] ;
2012-06-04 17:29:38 +02:00
}
2016-10-24 22:31:59 +02:00
if ( [ component isKindOfClass : [ iCalEvent class ] ] )
{
master = [ [ [ component parent ] events ] objectAtIndex : 0 ] ;
masterEndDate = [ master endDate ] ;
2016-11-01 19:52:18 +01:00
endDate = [ ( iCalEvent * ) component endDate ] ;
2016-10-24 22:31:59 +02:00
}
else
{
master = [ [ [ component parent ] todos ] objectAtIndex : 0 ] ;
masterEndDate = [ master due ] ;
2016-11-01 19:52:18 +01:00
endDate = [ ( iCalToDo * ) component due ] ;
2016-10-24 22:31:59 +02:00
}
2019-09-03 19:34:35 +02:00
if ( ! [ master startDate ] )
{
[ self errorWithFormat : @ "ignored component with no DTSTART" ] ;
return ;
}
2016-10-24 22:31:59 +02:00
delta = [ masterEndDate timeIntervalSinceDate : [ master startDate ] ] ;
2016-08-05 20:53:38 +02:00
recurrenceIdRange = [ NGCalendarDateRange calendarDateRangeWithStartDate : recurrenceId
endDate : [ recurrenceId dateByAddingYears : 0 months : 0 days : 0 hours : 0 minutes : 0 seconds : delta ] ] ;
if ( [ dateRange doesIntersectWithDateRange : recurrenceIdRange ] )
2008-07-12 00:28:12 +02:00
{
2013-02-15 21:17:08 +01:00
// The recurrence exception intersects with the date range ;
// find the occurence and replace it with the new record
recordIndex = [ self _indexOfRecordMatchingDate : recurrenceId inArray : ma ] ;
2008-07-12 00:28:12 +02:00
if ( recordIndex > -1 )
{
2016-08-05 20:53:38 +02:00
if ( [ dateRange containsDate : [ component startDate ] ] ||
2016-11-01 19:52:18 +01:00
( endDate && [ dateRange containsDate : endDate ] ) )
2016-10-24 22:31:59 +02:00
{
2015-11-05 15:59:31 +01:00
// We must pass nil to : container here in order to avoid re - entrancy issues .
2016-11-02 23:16:45 +01:00
newRecord = [ self _fixupRecord : [ component quickRecordFromContent : nil container : nil nameInContainer : nil ] ] ;
2013-02-15 21:17:08 +01:00
[ ma replaceObjectAtIndex : recordIndex withObject : newRecord ] ;
}
else
// The range doesn ' t cover the exception ; remove it from the records
[ ma removeObjectAtIndex : recordIndex ] ;
}
2008-07-12 00:28:12 +02:00
else
[ self errorWithFormat :
2011-03-30 01:25:40 +02:00
@ "missing exception record for recurrence-id %@ (uid %@)" ,
recurrenceId , [ component uid ] ] ;
2008-07-12 00:28:12 +02:00
}
else
{
2013-02-15 21:17:08 +01:00
// The recurrence id of the exception is outside the date range ;
2014-09-12 14:34:15 +02:00
// simply add the exception to the records array .
2015-11-05 15:59:31 +01:00
// We must pass nil to : container here in order to avoid re - entrancy issues .
2016-11-02 23:16:45 +01:00
newRecord = [ self _fixupRecord : [ component quickRecordFromContent : nil container : nil nameInContainer : nil ] ] ;
2015-11-05 15:59:31 +01:00
if ( [ newRecord objectForKey : @ "startDate" ] && [ newRecord objectForKey : @ "endDate" ] ) {
newRecordRange = [ NGCalendarDateRange
calendarDateRangeWithStartDate : [ newRecord objectForKey : @ "startDate" ]
endDate : [ newRecord objectForKey : @ "endDate" ] ] ;
if ( [ dateRange doesIntersectWithDateRange : newRecordRange ] )
2013-02-15 21:17:08 +01:00
[ ma addObject : newRecord ] ;
2015-11-05 15:59:31 +01:00
else
newRecord = nil ;
} else {
[ self warnWithFormat : @ "Recurrence %@ without dtstart or dtend. Ignoring" , recurrenceId ] ;
2013-02-15 21:17:08 +01:00
newRecord = nil ;
2015-11-05 15:59:31 +01:00
}
2008-07-12 00:28:12 +02:00
}
if ( newRecord )
2013-02-15 21:17:08 +01:00
{
recurrenceId = [ component recurrenceId ] ;
dateSecs = [ NSNumber numberWithInt : [ recurrenceId timeIntervalSince1970 ] ] ;
[ newRecord setObject : dateSecs forKey : @ "c_recurrence_id" ] ;
[ newRecord setObject : [ NSNumber numberWithInt : 1 ] forKey : @ "c_iscycle" ] ;
2015-01-15 21:29:02 +01:00
2013-02-15 21:17:08 +01:00
// We identified the record as an exception .
[ newRecord setObject : [ NSNumber numberWithInt : 1 ] forKey : @ "isException" ] ;
[ self _fixExceptionRecord : newRecord fromRow : row ] ;
}
2014-09-12 14:34:15 +02:00
// We finally adjust the c_nextalarm
[ self _computeAlarmForRow : ( id ) row
master : component ] ;
2008-07-12 00:28:12 +02:00
}
2011-04-25 12:31:08 +02:00
//
//
//
2008-07-12 00:28:12 +02:00
- ( void ) _appendCycleExceptionsFromRow : ( NSDictionary * ) row
2008-12-30 15:47:58 +01:00
firstInstanceCalendarDateRange : ( NGCalendarDateRange * ) fir
2008-07-14 17:14:40 +02:00
forRange : ( NGCalendarDateRange * ) dateRange
2012-06-04 17:29:38 +02:00
withTimeZone : ( NSTimeZone * ) tz
2014-09-12 14:34:15 +02:00
withCalendar : ( iCalCalendar * ) calendar
2008-07-14 17:14:40 +02:00
toArray : ( NSMutableArray * ) ma
2008-07-12 00:28:12 +02:00
{
2014-09-12 14:34:15 +02:00
NSArray * components ;
2008-07-12 00:28:12 +02:00
NSString * content ;
2014-09-12 14:34:15 +02:00
unsigned int count , max ;
2008-07-12 00:28:12 +02:00
content = [ row objectForKey : @ "c_content" ] ;
2014-09-12 14:34:15 +02:00
if ( ! calendar && [ content isNotNull ] )
2008-07-12 00:28:12 +02:00
{
2014-09-12 14:34:15 +02:00
calendar = [ iCalCalendar parseSingleFromSource : content ] ;
}
if ( calendar )
{
components = [ calendar allObjects ] ;
max = [ components count ] ;
for ( count = 1 ; count < max ; count + + ) // skip master event
[ self _appendCycleException : [ components objectAtIndex : count ]
firstInstanceCalendarDateRange : fir
fromRow : row
forRange : dateRange
withTimeZone : tz
toArray : ma ] ;
2008-07-12 00:28:12 +02:00
}
}
2011-01-14 03:54:33 +01:00
/ * *
* Calculate and return the occurrences of the recurrent event for the given
* period .
* @ param theRecord the event definition .
* @ param theRange the period to look in .
* @ param theRecords the array into which are copied the resulting occurrences .
2011-01-21 22:56:09 +01:00
* @ see [ iCalRepeatableEntityObject + SOGo doesOccurOnDate : ]
2011-01-14 03:54:33 +01:00
* /
2014-09-12 14:34:15 +02:00
- ( void ) flattenCycleRecord : ( NSDictionary * ) theRecord
forRange : ( NGCalendarDateRange * ) theRange
intoArray : ( NSMutableArray * ) theRecords
withCalendar : ( iCalCalendar * ) calendar
2008-06-13 22:22:51 +02:00
{
NSMutableDictionary * row , * fixedRow ;
2017-12-15 22:17:51 +01:00
NSMutableArray * records , * ranges ;
2011-01-14 03:54:33 +01:00
NSDictionary * cycleinfo ;
2011-03-30 01:25:40 +02:00
NGCalendarDateRange * firstRange , * recurrenceRange , * oneRange ;
2017-12-15 22:17:51 +01:00
NSArray * rules , * exRules , * rDates , * exDates ;
2014-09-12 14:34:15 +02:00
NSArray * components ;
2008-06-13 22:22:51 +02:00
NSString * content ;
2012-06-04 17:29:38 +02:00
NSCalendarDate * checkStartDate , * checkEndDate , * firstStartDate , * firstEndDate ;
NSTimeZone * allDayTimeZone ;
2011-04-19 22:39:12 +02:00
iCalDateTime * dtstart ;
2014-09-12 14:34:15 +02:00
iCalRepeatableEntityObject * component ;
2011-01-14 03:54:33 +01:00
iCalTimeZone * eventTimeZone ;
2017-08-14 19:59:16 +02:00
unsigned count , max ;
2017-08-14 20:25:52 +02:00
NSInteger offset ;
2012-06-04 17:29:38 +02:00
id tz ;
2008-06-13 22:22:51 +02:00
2011-01-14 03:54:33 +01:00
content = [ theRecord objectForKey : @ "c_cycleinfo" ] ;
2008-06-13 22:22:51 +02:00
if ( ! [ content isNotNull ] )
{
2017-07-19 17:05:16 +02:00
// If c_iscycle is set but c_cycleinfo is null , that means we ' re dealing with a vcalendar that
// contains ONLY one or more vevent with recurrence - id set for each of them . This can happen if
// an organizer invites an attendee only to one or many occurences of a repetitive event .
iCalCalendar * c ;
2017-10-25 21:18:28 +02:00
NSDictionary * record ;
2017-07-19 17:05:16 +02:00
c = [ iCalCalendar parseSingleFromSource : [ theRecord objectForKey : @ "c_content" ] ] ;
2017-10-25 21:18:28 +02:00
components = [ self _fixupRecords :
[ c quickRecordsFromContent : [ theRecord objectForKey : @ "c_content" ]
container : nil
nameInContainer : [ theRecord objectForKey : @ "c_name" ] ] ] ;
max = [ components count ] ;
for ( count = 0 ; count < max ; count + + )
{
record = [ components objectAtIndex : count ] ;
oneRange = [ NGCalendarDateRange calendarDateRangeWithStartDate : [ record objectForKey : @ "startDate" ]
endDate : [ record objectForKey : @ "endDate" ] ] ;
if ( [ theRange doesIntersectWithDateRange : oneRange ] )
{
[ theRecords addObject : record ] ;
}
}
2008-06-13 22:22:51 +02:00
return ;
}
cycleinfo = [ content propertyList ] ;
if ( ! cycleinfo )
{
[ self errorWithFormat : @ "cyclic record doesn't have cycleinfo -> %@" ,
2011-01-14 03:54:33 +01:00
theRecord ] ;
2008-06-13 22:22:51 +02:00
return ;
}
2011-01-14 20:07:43 +01:00
rules = [ cycleinfo objectForKey : @ "rules" ] ;
exRules = [ cycleinfo objectForKey : @ "exRules" ] ;
2017-12-15 22:17:51 +01:00
rDates = [ cycleinfo objectForKey : @ "rDates" ] ;
2011-01-14 20:07:43 +01:00
exDates = [ cycleinfo objectForKey : @ "exDates" ] ;
2012-07-12 17:03:38 +02:00
eventTimeZone = nil ;
allDayTimeZone = nil ;
tz = nil ;
2012-06-04 17:29:38 +02:00
2014-09-12 14:34:15 +02:00
row = [ self _fixupRecord : theRecord ] ;
2008-06-13 22:22:51 +02:00
[ row removeObjectForKey : @ "c_cycleinfo" ] ;
[ row setObject : sharedYes forKey : @ "isRecurrentEvent" ] ;
2011-01-14 03:54:33 +01:00
content = [ theRecord objectForKey : @ "c_content" ] ;
2014-09-12 14:34:15 +02:00
if ( ! calendar && [ content isNotNull ] )
2011-01-14 03:54:33 +01:00
{
2014-09-12 14:34:15 +02:00
calendar = [ iCalCalendar parseSingleFromSource : content ] ;
}
2011-04-19 22:39:12 +02:00
2014-09-12 14:34:15 +02:00
if ( calendar )
{
if ( [ [ theRecord objectForKey : @ "c_component" ] isEqualToString : @ "vtodo" ] )
components = [ calendar todos ] ;
else
components = [ calendar events ] ;
if ( [ components count ] )
{
// Retrieve the range of the first / master event
component = [ components objectAtIndex : 0 ] ;
dtstart = ( iCalDateTime * ) [ component uniqueChildWithTag : @ "dtstart" ] ;
firstRange = [ component firstOccurenceRange ] ; // ignores timezone
eventTimeZone = [ dtstart timeZone ] ;
if ( eventTimeZone )
{
// Adjust the range to check with respect to the event timezone ( extracted from the start date )
checkStartDate = [ eventTimeZone computedDateForDate : [ theRange startDate ] ] ;
checkEndDate = [ eventTimeZone computedDateForDate : [ theRange endDate ] ] ;
recurrenceRange = [ NGCalendarDateRange calendarDateRangeWithStartDate : checkStartDate
endDate : checkEndDate ] ;
}
else
{
recurrenceRange = theRange ;
if ( [ [ theRecord objectForKey : @ "c_isallday" ] boolValue ] )
2011-04-16 03:35:06 +02:00
{
2014-09-12 14:34:15 +02:00
// The event lasts all - day and has no timezone ( floating ) ; we convert the range of the first event
// to the user ' s timezone
allDayTimeZone = timeZone ;
offset = [ allDayTimeZone secondsFromGMTForDate : [ firstRange startDate ] ] ;
firstStartDate = [ [ firstRange startDate ] dateByAddingYears : 0 months : 0 days : 0 hours : 0 minutes : 0
2011-04-19 22:39:12 +02:00
seconds : - offset ] ;
2014-09-12 14:34:15 +02:00
firstEndDate = [ [ firstRange endDate ] dateByAddingYears : 0 months : 0 days : 0 hours : 0 minutes : 0
seconds : - offset ] ;
[ firstStartDate setTimeZone : allDayTimeZone ] ;
[ firstEndDate setTimeZone : allDayTimeZone ] ;
firstRange = [ NGCalendarDateRange calendarDateRangeWithStartDate : firstStartDate
endDate : firstEndDate ] ;
2011-04-16 03:35:06 +02:00
}
2014-09-12 14:34:15 +02:00
}
# warning this code is ugly : we should not mix objects with different types as \
2012-07-12 17:03:38 +02:00
it reduces readability
2014-09-12 14:34:15 +02:00
tz = eventTimeZone ? eventTimeZone : allDayTimeZone ;
if ( tz )
{
2017-12-15 22:17:51 +01:00
// Adjust the recurrence and exception dates
2014-09-12 14:34:15 +02:00
exDates = [ component exceptionDatesWithTimeZone : tz ] ;
2017-12-15 22:17:51 +01:00
rDates = [ component recurrenceDatesWithTimeZone : tz ] ;
2014-09-12 14:34:15 +02:00
// Adjust the recurrence rules "until" dates
rules = [ component recurrenceRulesWithTimeZone : tz ] ;
exRules = [ component exceptionRulesWithTimeZone : tz ] ;
}
// Calculate the occurrences for the given range
records = [ NSMutableArray array ] ;
2017-12-15 22:17:51 +01:00
ranges =
[ NSMutableArray arrayWithArray :
[ iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange : recurrenceRange
firstInstanceCalendarDateRange : firstRange
recurrenceRules : rules
exceptionRules : exRules
recurrenceDates : rDates
exceptionDates : exDates ] ] ;
// Add the master occurrence when dealing with RDATES .
// However , the master event must not be flagged with X - MOZ - FAKED - MASTER .
if ( [ component hasRecurrenceDates ] &&
! [ [ [ component uniqueChildWithTag : @ "x-moz-faked-master" ]
flattenedValuesForKey : @ "" ] isEqualToString : @ "1" ] &&
[ recurrenceRange doesIntersectWithDateRange : firstRange ] )
{
[ ranges insertObject : firstRange atIndex : 0 ] ;
}
2014-09-12 14:34:15 +02:00
max = [ ranges count ] ;
for ( count = 0 ; count < max ; count + + )
{
oneRange = [ ranges objectAtIndex : count ] ;
fixedRow = [ self fixupCycleRecord : row
cycleRange : oneRange
firstInstanceCalendarDateRange : firstRange
withEventTimeZone : eventTimeZone ] ;
// We now adjust the c_nextalarm based on each occurences . For each of them , we use the master event
// alarm information since exceptions to recurrence rules might have their own , while that is not the
// case for standard occurences .
if ( [ component hasAlarms ] )
2011-04-05 17:11:34 +02:00
{
2014-09-12 14:34:15 +02:00
[ self _computeAlarmForRow : fixedRow
master : component ] ;
2011-04-05 17:11:34 +02:00
}
2011-04-16 03:35:06 +02:00
2014-09-12 14:34:15 +02:00
[ records addObject : fixedRow ] ;
2011-04-16 03:35:06 +02:00
}
2014-09-12 14:34:15 +02:00
[ self _appendCycleExceptionsFromRow : row
firstInstanceCalendarDateRange : firstRange
forRange : theRange
withTimeZone : allDayTimeZone
withCalendar : calendar
toArray : records ] ;
[ theRecords addObjectsFromArray : records ] ;
} // if ( [ components count ] ) . . .
2011-01-14 03:54:33 +01:00
}
2011-03-30 04:14:56 +02:00
else
[ self errorWithFormat : @ "cyclic record doesn't have content -> %@" , theRecord ] ;
2008-06-13 22:22:51 +02:00
}
2014-09-12 14:34:15 +02:00
//
// TODO : is the result supposed to be sorted by date ?
//
2009-06-15 23:19:36 +02:00
- ( NSArray * ) _flattenCycleRecords : ( NSArray * ) _records
fetchRange : ( NGCalendarDateRange * ) _r
2008-06-13 22:22:51 +02:00
{
NSMutableArray * ma ;
NSDictionary * row ;
2008-07-12 00:28:12 +02:00
unsigned int count , max ;
2008-06-13 22:22:51 +02:00
2008-07-12 00:28:12 +02:00
max = [ _records count ] ;
ma = [ NSMutableArray arrayWithCapacity : max ] ;
2011-01-21 22:56:09 +01:00
_r = [ NGCalendarDateRange calendarDateRangeWithStartDate : [ _r startDate ]
2017-03-03 20:13:25 +01:00
endDate : [ _r endDate ] ] ;
2011-01-21 22:56:09 +01:00
2008-07-12 00:28:12 +02:00
for ( count = 0 ; count < max ; count + + )
{
row = [ _records objectAtIndex : count ] ;
2014-09-12 14:34:15 +02:00
[ self flattenCycleRecord : row forRange : _r intoArray : ma withCalendar : nil ] ;
2008-07-12 00:28:12 +02:00
}
2008-06-13 22:22:51 +02:00
return ma ;
}
2014-09-12 14:34:15 +02:00
//
//
//
2008-06-13 22:22:51 +02:00
- ( void ) _buildStripFieldsFromFields : ( NSArray * ) fields
{
stripFields = [ [ NSMutableArray alloc ] initWithCapacity : [ fields count ] ] ;
[ stripFields setArray : fields ] ;
2008-12-23 19:43:37 +01:00
// What we keep . . . .
2008-06-13 22:22:51 +02:00
[ stripFields removeObjectsInArray : [ NSArray arrayWithObjects : @ "c_name" ,
@ "c_uid" , @ "c_startdate" ,
@ "c_enddate" , @ "c_isallday" ,
2008-12-14 16:47:01 +01:00
@ "c_iscycle" , @ "c_isopaque" ,
2009-02-06 21:17:04 +01:00
@ "c_cycleinfo" ,
@ "c_cycleenddate" ,
2008-06-13 22:22:51 +02:00
@ "c_classification" ,
@ "c_component" , nil ] ] ;
}
2014-09-12 14:34:15 +02:00
//
//
//
2008-06-13 22:22:51 +02:00
- ( void ) _fixupProtectedInformation : ( NSEnumerator * ) ma
inFields : ( NSArray * ) fields
forUser : ( NSString * ) uid
{
NSMutableDictionary * currentRecord ;
NSString * roles [ ] = { nil , nil , nil } ;
iCalAccessClass accessClass ;
NSString * fullRole , * role ;
if ( ! stripFields )
[ self _buildStripFieldsFromFields : fields ] ;
# warning we do not take the participation status into account
while ( ( currentRecord = [ ma nextObject ] ) )
{
2020-04-03 18:18:16 +02:00
accessClass = [ [ currentRecord objectForKey : @ "c_classification" ] intValue ] ;
2008-06-13 22:22:51 +02:00
role = roles [ accessClass ] ;
if ( ! role )
2009-06-02 16:40:50 +02:00
{
fullRole = [ self roleForComponentsWithAccessClass : accessClass
forUser : uid ] ;
if ( [ fullRole length ] > 9 )
role = [ fullRole substringFromIndex : 9 ] ;
roles [ accessClass ] = role ;
}
2008-06-13 22:22:51 +02:00
if ( [ role isEqualToString : @ "DAndTViewer" ] )
2009-06-02 16:40:50 +02:00
[ currentRecord removeObjectsForKeys : stripFields ] ;
2008-06-13 22:22:51 +02:00
}
}
2009-06-02 19:59:06 +02:00
/ * TODO : this method should make use of bareFetchFields instead and only keep
its "intelligence" part for handling protected infos and recurrent
events . . . * /
2008-12-23 19:43:37 +01:00
- ( NSArray * ) fetchFields : ( NSArray * ) _fields
2009-06-02 16:40:50 +02:00
from : ( NSCalendarDate * ) _startDate
to : ( NSCalendarDate * ) _endDate
title : ( NSString * ) title
component : ( id ) _component
additionalFilters : ( NSString * ) filters
2009-06-02 16:39:21 +02:00
includeProtectedInformation : ( BOOL ) _includeProtectedInformation
2008-06-13 22:22:51 +02:00
{
EOQualifier * qualifier ;
GCSFolder * folder ;
2009-06-17 20:07:23 +02:00
NSMutableArray * fields , * ma ;
2020-04-03 18:18:16 +02:00
NSMutableDictionary * currentRecord ;
2008-06-13 22:22:51 +02:00
NSArray * records ;
2020-04-03 18:18:16 +02:00
NSEnumerator * matchingRecords ;
2012-04-12 22:24:15 +02:00
NSMutableArray * baseWhere ;
2010-06-01 20:12:01 +02:00
NSString * where , * dateSqlString , * privacySQLString , * currentLogin ;
2008-11-07 19:56:03 +01:00
NSCalendarDate * endDate ;
2008-06-13 22:22:51 +02:00
NGCalendarDateRange * r ;
2009-06-17 20:07:23 +02:00
BOOL rememberRecords , canCycle ;
2020-04-03 18:18:16 +02:00
SOGoUser * ownerUser ;
2008-06-13 22:22:51 +02:00
2020-07-01 22:58:16 +02:00
ownerUser = [ SOGoUser userWithLogin : self -> owner roles : nil ] ;
2008-06-13 22:22:51 +02:00
rememberRecords = [ self _checkIfWeCanRememberRecords : _fields ] ;
2014-09-12 14:34:15 +02:00
canCycle = [ _component isEqualToString : @ "vevent" ] || [ _component isEqualToString : @ "vtodo" ] ;
2008-06-13 22:22:51 +02:00
// if ( rememberRecords )
// NSLog ( @ "we will remember those records!" ) ;
folder = [ self ocsFolder ] ;
if ( ! folder )
{
[ self errorWithFormat : @ "(%s): missing folder for fetch!" ,
__PRETTY _FUNCTION __ ] ;
return nil ;
}
2012-04-12 22:24:15 +02:00
baseWhere = [ NSMutableArray arrayWithCapacity : 32 ] ;
2009-06-17 20:07:23 +02:00
if ( _component )
2012-04-13 01:45:23 +02:00
{
if ( [ _component isEqualToString : @ "vtodo" ] && ! [ self showCalendarTasks ] )
return [ NSArray array ] ;
else
[ baseWhere addObject : [ NSString stringWithFormat : @ "c_component = '%@'" ,
_component ] ] ;
}
else if ( ! [ self showCalendarTasks ] )
2020-06-30 19:22:17 +02:00
[ baseWhere addObject : @ "c_component != 'vtodo'" ] ;
2009-06-17 20:07:23 +02:00
2008-11-07 19:56:03 +01:00
if ( _startDate )
2008-06-13 22:22:51 +02:00
{
2008-11-07 19:56:03 +01:00
if ( _endDate )
2009-06-02 16:40:50 +02:00
endDate = _endDate ;
2008-11-07 19:56:03 +01:00
else
2009-06-02 16:40:50 +02:00
endDate = [ NSCalendarDate distantFuture ] ;
2008-06-13 22:22:51 +02:00
r = [ NGCalendarDateRange calendarDateRangeWithStartDate : _startDate
2009-06-02 16:40:50 +02:00
endDate : endDate ] ;
2012-04-19 15:17:16 +02:00
dateSqlString = [ self _sqlStringRangeFrom : _startDate to : endDate
cycle : NO ] ;
2008-06-13 22:22:51 +02:00
}
else
{
r = nil ;
2012-04-12 22:24:15 +02:00
dateSqlString = nil ;
2008-06-13 22:22:51 +02:00
}
2010-06-01 20:12:01 +02:00
privacySQLString = [ self aclSQLListingFilter ] ;
2020-06-30 19:22:17 +02:00
// Check for access to classification and also make sure the user is still active
if ( privacySQLString && ownerUser )
2010-06-01 20:12:01 +02:00
{
if ( [ privacySQLString length ] )
2012-04-12 22:24:15 +02:00
[ baseWhere addObject : privacySQLString ] ;
2014-09-12 14:34:15 +02:00
2010-06-01 20:12:01 +02:00
if ( [ title length ] )
2014-05-08 23:53:20 +02:00
{
2014-09-12 14:34:15 +02:00
if ( [ filters length ] )
{
if ( [ filters isEqualToString : @ "title_Category_Location" ] || [ filters isEqualToString : @ "entireContent" ] )
{
[ baseWhere addObject : [ NSString stringWithFormat : @ "(c_title isCaseInsensitiveLike: '%%%@%%' OR c_category isCaseInsensitiveLike: '%%%@%%' OR c_location isCaseInsensitiveLike: '%%%@%%')" ,
2016-12-09 16:45:44 +01:00
[ title asSafeSQLString ] ,
[ title asSafeSQLString ] ,
[ title asSafeSQLString ] ] ] ;
2014-09-12 14:34:15 +02:00
}
}
else
[ baseWhere addObject : [ NSString stringWithFormat : @ "c_title isCaseInsensitiveLike: '%%%@%%'" ,
2016-12-09 16:45:44 +01:00
[ title asSafeSQLString ] ] ] ;
2014-05-08 23:53:20 +02:00
}
2014-09-12 14:34:15 +02:00
2010-06-01 20:12:01 +02:00
/ * prepare mandatory fields * /
2014-09-12 14:34:15 +02:00
2010-06-01 20:12:01 +02:00
fields = [ NSMutableArray arrayWithArray : _fields ] ;
[ fields addObjectUniquely : @ "c_name" ] ;
[ fields addObjectUniquely : @ "c_uid" ] ;
[ fields addObjectUniquely : @ "c_startdate" ] ;
[ fields addObjectUniquely : @ "c_enddate" ] ;
[ fields addObjectUniquely : @ "c_isallday" ] ;
2008-06-13 22:22:51 +02:00
2010-06-01 20:12:01 +02:00
if ( canCycle )
2012-04-12 22:24:15 +02:00
{
if ( dateSqlString )
[ baseWhere addObject : dateSqlString ] ;
[ baseWhere addObject : @ "c_iscycle = 0" ] ;
}
where = [ baseWhere componentsJoinedByString : @ " AND " ] ;
2008-06-13 22:22:51 +02:00
2010-06-01 20:12:01 +02:00
/ * fetch non - recurrent apts first * /
2012-04-12 22:24:15 +02:00
qualifier = [ EOQualifier qualifierWithQualifierFormat : where ] ;
2008-11-07 19:56:03 +01:00
records = [ folder fetchFields : fields matchingQualifier : qualifier ] ;
2011-03-30 04:14:56 +02:00
2008-11-07 19:56:03 +01:00
if ( records )
2009-06-02 16:40:50 +02:00
{
if ( r )
2014-09-12 14:34:15 +02:00
records = [ self _fixupRecords : records ] ;
2010-06-01 20:12:01 +02:00
ma = [ NSMutableArray arrayWithArray : records ] ;
}
else
ma = nil ;
2016-03-22 15:44:23 +01:00
// Fetch recurrent apts now . We support the following scenarios :
// "All events" - so the start and end date is nil
// "All future events" - start is defined , date is nil
if ( canCycle )
2010-06-01 20:12:01 +02:00
{
2016-03-22 15:44:23 +01:00
unsigned int delta ;
delta = 1 ;
// If we don ' t have a start date , we use the current date - 1 year
if ( ! _startDate )
{
_startDate = [ [ NSCalendarDate date ] dateByAddingYears : -1 months : 0 days : 0 hours : 0 minutes : 0 seconds : 0 ] ;
delta + + ;
}
// We if we don ' t have an end date , we use the start date + 1 year
if ( ! _endDate )
{
endDate = [ _startDate dateByAddingYears : delta months : 0 days : 0 hours : 0 minutes : 0 seconds : 0 ] ;
}
r = [ NGCalendarDateRange calendarDateRangeWithStartDate : _startDate
endDate : endDate ] ;
// we know the last element of "baseWhere" is the c_iscycle condition
2012-04-12 22:24:15 +02:00
[ baseWhere removeLastObject ] ;
2012-04-19 15:17:16 +02:00
2016-03-22 15:44:23 +01:00
// replace the date range
2012-04-19 15:17:16 +02:00
if ( r )
{
2019-08-19 22:47:37 +02:00
if ( dateSqlString )
2016-10-07 18:19:19 +02:00
[ baseWhere removeLastObject ] ;
2012-04-19 15:17:16 +02:00
dateSqlString = [ self _sqlStringRangeFrom : _startDate
to : endDate
cycle : YES ] ;
[ baseWhere addObject : dateSqlString ] ;
}
2012-04-12 22:24:15 +02:00
[ baseWhere addObject : @ "c_iscycle = 1" ] ;
where = [ baseWhere componentsJoinedByString : @ " AND " ] ;
qualifier = [ EOQualifier qualifierWithQualifierFormat : where ] ;
2010-06-01 20:12:01 +02:00
records = [ folder fetchFields : fields matchingQualifier : qualifier ] ;
if ( records )
{
if ( r )
records = [ self _flattenCycleRecords : records fetchRange : r ] ;
2011-03-30 04:14:56 +02:00
if ( ma )
2010-06-01 20:12:01 +02:00
[ ma addObjectsFromArray : records ] ;
else
ma = [ NSMutableArray arrayWithArray : records ] ;
}
}
2016-03-22 15:44:23 +01:00
2010-06-01 20:12:01 +02:00
if ( ! ma )
{
[ self errorWithFormat : @ "(%s): fetch failed!" , __PRETTY _FUNCTION __ ] ;
return nil ;
2009-06-02 16:40:50 +02:00
}
2008-06-13 22:22:51 +02:00
2010-06-01 20:12:01 +02:00
currentLogin = [ [ context activeUser ] login ] ;
2020-07-01 22:58:16 +02:00
if ( ! [ currentLogin isEqualToString : self -> owner ] )
2020-04-03 18:18:16 +02:00
{
if ( ! _includeProtectedInformation )
[ self _fixupProtectedInformation : [ ma objectEnumerator ]
inFields : _fields
forUser : currentLogin ] ;
}
// Add owner to each record . It will be used when generating freebusy .
matchingRecords = [ ma objectEnumerator ] ;
while ( ( currentRecord = [ matchingRecords nextObject ] ) )
{
[ currentRecord setObject : ownerUser forKey : @ "owner" ] ;
}
2008-06-13 22:22:51 +02:00
2010-06-01 20:12:01 +02:00
if ( rememberRecords )
[ self _rememberRecords : ma ] ;
}
else
ma = [ NSMutableArray array ] ;
2008-06-13 22:22:51 +02:00
return ma ;
}
# warning we should use the EOFetchSpecification for that ! ! ! ( see doPROPFIND : )
# warning components in calendar - data query are ignored
2008-07-12 00:28:12 +02:00
2008-06-13 22:22:51 +02:00
- ( NSString * ) _nodeTagForProperty : ( NSString * ) property
{
NSString * namespace , * nodeName , * nsRep ;
NSRange nsEnd ;
nsEnd = [ property rangeOfString : @ "}" ] ;
namespace
= [ property substringFromRange : NSMakeRange ( 1 , nsEnd . location - 1 ) ] ;
nodeName = [ property substringFromIndex : nsEnd . location + 1 ] ;
2008-06-30 20:52:20 +02:00
if ( [ namespace isEqualToString : XMLNS_CALDAV ] )
2008-06-13 22:22:51 +02:00
nsRep = @ "C" ;
else
nsRep = @ "D" ;
return [ NSString stringWithFormat : @ "%@:%@" , nsRep , nodeName ] ;
}
2009-06-02 16:05:59 +02:00
- ( NSCalendarDate * ) _getMaxStartDate
{
2009-09-09 19:35:03 +02:00
NSCalendarDate * now , * rc ;
2009-07-07 22:57:00 +02:00
2009-09-09 19:35:03 +02:00
if ( davCalendarStartTimeLimit > 0 && ! [ [ context activeUser ] isSuperUser ] )
2009-06-02 16:05:59 +02:00
{
2009-09-09 19:35:03 +02:00
now = [ NSCalendarDate date ] ;
rc = [ now addTimeInterval : - davTimeLimitSeconds ] ;
2009-06-02 16:05:59 +02:00
}
2009-07-07 22:57:00 +02:00
else
rc = nil ;
2009-06-02 16:05:59 +02:00
return rc ;
}
- ( void ) _enforceTimeLimitOnFilter : ( NSMutableDictionary * ) filter
2009-09-09 19:35:03 +02:00
withStartDate : ( NSCalendarDate * ) startDate
andEndDate : ( NSCalendarDate * ) endDate
2009-06-02 16:05:59 +02:00
{
2009-09-09 19:35:03 +02:00
NSCalendarDate * now ;
2009-07-07 22:57:00 +02:00
int interval , intervalStart , intervalEnd ;
2009-06-02 16:05:59 +02:00
2009-09-09 19:35:03 +02:00
if ( davCalendarStartTimeLimit > 0 && ! [ [ context activeUser ] isSuperUser ] )
2009-06-02 16:05:59 +02:00
{
2009-09-09 19:35:03 +02:00
interval = ( [ endDate timeIntervalSinceDate : startDate ] / 86400 ) ;
if ( interval > davCalendarStartTimeLimit )
2009-06-02 16:05:59 +02:00
{
2009-09-09 19:35:03 +02:00
now = [ NSCalendarDate date ] ;
if ( [ now compare : startDate ] = = NSOrderedDescending
&& [ now compare : endDate ] = = NSOrderedAscending )
2009-06-02 16:05:59 +02:00
{
2009-09-09 19:35:03 +02:00
intervalStart = [ now timeIntervalSinceDate : startDate ] / 86400 ;
intervalEnd = [ endDate timeIntervalSinceDate : now ] / 86400 ;
if ( intervalStart > davCalendarStartTimeLimit / 2 )
{
startDate = [ now addTimeInterval : - davTimeHalfLimitSeconds ] ;
[ filter setObject : startDate forKey : @ "start" ] ;
}
if ( intervalEnd > davCalendarStartTimeLimit / 2 )
{
endDate = [ now addTimeInterval : davTimeHalfLimitSeconds ] ;
[ filter setObject : endDate forKey : @ "end" ] ;
}
2009-06-02 16:05:59 +02:00
}
2009-09-09 19:35:03 +02:00
else if ( [ now compare : endDate ] = = NSOrderedDescending )
2009-06-02 16:05:59 +02:00
{
2009-09-09 19:35:03 +02:00
startDate = [ endDate addTimeInterval : - davTimeLimitSeconds ] ;
[ filter setObject : startDate forKey : @ "start" ] ;
}
else if ( [ now compare : startDate ] = = NSOrderedAscending )
{
endDate = [ startDate addTimeInterval : davTimeLimitSeconds ] ;
[ filter setObject : endDate forKey : @ "end" ] ;
2009-06-02 16:05:59 +02:00
}
}
}
}
2008-06-13 22:22:51 +02:00
- ( void ) _appendTimeRange : ( id < DOMElement > ) timeRangeElement
toFilter : ( NSMutableDictionary * ) filter
{
2009-09-09 19:35:03 +02:00
NSCalendarDate * startDate , * endDate ;
startDate = [ [ timeRangeElement attribute : @ "start" ] asCalendarDate ] ;
if ( ! startDate )
startDate = [ NSCalendarDate distantPast ] ;
[ filter setObject : startDate forKey : @ "start" ] ;
endDate = [ [ timeRangeElement attribute : @ "end" ] asCalendarDate ] ;
if ( ! endDate )
endDate = [ NSCalendarDate distantFuture ] ;
[ filter setObject : endDate forKey : @ "end" ] ;
[ self _enforceTimeLimitOnFilter : filter
withStartDate : startDate andEndDate : endDate ] ;
2008-06-13 22:22:51 +02:00
}
2009-06-02 16:39:21 +02:00
- ( void ) _addDateRangeLimitToFilter : ( NSMutableDictionary * ) filter
{
NSCalendarDate * now ;
now = [ NSCalendarDate date ] ;
2009-09-09 19:35:03 +02:00
[ filter setObject : [ now addTimeInterval : davTimeHalfLimitSeconds ]
2009-06-02 16:39:21 +02:00
forKey : @ "start" ] ;
2009-09-09 19:35:03 +02:00
[ filter setObject : [ now addTimeInterval : - davTimeHalfLimitSeconds ]
2009-06-02 16:39:21 +02:00
forKey : @ "end" ] ;
}
2008-06-13 22:22:51 +02:00
# warning This method lacks support for timeranges
- ( void ) _appendPropertyFilter : ( id < DOMElement > ) propFilter
toFilter : ( NSMutableDictionary * ) filter
{
NSString * propName , * textMatch ;
id < DOMNodeList > matches ;
propName = [ [ propFilter attribute : @ "name" ] lowercaseString ] ;
matches = [ propFilter getElementsByTagName : @ "text-match" ] ;
if ( [ matches length ] )
textMatch = [ [ matches objectAtIndex : 0 ] textValue ] ;
else
{
matches = [ propFilter getElementsByTagName : @ "is-not-defined" ] ;
if ( [ matches length ] )
textMatch = @ "NULL" ;
else
textMatch = @ "" ;
}
[ filter setObject : textMatch forKey : propName ] ;
}
2012-10-22 16:09:13 +02:00
- ( NSDictionary * ) _parseCalendarFilter : ( id < DOMElement > ) filterElement
2008-06-13 22:22:51 +02:00
{
NSMutableDictionary * filterData ;
id < DOMElement > parentNode ;
id < DOMNodeList > elements ;
NSString * componentName ;
2009-06-02 16:05:59 +02:00
NSCalendarDate * maxStart ;
2008-06-13 22:22:51 +02:00
parentNode = ( id < DOMElement > ) [ filterElement parentNode ] ;
2014-09-22 17:38:07 +02:00
// This parses time - range filters .
//
// < C : filter >
// < C : comp - filter name = "VCALENDAR" >
// < C : comp - filter name = "VEVENT" >
// < C : time - range start = "20060104T000000Z"
// end = "20060105T000000Z" / >
// < / C : comp - filter >
// < / C : comp - filter >
// < / C : filter >
//
//
// We currently ignore filters based on just the component type .
// For example , this is ignored :
//
// < c : calendar - query xmlns : d = "DAV:" xmlns : c = "urn:ietf:params:xml:ns:caldav" >
// < d : prop >
// < d : getetag / >
// < c : calendar - data / >
// < / d : prop >
// < c : filter >
// < c : comp - filter name = "VCALENDAR" / >
// < / c : filter >
// < / c : calendar - query >
//
2008-06-13 22:22:51 +02:00
if ( [ [ parentNode tagName ] isEqualToString : @ "comp-filter" ]
&& [ [ parentNode attribute : @ "name" ] isEqualToString : @ "VCALENDAR" ] )
{
componentName = [ [ filterElement attribute : @ "name" ] lowercaseString ] ;
filterData = [ NSMutableDictionary dictionary ] ;
[ filterData setObject : componentName forKey : @ "name" ] ;
elements = [ filterElement getElementsByTagName : @ "time-range" ] ;
if ( [ elements length ] )
[ self _appendTimeRange : [ elements objectAtIndex : 0 ]
2009-06-02 19:59:06 +02:00
toFilter : filterData ] ;
2008-06-13 22:22:51 +02:00
elements = [ filterElement getElementsByTagName : @ "prop-filter" ] ;
if ( [ elements length ] )
[ self _appendPropertyFilter : [ elements objectAtIndex : 0 ]
2009-06-02 19:59:06 +02:00
toFilter : filterData ] ;
2009-06-02 16:05:59 +02:00
2009-06-02 19:59:06 +02:00
if ( ! [ filterData objectForKey : @ "start" ] )
2009-06-02 16:05:59 +02:00
{
maxStart = [ self _getMaxStartDate ] ;
if ( maxStart )
2009-06-08 16:32:21 +02:00
[ self _addDateRangeLimitToFilter : filterData ] ;
2009-06-02 16:05:59 +02:00
}
2009-06-02 17:28:42 +02:00
[ filterData setObject : [ NSNumber numberWithBool : NO ] forKey : @ "iscycle" ] ;
2008-06-13 22:22:51 +02:00
}
else
filterData = nil ;
2006-10-17 21:57:14 +02:00
return filterData ;
}
2009-06-02 17:28:42 +02:00
- ( NSDictionary * ) _makeCyclicFilterFrom : ( NSDictionary * ) filter
{
NSMutableDictionary * rc ;
2009-06-09 14:49:44 +02:00
NSNumber * start ;
2009-06-02 17:28:42 +02:00
rc = [ NSMutableDictionary dictionaryWithDictionary : filter ] ;
2009-06-09 14:49:44 +02:00
start = [ rc objectForKey : @ "start" ] ;
if ( start )
[ rc setObject : start forKey : @ "cycleenddate" ] ;
2009-06-02 17:28:42 +02:00
[ rc removeObjectForKey : @ "start" ] ;
[ rc removeObjectForKey : @ "end" ] ;
2009-06-02 19:59:06 +02:00
[ rc setObject : sharedYes forKey : @ "iscycle" ] ;
2009-06-02 17:28:42 +02:00
return rc ;
}
2012-10-22 16:09:13 +02:00
- ( NSArray * ) _parseCalendarFilters : ( id < DOMElement > ) parentNode
2006-10-17 21:57:14 +02:00
{
2008-03-18 18:26:34 +01:00
id < DOMNodeList > children ;
2012-10-22 16:09:13 +02:00
id < DOMElement > element ;
2006-10-17 21:57:14 +02:00
NSMutableArray * filters ;
NSDictionary * filter ;
2008-03-18 18:26:34 +01:00
unsigned int count , max ;
2006-10-17 21:57:14 +02:00
2008-06-13 22:22:51 +02:00
// NSLog ( @ "parseCalendarFilter: %@" , [ NSDate date ] ) ;
2007-12-05 00:28:52 +01:00
filters = [ NSMutableArray array ] ;
2008-03-18 18:26:34 +01:00
children = [ parentNode getElementsByTagName : @ "comp-filter" ] ;
max = [ children length ] ;
for ( count = 0 ; count < max ; count + + )
2006-10-17 21:57:14 +02:00
{
2009-06-18 22:58:46 +02:00
element = [ children objectAtIndex : count ] ;
filter = [ self _parseCalendarFilter : element ] ;
2006-10-17 21:57:14 +02:00
if ( filter )
2009-06-02 17:28:42 +02:00
{
[ filters addObject : filter ] ;
[ filters addObject : [ self _makeCyclicFilterFrom : filter ] ] ;
}
2006-10-17 21:57:14 +02:00
}
2008-06-13 22:22:51 +02:00
// NSLog ( @ "/parseCalendarFilter: %@" , [ NSDate date ] ) ;
2006-10-17 21:57:14 +02:00
return filters ;
}
2008-05-16 17:52:19 +02:00
- ( NSString * ) _additionalFilterKey : ( NSString * ) key
2009-06-02 17:28:42 +02:00
value : ( NSString * ) value
2008-05-16 17:52:19 +02:00
{
NSString * filterString ;
if ( [ value length ] )
{
if ( [ value isEqualToString : @ "NULL" ] )
2009-06-02 17:28:42 +02:00
filterString = [ NSString stringWithFormat : @ "(%@ = '')" , key ] ;
2008-05-16 17:52:19 +02:00
else
2009-06-02 17:28:42 +02:00
filterString
= [ NSString stringWithFormat : @ "(%@ like '%%%@%%')" , key , value ] ;
2008-05-16 17:52:19 +02:00
}
else
filterString = [ NSString stringWithFormat : @ "(%@ != '')" , key ] ;
return filterString ;
}
2009-06-09 19:42:00 +02:00
/ * This method enables the mapping between comp - filter attributes and SQL
2009-06-09 19:41:15 +02:00
fields in the quick table . Probably unused most of the time but should be
completed one day for full CalDAV compliance . * /
2008-05-16 17:52:19 +02:00
- ( NSString * ) _composeAdditionalFilters : ( NSDictionary * ) filter
{
NSString * additionalFilter ;
NSEnumerator * keys ;
NSString * currentKey , * keyField , * filterString ;
static NSArray * fields = nil ;
NSMutableArray * filters ;
2009-06-19 17:17:12 +02:00
NSCalendarDate * cEndDate ;
NSNumber * cycle ;
2008-05-16 17:52:19 +02:00
# warning the list of fields should be taken from the . ocs description file
if ( ! fields )
{
fields = [ NSArray arrayWithObject : @ "c_uid" ] ;
[ fields retain ] ;
}
2008-06-13 22:22:51 +02:00
2009-06-16 23:35:23 +02:00
filters = [ NSMutableArray array ] ;
2008-06-13 22:22:51 +02:00
keys = [ [ filter allKeys ] objectEnumerator ] ;
while ( ( currentKey = [ keys nextObject ] ) )
{
keyField = [ NSString stringWithFormat : @ "c_%@" , currentKey ] ;
if ( [ fields containsObject : keyField ] )
2009-06-02 16:05:59 +02:00
{
2009-06-02 19:59:06 +02:00
filterString
= [ self _additionalFilterKey : keyField
value : [ filter objectForKey : currentKey ] ] ;
2009-06-02 16:05:59 +02:00
[ filters addObject : filterString ] ;
}
2006-10-11 20:48:25 +02:00
}
2006-09-27 00:27:34 +02:00
2009-06-02 17:28:42 +02:00
// Exception for iscycle
cycle = [ filter objectForKey : @ "iscycle" ] ;
if ( cycle )
{
filterString = [ NSString stringWithFormat : @ "(c_iscycle = '%d')" ,
2009-06-02 19:59:06 +02:00
[ cycle intValue ] ] ;
2009-06-02 17:28:42 +02:00
[ filters addObject : filterString ] ;
2009-06-08 16:32:21 +02:00
if ( [ cycle intValue ] )
{
cEndDate = [ filter objectForKey : @ "cycleenddate" ] ;
2009-06-19 17:17:12 +02:00
if ( cEndDate )
2009-06-16 18:21:21 +02:00
{
filterString = [ NSString stringWithFormat :
2009-07-07 20:21:15 +02:00
@ "(c_cycleenddate = NULL OR c_cycleenddate >= %d)" ,
2009-06-19 17:17:12 +02:00
( int ) [ cEndDate timeIntervalSince1970 ] ] ;
2009-06-16 18:21:21 +02:00
[ filters addObject : filterString ] ;
}
2009-06-08 16:32:21 +02:00
}
2009-06-02 17:28:42 +02:00
}
2008-06-13 22:22:51 +02:00
if ( [ filters count ] )
2009-06-09 19:50:25 +02:00
additionalFilter = [ filters componentsJoinedByString : @ " AND " ] ;
2008-06-13 22:22:51 +02:00
else
additionalFilter = nil ;
2008-01-16 19:57:58 +01:00
2008-06-13 22:22:51 +02:00
return additionalFilter ;
2006-06-15 21:34:10 +02:00
}
2008-06-13 22:22:51 +02:00
- ( NSString * ) davCalendarColor
{
NSString * color ;
2006-11-02 22:53:27 +01:00
2008-06-13 22:22:51 +02:00
color = [ [ self calendarColor ] uppercaseString ] ;
2006-11-02 22:53:27 +01:00
2009-07-16 19:35:40 +02:00
// return color ;
return [ NSString stringWithFormat : @ "%@FF" , color ] ;
2006-11-02 22:53:27 +01:00
}
2008-06-13 22:22:51 +02:00
- ( NSException * ) setDavCalendarColor : ( NSString * ) newColor
2006-12-14 22:20:13 +01:00
{
2008-06-13 22:22:51 +02:00
NSException * error ;
NSString * realColor ;
if ( [ newColor length ] = = 9
&& [ newColor hasPrefix : @ "#" ] )
{
realColor = [ newColor substringToIndex : 7 ] ;
[ self setCalendarColor : realColor ] ;
error = nil ;
}
else
error = [ NSException exceptionWithHTTPStatus : 400
reason : @ "Bad color format (should be '#XXXXXXXX')." ] ;
return error ;
2006-12-14 22:20:13 +01:00
}
2008-07-14 18:46:10 +02:00
- ( NSString * ) davCalendarOrder
{
unsigned int order ;
order = [ [ container subFolders ] indexOfObject : self ] ;
2011-04-29 15:42:04 +02:00
return [ NSString stringWithFormat : @ "%d" , order + 1 ] ;
2008-07-14 18:46:10 +02:00
}
- ( NSException * ) setDavCalendarOrder : ( NSString * ) newColor
{
2009-10-21 23:17:11 +02:00
/ * we fail silently * /
return nil ;
}
- ( NSString * ) davCalendarTimeZone
{
SOGoUser * ownerUser ;
NSString * ownerTimeZone ;
2011-11-30 04:10:06 +01:00
iCalCalendar * tzCal ;
iCalTimeZone * tz ;
NSString * prodID ;
2009-10-21 23:17:11 +02:00
ownerUser = [ SOGoUser userWithLogin : [ self ownerInContext : context ] ] ;
2009-11-29 05:19:32 +01:00
ownerTimeZone = [ [ ownerUser userDefaults ] timeZoneName ] ;
2011-11-30 04:10:06 +01:00
tz = [ iCalTimeZone timeZoneForName : ownerTimeZone ] ;
tzCal = [ iCalCalendar groupWithTag : @ "vcalendar" ] ;
[ tzCal setVersion : @ "2.0" ] ;
prodID = [ NSString stringWithFormat :
@ "-//Inverse inc./SOGo %@//EN" , SOGoVersion ] ;
[ tzCal setProdID : prodID ] ;
[ tzCal addChild : tz ] ;
return [ tzCal versitString ] ;
2009-10-21 23:17:11 +02:00
}
- ( NSException * ) setDavCalendarTimeZone : ( NSString * ) newTimeZone
{
/ * we fail silently * /
2008-07-14 18:46:10 +02:00
return nil ;
}
2009-06-16 23:35:23 +02:00
- ( void ) _appendComponentProperties : ( NSDictionary * ) properties
2009-06-02 16:05:59 +02:00
matchingFilters : ( NSArray * ) filters
toResponse : ( WOResponse * ) response
2007-03-10 00:10:43 +01:00
{
2009-06-16 23:35:23 +02:00
NSArray * apts ;
NSMutableArray * fields ;
2008-06-13 22:22:51 +02:00
NSDictionary * currentFilter ;
NSEnumerator * filterList ;
2009-06-30 23:21:50 +02:00
NSString * additionalFilters , * baseURL , * currentField ;
2008-11-18 01:06:37 +01:00
NSMutableString * buffer ;
2009-06-16 23:35:23 +02:00
NSString * * propertiesArray ;
2009-06-30 23:21:50 +02:00
NSEnumerator * addFields ;
2009-06-03 23:38:46 +02:00
unsigned int count , max , propertiesCount ;
2007-03-10 00:10:43 +01:00
2009-06-24 01:38:52 +02:00
fields = [ NSMutableArray arrayWithObjects : @ "c_name" , @ "c_component" , nil ] ;
2009-06-30 23:21:50 +02:00
addFields = [ [ properties allValues ] objectEnumerator ] ;
while ( ( currentField = [ addFields nextObject ] ) )
if ( [ currentField length ] )
[ fields addObjectUniquely : currentField ] ;
2009-10-21 23:17:11 +02:00
baseURL = [ self davURLAsString ] ;
2008-11-22 22:52:40 +01:00
2009-06-16 23:35:23 +02:00
propertiesArray = [ [ properties allKeys ] asPointersOfObjects ] ;
propertiesCount = [ properties count ] ;
2009-06-03 23:38:46 +02:00
2009-06-18 22:58:46 +02:00
// NSLog ( @ "start" ) ;
2008-06-13 22:22:51 +02:00
filterList = [ filters objectEnumerator ] ;
while ( ( currentFilter = [ filterList nextObject ] ) )
2007-03-10 00:10:43 +01:00
{
2008-06-13 22:22:51 +02:00
additionalFilters = [ self _composeAdditionalFilters : currentFilter ] ;
2009-06-02 20:00:19 +02:00
/ * TODO : we should invoke bareFetchField : . . . twice and compute the
recurrent events properly instead of using _makeCyclicFilterFrom : * /
2008-11-18 01:06:37 +01:00
apts = [ self bareFetchFields : fields
2009-06-02 16:05:59 +02:00
from : [ currentFilter objectForKey : @ "start" ]
to : [ currentFilter objectForKey : @ "end" ]
title : [ currentFilter objectForKey : @ "title" ]
component : [ currentFilter objectForKey : @ "name" ]
additionalFilters : additionalFilters ] ;
2009-06-18 22:58:46 +02:00
// NSLog ( @ "adding properties" ) ;
2008-06-13 22:22:51 +02:00
max = [ apts count ] ;
2009-06-16 23:35:23 +02:00
buffer = [ NSMutableString stringWithCapacity : max * 512 ] ;
2008-06-13 22:22:51 +02:00
for ( count = 0 ; count < max ; count + + )
2009-06-02 16:05:59 +02:00
[ self appendObject : [ apts objectAtIndex : count ]
2009-06-16 23:35:23 +02:00
properties : propertiesArray
2009-06-03 23:38:46 +02:00
count : propertiesCount
2009-06-02 16:05:59 +02:00
withBaseURL : baseURL
toBuffer : buffer ] ;
2009-06-18 22:58:46 +02:00
// NSLog ( @ "done 1" ) ;
2008-11-18 01:06:37 +01:00
[ response appendContentString : buffer ] ;
2009-06-18 22:58:46 +02:00
// NSLog ( @ "done 2" ) ;
2007-03-10 00:10:43 +01:00
}
2009-06-18 22:58:46 +02:00
// NSLog ( @ "stop" ) ;
2009-06-03 23:38:46 +02:00
2009-06-16 23:35:23 +02:00
NSZoneFree ( NULL , propertiesArray ) ;
2007-03-10 00:10:43 +01:00
}
2009-06-18 22:58:46 +02:00
/ * This table is meant to match SQL fields to the properties that requires
them . The fields may NOT be processed directly . This list is not complete
but is at least sufficient for processing requests from Lightning . * /
- ( NSDictionary * ) davSQLFieldsTable
{
static NSMutableDictionary * davSQLFieldsTable = nil ;
if ( ! davSQLFieldsTable )
{
davSQLFieldsTable = [ [ super davSQLFieldsTable ] mutableCopy ] ;
[ davSQLFieldsTable setObject : @ "c_content"
forKey : @ "{" XMLNS_CALDAV @ "}calendar-data" ] ;
}
return davSQLFieldsTable ;
}
2008-06-13 22:22:51 +02:00
- ( id ) davCalendarQuery : ( id ) queryContext
2006-08-16 00:04:37 +02:00
{
2008-06-13 22:22:51 +02:00
WOResponse * r ;
id < DOMDocument > document ;
2012-10-22 16:09:13 +02:00
id < DOMElement > documentElement , propElement ;
2008-06-13 22:22:51 +02:00
r = [ context response ] ;
2010-01-15 00:19:19 +01:00
[ r prepareDAVResponse ] ;
2008-06-13 22:22:51 +02:00
[ r appendContentString : @ "<D:multistatus xmlns:D=\" DAV : \ ""
2009-06-18 22:58:46 +02:00
@ " xmlns:C=\" urn : ietf : params : xml : ns : caldav \ ">" ] ;
2008-06-13 22:22:51 +02:00
document = [ [ context request ] contentAsDOMDocument ] ;
2012-10-22 16:09:13 +02:00
documentElement = ( id < DOMElement > ) [ document documentElement ] ;
propElement = [ ( NGDOMNodeWithChildren * ) documentElement
firstElementWithTag : @ "prop" inNamespace : XMLNS_WEBDAV ] ;
2009-06-18 22:58:46 +02:00
[ self _appendComponentProperties : [ self parseDAVRequestedProperties : propElement ]
2009-06-16 23:35:23 +02:00
matchingFilters : [ self _parseCalendarFilters : documentElement ]
2009-06-01 19:56:31 +02:00
toResponse : r ] ;
2008-10-22 17:54:02 +02:00
[ r appendContentString : @ "</D:multistatus>" ] ;
2008-06-13 22:22:51 +02:00
return r ;
2006-06-15 21:34:10 +02:00
}
2010-08-12 16:02:21 +02:00
- ( WOResponse * ) davCalendarMultiget : ( WOContext * ) queryContext
2007-04-11 21:08:58 +02:00
{
2010-08-12 16:02:21 +02:00
return [ self performMultigetInContext : queryContext
inNamespace : @ "urn:ietf:params:xml:ns:caldav" ] ;
2006-06-15 21:34:10 +02:00
}
2009-07-07 22:57:00 +02:00
- ( NSString * ) additionalWebdavSyncFilters
{
NSCalendarDate * startDate ;
NSString * filter ;
2012-04-12 22:25:13 +02:00
NSMutableArray * filters ;
2009-07-07 22:57:00 +02:00
int startDateSecs ;
2012-04-12 22:25:13 +02:00
filters = [ NSMutableArray arrayWithCapacity : 8 ] ;
2009-07-07 22:57:00 +02:00
startDate = [ self _getMaxStartDate ] ;
if ( startDate )
{
startDateSecs = ( int ) [ startDate timeIntervalSince1970 ] ;
2012-04-12 22:25:13 +02:00
filter = [ NSString stringWithFormat : @ "(c_enddate = NULL"
2009-07-07 22:57:00 +02:00
@ " OR (c_enddate >= %d AND c_iscycle = 0)"
2012-04-12 22:25:13 +02:00
@ " OR (c_cycleenddate >= %d AND c_iscycle = 1))" ,
2009-07-07 22:57:00 +02:00
startDateSecs , startDateSecs ] ;
2012-04-12 22:25:13 +02:00
[ filters addObject : filter ] ;
2009-07-07 22:57:00 +02:00
}
2012-04-12 22:25:13 +02:00
if ( ! [ self showCalendarTasks ] )
[ filters addObject : @ "c_component != 'vtodo'" ] ;
return [ filters componentsJoinedByString : @ " AND " ] ;
2009-07-07 22:57:00 +02:00
}
2008-06-13 22:22:51 +02:00
- ( Class ) objectClassForContent : ( NSString * ) content
2006-10-11 20:48:25 +02:00
{
2008-06-13 22:22:51 +02:00
iCalCalendar * calendar ;
NSArray * elements ;
NSString * firstTag ;
Class objectClass ;
2006-10-11 20:48:25 +02:00
2008-06-13 22:22:51 +02:00
objectClass = Nil ;
2006-10-11 20:48:25 +02:00
2008-06-13 22:22:51 +02:00
calendar = [ iCalCalendar parseSingleFromSource : content ] ;
if ( calendar )
{
elements = [ calendar allObjects ] ;
if ( [ elements count ] )
{
firstTag = [ [ [ elements objectAtIndex : 0 ] tag ] uppercaseString ] ;
if ( [ firstTag isEqualToString : @ "VEVENT" ] )
objectClass = [ SOGoAppointmentObject class ] ;
else if ( [ firstTag isEqualToString : @ "VTODO" ] )
objectClass = [ SOGoTaskObject class ] ;
}
2006-10-11 20:48:25 +02:00
}
2008-06-13 22:22:51 +02:00
return objectClass ;
}
- ( BOOL ) requestNamedIsHandledLater : ( NSString * ) name
{
return [ name isEqualToString : @ "OPTIONS" ] ;
}
- ( id ) lookupName : ( NSString * ) _key
inContext : ( id ) _ctx
acquire : ( BOOL ) _flag
{
id obj ;
NSString * url ;
BOOL handledLater ;
2009-07-01 21:27:44 +02:00
WORequest * rq ;
2008-06-13 22:22:51 +02:00
/ * first check attributes directly bound to the application * /
handledLater = [ self requestNamedIsHandledLater : _key ] ;
if ( handledLater )
obj = nil ;
2006-10-11 20:48:25 +02:00
else
2008-06-13 22:22:51 +02:00
{
obj = [ super lookupName : _key inContext : _ctx acquire : NO ] ;
if ( ! obj )
{
2009-07-01 21:27:44 +02:00
rq = [ _ctx request ] ;
if ( [ self isValidContentName : _key ]
&& [ rq handledByDefaultHandler ] )
2008-06-13 22:22:51 +02:00
{
2009-07-01 21:27:44 +02:00
url = [ [ rq uri ] urlWithoutParameters ] ;
2008-07-14 17:14:40 +02:00
if ( [ url hasSuffix : @ "AsTask" ] )
obj = [ SOGoTaskObject objectWithName : _key
inContainer : self ] ;
else if ( [ url hasSuffix : @ "AsAppointment" ] )
obj = [ SOGoAppointmentObject objectWithName : _key
inContainer : self ] ;
2008-07-14 18:46:10 +02:00
[ obj setIsNew : YES ] ;
2008-06-13 22:22:51 +02:00
}
}
if ( ! obj )
obj = [ NSException exceptionWithHTTPStatus : 404 / * Not Found * / ] ;
}
2006-10-11 20:48:25 +02:00
2008-06-13 22:22:51 +02:00
if ( obj )
[ [ SOGoCache sharedCache ] registerObject : obj
withName : _key
inContainer : container ] ;
return obj ;
2006-10-11 20:48:25 +02:00
}
2009-07-20 20:29:09 +02:00
- ( NSDictionary * ) freebusyResponseForRecipient : ( iCalPerson * ) recipient
2008-06-30 20:52:20 +02:00
withUser : ( SOGoUser * ) user
andCalendarData : ( NSString * ) calendarData
{
NSDictionary * response ;
NSMutableArray * content ;
2009-06-16 23:35:23 +02:00
content = [ NSMutableArray array ] ;
2008-06-30 20:52:20 +02:00
2009-07-20 20:29:09 +02:00
[ content addObject : davElementWithContent ( @ "recipient" ,
XMLNS_CALDAV , [ recipient email ] ) ] ;
2008-06-30 20:52:20 +02:00
if ( user )
{
[ content addObject : davElementWithContent ( @ "request-status" , XMLNS_CALDAV ,
@ "2.0;Success" ) ] ;
2009-06-09 22:00:28 +02:00
[ content addObject : davElementWithContent ( @ "calendar-data" , XMLNS_CALDAV ,
2016-04-06 17:19:18 +02:00
[ calendarData safeStringByEscapingXMLString ] ) ] ;
2008-06-30 20:52:20 +02:00
}
else
[ content addObject :
davElementWithContent ( @ "request-status" , XMLNS_CALDAV ,
@ "3.7;Invalid Calendar User" ) ] ;
response = davElementWithContent ( @ "response" , XMLNS_CALDAV , content ) ;
return response ;
}
2009-07-20 20:29:09 +02:00
- ( NSDictionary * ) caldavFreeBusyRequestOnRecipient : ( iCalPerson * ) recipient
2009-06-09 22:43:53 +02:00
withUID : ( NSString * ) uid
2009-06-09 23:10:25 +02:00
andOrganizer : ( iCalPerson * ) organizer
2008-06-30 20:52:20 +02:00
from : ( NSCalendarDate * ) start
to : ( NSCalendarDate * ) to
{
SOGoUser * user ;
2012-01-13 18:20:58 +01:00
NSString * login , * contactId , * calendarData ;
2008-06-30 20:52:20 +02:00
SOGoFreeBusyObject * freebusy ;
2009-07-20 20:29:09 +02:00
login = [ recipient uid ] ;
if ( [ login length ] )
2008-06-30 20:52:20 +02:00
{
2009-08-25 23:28:24 +02:00
user = [ SOGoUser userWithLogin : login ] ;
2009-07-20 20:29:09 +02:00
freebusy = [ [ user homeFolderInContext : context ]
2008-06-30 20:52:20 +02:00
freeBusyObject : @ "freebusy.ifb"
2009-07-20 20:29:09 +02:00
inContext : context ] ;
calendarData = [ freebusy contentAsStringWithMethod : @ "REPLY"
andUID : uid
andOrganizer : organizer
2012-01-13 18:20:58 +01:00
andContact : nil
2009-07-20 20:29:09 +02:00
from : start to : to ] ;
}
2012-01-13 18:20:58 +01:00
else if ( ( contactId = [ recipient contactIDInContext : context ] ) )
{
user = [ context activeUser ] ;
freebusy = [ [ user homeFolderInContext : context ]
freeBusyObject : @ "freebusy.ifb"
inContext : context ] ;
calendarData = [ freebusy contentAsStringWithMethod : @ "REPLY"
andUID : uid
andOrganizer : organizer
andContact : contactId
from : start to : to ] ;
}
2009-07-20 20:29:09 +02:00
else
{
user = nil ;
calendarData = nil ;
2008-06-30 20:52:20 +02:00
}
return [ self freebusyResponseForRecipient : recipient
2009-07-20 20:29:09 +02:00
withUser : user
andCalendarData : calendarData ] ;
2008-06-30 20:52:20 +02:00
}
- ( NSDictionary * ) caldavFreeBusyRequest : ( iCalFreeBusy * ) freebusy
{
NSDictionary * responseElement ;
NSMutableArray * elements ;
2009-07-20 20:29:09 +02:00
NSString * uid ;
iCalPerson * recipient , * organizer ;
2008-07-05 00:25:27 +02:00
NSEnumerator * allRecipients ;
2008-06-30 20:52:20 +02:00
NSCalendarDate * startDate , * endDate ;
2009-06-16 23:35:23 +02:00
elements = [ NSMutableArray array ] ;
2008-06-30 20:52:20 +02:00
[ freebusy fillStartDate : & startDate andEndDate : & endDate ] ;
2009-06-09 22:43:53 +02:00
uid = [ freebusy uid ] ;
2009-06-09 23:10:25 +02:00
organizer = [ freebusy organizer ] ;
2009-07-20 20:29:09 +02:00
allRecipients = [ [ freebusy attendees ] objectEnumerator ] ;
2008-07-05 00:25:27 +02:00
while ( ( recipient = [ allRecipients nextObject ] ) )
2009-07-20 20:29:09 +02:00
[ elements addObject : [ self caldavFreeBusyRequestOnRecipient : recipient
2009-06-09 22:43:53 +02:00
withUID : uid
2009-06-09 23:10:25 +02:00
andOrganizer : organizer
2009-06-09 22:43:53 +02:00
from : startDate
to : endDate ] ] ;
2008-06-30 20:52:20 +02:00
responseElement = davElementWithContent ( @ "schedule-response" ,
XMLNS_CALDAV , elements ) ;
return responseElement ;
}
2008-07-08 17:44:50 +02:00
# warning we should merge this code with the code from the iTIP interpreter in MailPartViewer
2008-06-30 22:18:32 +02:00
- ( NSDictionary * ) caldavEventRequest : ( iCalEvent * ) event
2008-07-05 00:25:27 +02:00
withContent : ( NSString * ) iCalString
2008-06-30 22:18:32 +02:00
from : ( NSString * ) originator
to : ( NSArray * ) recipients
{
NSDictionary * responseElement ;
2008-07-08 17:44:50 +02:00
NSArray * elements ;
NSString * method , * filename ;
SOGoAppointmentObject * apt ;
2008-11-10 16:38:05 +01:00
2008-07-08 17:44:50 +02:00
filename = [ NSString stringWithFormat : @ "%@.ics" , [ event uid ] ] ;
apt = [ SOGoAppointmentObject objectWithName : filename
andContent : iCalString
inContainer : self ] ;
2008-06-30 22:18:32 +02:00
method = [ [ event parent ] method ] ;
if ( [ method isEqualToString : @ "REQUEST" ] )
2008-11-10 16:38:05 +01:00
elements = [ apt postCalDAVEventRequestTo : recipients from : originator ] ;
2008-06-30 22:18:32 +02:00
else if ( [ method isEqualToString : @ "REPLY" ] )
2008-11-10 16:38:05 +01:00
elements = [ apt postCalDAVEventReplyTo : recipients from : originator ] ;
2008-07-09 17:54:39 +02:00
else if ( [ method isEqualToString : @ "CANCEL" ] )
2008-11-10 16:38:05 +01:00
elements = [ apt postCalDAVEventCancelTo : recipients from : originator ] ;
2008-07-08 17:44:50 +02:00
else
elements = nil ;
if ( elements )
responseElement = davElementWithContent ( @ "schedule-response" ,
XMLNS_CALDAV , elements ) ;
2008-06-30 22:18:32 +02:00
else
responseElement = nil ;
return responseElement ;
}
2008-06-30 20:52:20 +02:00
- ( WOResponse * ) _caldavScheduleResponse : ( NSDictionary * ) tags
{
WOResponse * response ;
response = [ context response ] ;
if ( tags )
{
2009-07-20 20:23:44 +02:00
// WARNING
// don ' t touch unless you ' re going to re - test caldav sync
// with an iPhone AND lightning
2008-06-30 20:52:20 +02:00
[ response setStatus : 200 ] ;
2009-07-19 19:22:54 +02:00
[ response appendContentString : @ "<?xml version=\" 1.0 \ ""
2009-07-19 19:22:26 +02:00
@ " encoding=\" utf -8 \ "?>" ] ;
2008-06-30 20:52:20 +02:00
[ response setHeader : @ "application/xml; charset=utf-8"
2009-07-17 20:36:09 +02:00
forKey : @ "Content-Type" ] ;
2008-06-30 20:52:20 +02:00
[ response appendContentString :
[ tags asWebDavStringWithNamespaces : nil ] ] ;
}
else
[ response setStatus : 415 ] ;
return response ;
}
2008-07-05 00:25:27 +02:00
- ( WOResponse * ) caldavScheduleRequest : ( NSString * ) iCalString
from : ( NSString * ) originator
to : ( NSArray * ) recipients
2008-06-30 20:52:20 +02:00
{
2008-07-05 00:25:27 +02:00
NSString * tag ;
iCalCalendar * calendar ;
2008-06-30 20:52:20 +02:00
iCalEntityObject * element ;
NSDictionary * tags ;
# warning needs to handle errors
2008-07-05 00:25:27 +02:00
calendar = [ iCalCalendar parseSingleFromSource : iCalString ] ;
element = [ [ calendar allObjects ] objectAtIndex : 0 ] ;
tag = [ [ element tag ] uppercaseString ] ;
if ( [ tag isEqualToString : @ "VFREEBUSY" ] )
2009-07-20 20:29:09 +02:00
tags = [ self caldavFreeBusyRequest : ( iCalFreeBusy * ) element ] ;
2008-07-05 00:25:27 +02:00
else if ( [ tag isEqualToString : @ "VEVENT" ] )
tags = [ self caldavEventRequest : ( iCalEvent * ) element
2012-01-13 18:20:58 +01:00
withContent : iCalString
from : originator to : recipients ] ;
2008-07-05 00:25:27 +02:00
else
tags = nil ;
2008-06-30 20:52:20 +02:00
return [ self _caldavScheduleResponse : tags ] ;
}
2008-07-04 20:22:06 +02:00
- ( id ) davPOSTRequest : ( WORequest * ) request
withContentType : ( NSString * ) cType
inContext : ( WOContext * ) localContext
2008-06-30 20:52:20 +02:00
{
id obj ;
2008-07-05 00:25:27 +02:00
NSString * originator ;
NSArray * recipients ;
2008-06-30 20:52:20 +02:00
2008-07-04 20:22:06 +02:00
if ( [ cType hasPrefix : @ "text/calendar" ] )
2008-06-30 20:52:20 +02:00
{
2008-07-05 00:25:27 +02:00
originator = [ request headerForKey : @ "originator" ] ;
2008-11-10 16:38:05 +01:00
if ( [ [ originator lowercaseString ] hasPrefix : @ "mailto:" ] )
originator = [ originator substringFromIndex : 7 ] ;
2008-07-05 00:25:27 +02:00
recipients = [ [ request headerForKey : @ "recipient" ]
2009-07-23 19:34:10 +02:00
componentsSeparatedByString : @ "," ] ;
2008-07-05 00:25:27 +02:00
obj = [ self caldavScheduleRequest : [ request contentAsString ]
2009-07-23 19:34:10 +02:00
from : originator to : [ recipients trimmedComponents ] ] ;
2008-06-30 20:52:20 +02:00
}
2008-07-04 20:22:06 +02:00
else
obj = [ super davPOSTRequest : request withContentType : cType
inContext : localContext ] ;
2008-06-30 20:52:20 +02:00
return obj ;
}
2008-06-13 22:22:51 +02:00
- ( NSArray * ) groupDavResourceType
2007-04-26 03:16:19 +02:00
{
2008-06-13 22:22:51 +02:00
return [ NSArray arrayWithObjects : @ "vevent-collection" ,
@ "vtodo-collection" , nil ] ;
}
2007-04-26 03:16:19 +02:00
2008-06-13 22:22:51 +02:00
- ( NSArray * ) davResourceType
{
2009-06-19 17:34:22 +02:00
NSMutableArray * colType ;
NSArray * gdRT , * gdVEventCol , * gdVTodoCol ;
2009-07-20 20:20:44 +02:00
WORequest * request ;
2009-06-19 17:34:22 +02:00
colType = [ NSMutableArray arrayWithCapacity : 10 ] ;
[ colType addObject : @ "collection" ] ;
[ colType addObject : [ NSArray arrayWithObjects : @ "calendar" , XMLNS_CALDAV , nil ] ] ;
2009-07-20 20:49:56 +02:00
/ * iPhone compatibility : we can only return a caldav "calendar"
resourcetype . Anything else will prevent the iPhone from querying the
collection . * /
2009-07-20 20:20:44 +02:00
request = [ context request ] ;
2009-10-21 23:17:11 +02:00
if ( ! ( [ request isIPhone ] || [ request isICal4 ] ) )
2007-04-26 03:16:19 +02:00
{
2015-10-31 07:10:03 +01:00
gdRT = ( NSArray * ) [ self groupDavResourceType ] ;
2009-07-20 20:20:44 +02:00
gdVEventCol = [ NSArray arrayWithObjects : [ gdRT objectAtIndex : 0 ] ,
XMLNS_GROUPDAV , nil ] ;
[ colType addObject : gdVEventCol ] ;
2012-04-13 01:41:47 +02:00
if ( [ self showCalendarTasks ] )
{
gdVTodoCol = [ NSArray arrayWithObjects : [ gdRT objectAtIndex : 1 ] ,
XMLNS_GROUPDAV , nil ] ;
[ colType addObject : gdVTodoCol ] ;
}
2009-07-20 20:20:44 +02:00
if ( [ nameInContainer isEqualToString : @ "personal" ] )
2010-01-21 00:09:35 +01:00
[ colType addObject : [ NSArray arrayWithObjects : @ "schedule-outbox" ,
XMLNS_CALDAV , nil ] ] ;
2007-04-26 03:16:19 +02:00
}
2008-06-13 22:22:51 +02:00
return colType ;
2007-04-26 03:16:19 +02:00
}
2009-06-19 18:20:49 +02:00
- ( SOGoWebDAVValue * ) davCalendarComponentSet
{
NSMutableArray * components ;
if ( ! componentSet )
{
2012-04-13 01:40:05 +02:00
components = [ [ NSMutableArray alloc ] initWithCapacity : 2 ] ;
2009-06-19 18:20:49 +02:00
/ * Totally hackish . . . . we use the "n1" prefix because we know our
extensions will assign that one to . . : caldav but we really need to
handle element attributes * /
[ components addObject : [ SOGoWebDAVValue
valueForObject : @ "<n1:comp name=\" VEVENT \ "/>"
attributes : nil ] ] ;
2014-09-17 17:35:09 +02:00
2014-09-17 17:51:46 +02:00
// See bugs #2878 and #2879
2014-09-17 17:35:09 +02:00
[ components addObject : [ SOGoWebDAVValue
valueForObject : @ "<n1:comp name=\" VFREEBUSY \ "/>"
attributes : nil ] ] ;
2012-04-13 01:40:05 +02:00
if ( [ self showCalendarTasks ] )
[ components addObject : [ SOGoWebDAVValue
valueForObject : @ "<n1:comp name=\" VTODO \ "/>"
attributes : nil ] ] ;
2009-06-19 18:20:49 +02:00
componentSet
= [ davElementWithContent ( @ "supported-calendar-component-set" ,
XMLNS_CALDAV ,
components )
asWebDAVValue ] ;
2009-06-30 23:34:17 +02:00
[ componentSet retain ] ;
2012-04-13 01:40:05 +02:00
[ components release ] ;
2009-06-19 18:20:49 +02:00
}
return componentSet ;
}
2008-06-30 20:52:20 +02:00
- ( NSString * ) davDescription
{
return @ "" ;
}
2013-09-25 22:02:13 +02:00
/ *
RFC5842 states :
3.1 . DAV : resource - id Property
The DAV : resource - id property is a REQUIRED property that enables
clients to determine whether two bindings are to the same resource .
The value of DAV : resource - id is a URI , and may use any registered URI
scheme that guarantees the uniqueness of the value across all
resources for all time ( e . g . , the urn : uuid : URN namespace defined in
[ RFC4122 ] or the opaquelocktoken : URI scheme defined in [ RFC4918 ] ) .
< ! ELEMENT resource - id ( href ) >
. . .
so we must STRIP any username prefix , to make the ID global .
* /
2011-11-30 15:33:11 +01:00
- ( NSString * ) davResourceId
{
2013-09-25 22:02:13 +02:00
NSString * name , * prefix ;
prefix = [ NSString stringWithFormat : @ "%@_" , [ self ownerInContext : context ] ] ;
name = [ self nameInContainer ] ;
if ( [ name hasPrefix : prefix ] )
{
name = [ name substringFromIndex : [ prefix length ] ] ;
}
2011-11-30 15:33:11 +01:00
return [ NSString stringWithFormat : @ "urn:uuid:%@:calendars:%@" ,
2013-09-25 22:02:13 +02:00
[ self ownerInContext : context ] , name ] ;
2011-11-30 15:33:11 +01:00
}
2010-05-06 21:30:14 +02:00
- ( NSArray * ) davScheduleCalendarTransparency
{
const NSString * opacity ;
opacity = ( [ self includeInFreeBusy ] ? @ "opaque" : @ "transparent" ) ;
return [ NSArray arrayWithObject : [ NSArray arrayWithObjects : opacity ,
XMLNS_CALDAV ,
nil ] ] ;
}
- ( NSException * ) setDavScheduleCalendarTransparency : ( id ) newName
{
NSException * error ;
error = nil ;
if ( [ newName rangeOfString : @ "opaque" ] . location ! = NSNotFound )
[ self setIncludeInFreeBusy : YES ] ;
else if ( [ newName rangeOfString : @ "transparent" ] . location ! = NSNotFound )
[ self setIncludeInFreeBusy : NO ] ;
else
error = [ NSException exceptionWithHTTPStatus : 400
reason : @ "Bad transparency value." ] ;
return error ;
}
2012-04-13 17:17:12 +02:00
- ( NSString * ) davCalendarShowAlarms
{
2012-07-12 17:03:38 +02:00
return [ self davBooleanForResult : [ self showCalendarAlarms ] ] ;
}
- ( NSException * ) setDavCalendarShowAlarms : ( id ) newBoolean
{
NSException * error ;
2012-04-13 17:17:12 +02:00
2012-07-12 17:03:38 +02:00
if ( [ self isValidDAVBoolean : newBoolean ] )
{
[ self setShowCalendarAlarms : [ self resultForDAVBoolean : newBoolean ] ] ;
error = nil ;
}
2012-04-13 17:17:12 +02:00
else
2012-07-12 17:03:38 +02:00
error = [ NSException exceptionWithHTTPStatus : 400
reason : @ "Bad boolean value." ] ;
2012-04-13 17:17:12 +02:00
2012-07-12 17:03:38 +02:00
return error ;
2012-04-13 17:17:12 +02:00
}
2012-07-12 17:03:38 +02:00
- ( NSString * ) davNotifyOnPersonalModifications
{
return [ self davBooleanForResult : [ self notifyOnPersonalModifications ] ] ;
}
- ( NSException * ) setDavNotifyOnPersonalModifications : ( NSString * ) newBoolean
2012-04-13 17:17:12 +02:00
{
NSException * error ;
2012-07-12 17:03:38 +02:00
if ( [ self isValidDAVBoolean : newBoolean ] )
{
[ self setNotifyOnPersonalModifications :
[ self resultForDAVBoolean : newBoolean ] ] ;
error = nil ;
}
else
error = [ NSException exceptionWithHTTPStatus : 400
reason : @ "Bad boolean value." ] ;
return error ;
}
- ( NSString * ) davNotifyOnExternalModifications
{
return [ self davBooleanForResult : [ self notifyOnExternalModifications ] ] ;
}
- ( NSException * ) setDavNotifyOnExternalModifications : ( NSString * ) newBoolean
{
NSException * error ;
2012-04-13 17:17:12 +02:00
2012-07-12 17:03:38 +02:00
if ( [ self isValidDAVBoolean : newBoolean ] )
{
[ self setNotifyOnExternalModifications :
[ self resultForDAVBoolean : newBoolean ] ] ;
error = nil ;
}
2012-04-13 17:17:12 +02:00
else
error = [ NSException exceptionWithHTTPStatus : 400
reason : @ "Bad boolean value." ] ;
return error ;
}
2012-07-12 17:03:38 +02:00
- ( NSString * ) davNotifyUserOnPersonalModifications
{
return [ self davBooleanForResult : [ self notifyUserOnPersonalModifications ] ] ;
}
- ( NSException * ) setDavNotifyUserOnPersonalModifications : ( NSString * ) newBoolean
{
NSException * error ;
if ( [ self isValidDAVBoolean : newBoolean ] )
{
[ self setNotifyUserOnPersonalModifications :
[ self resultForDAVBoolean : newBoolean ] ] ;
error = nil ;
}
else
error = [ NSException exceptionWithHTTPStatus : 400
reason : @ "Bad boolean value." ] ;
return error ;
}
- ( NSString * ) davNotifiedUserOnPersonalModifications
{
return [ self notifiedUserOnPersonalModifications ] ;
}
- ( NSException * ) setDavNotifiedUserOnPersonalModifications : ( NSString * ) theUser
{
[ self setNotifiedUserOnPersonalModifications : theUser ] ;
return nil ;
}
2008-06-13 22:22:51 +02:00
/ * vevent UID handling * /
2007-03-07 22:27:19 +01:00
2008-06-30 23:11:20 +02:00
- ( NSString * ) resourceNameForEventUID : ( NSString * ) uid
inFolder : ( GCSFolder * ) folder
2008-06-13 22:22:51 +02:00
{
static NSArray * nameFields = nil ;
EOQualifier * qualifier ;
2008-06-30 23:11:20 +02:00
NSArray * records ;
NSString * filename ;
unsigned int count ;
2008-06-30 23:46:05 +02:00
filename = nil ;
2008-06-30 23:11:20 +02:00
if ( ! nameFields )
2008-06-13 22:22:51 +02:00
nameFields = [ [ NSArray alloc ] initWithObjects : @ "c_name" , nil ] ;
2008-06-30 23:11:20 +02:00
if ( uid && folder )
{
2008-07-05 00:25:27 +02:00
qualifier = [ EOQualifier qualifierWithQualifierFormat : @ "c_uid = %@" ,
2016-12-09 16:45:44 +01:00
[ uid asSafeSQLString ] ] ;
2008-06-30 23:11:20 +02:00
records = [ folder fetchFields : nameFields matchingQualifier : qualifier ] ;
count = [ records count ] ;
if ( count )
{
2009-06-24 01:38:52 +02:00
filename = [ [ records objectAtIndex : 0 ] valueForKey : @ "c_name" ] ;
2008-06-30 23:11:20 +02:00
if ( count > 1 )
[ self errorWithFormat :
2008-07-05 00:25:27 +02:00
@ "The storage contains more than file with UID '%@'" ,
uid ] ;
2008-06-30 23:11:20 +02:00
}
}
return filename ;
2008-06-13 22:22:51 +02:00
}
2007-03-07 22:27:19 +01:00
2008-06-30 23:11:20 +02:00
- ( NSString * ) resourceNameForEventUID : ( NSString * ) uid
2008-06-13 22:22:51 +02:00
{
/ * caches UIDs * /
GCSFolder * folder ;
NSString * rname ;
2008-06-30 23:11:20 +02:00
rname = nil ;
if ( uid )
2007-03-07 22:27:19 +01:00
{
2008-06-30 23:11:20 +02:00
if ( ! uidToFilename )
uidToFilename = [ NSMutableDictionary new ] ;
rname = [ uidToFilename objectForKey : uid ] ;
if ( ! rname )
{
folder = [ self ocsFolder ] ;
rname = [ self resourceNameForEventUID : uid inFolder : folder ] ;
if ( rname )
[ uidToFilename setObject : rname forKey : uid ] ;
}
2007-03-07 22:27:19 +01:00
}
2008-06-30 23:11:20 +02:00
2008-06-13 22:22:51 +02:00
return rname ;
2007-03-07 22:27:19 +01:00
}
2007-11-29 17:14:11 +01:00
- ( NSArray * ) subscriptionRoles
{
return [ NSArray arrayWithObjects :
2008-12-23 16:51:12 +01:00
SOGoRole_ObjectCreator ,
SOGoRole_ObjectEraser ,
2007-11-29 17:14:11 +01:00
SOGoCalendarRole_PublicResponder ,
SOGoCalendarRole_PublicModifier ,
SOGoCalendarRole_PublicViewer ,
SOGoCalendarRole_PublicDAndTViewer ,
SOGoCalendarRole_PrivateResponder ,
SOGoCalendarRole_PrivateModifier ,
SOGoCalendarRole_PrivateViewer ,
SOGoCalendarRole_PrivateDAndTViewer ,
SOGoCalendarRole_ConfidentialResponder ,
SOGoCalendarRole_ConfidentialModifier ,
SOGoCalendarRole_ConfidentialViewer ,
SOGoCalendarRole_ConfidentialDAndTViewer , nil ] ;
}
2007-04-26 03:16:19 +02:00
- ( NSString * ) roleForComponentsWithAccessClass : ( iCalAccessClass ) accessClass
forUser : ( NSString * ) uid
{
2009-07-27 23:36:03 +02:00
NSString * accessRole , * ownerLogin , * prefix , * currentRole , * suffix ;
2007-04-26 03:16:19 +02:00
NSEnumerator * acls ;
2007-11-26 18:40:44 +01:00
NSMutableDictionary * userRoles ;
2007-04-26 03:16:19 +02:00
accessRole = nil ;
if ( accessClass = = iCalAccessPublic )
prefix = @ "Public" ;
else if ( accessClass = = iCalAccessPrivate )
prefix = @ "Private" ;
else
prefix = @ "Confidential" ;
2007-11-26 18:40:44 +01:00
userRoles = [ aclMatrix objectForKey : uid ] ;
if ( ! userRoles )
{
userRoles = [ NSMutableDictionary dictionaryWithCapacity : 3 ] ;
[ aclMatrix setObject : userRoles forKey : uid ] ;
}
2009-07-27 23:36:03 +02:00
2007-11-26 18:40:44 +01:00
accessRole = [ userRoles objectForKey : prefix ] ;
if ( ! accessRole )
{
2009-07-27 23:36:03 +02:00
ownerLogin = [ self ownerInContext : context ] ;
if ( [ ownerLogin isEqualToString : uid ] )
2007-11-26 18:40:44 +01:00
accessRole = @ "" ;
2009-07-27 23:36:03 +02:00
else
{
acls = [ [ self aclsForUser : uid ] objectEnumerator ] ;
currentRole = [ acls nextObject ] ;
while ( currentRole && ! accessRole )
if ( [ currentRole hasPrefix : prefix ] )
{
suffix = [ currentRole substringFromIndex : [ prefix length ] ] ;
accessRole = [ NSString stringWithFormat : @ "Component%@" , suffix ] ;
}
else
currentRole = [ acls nextObject ] ;
if ( ! accessRole )
accessRole = @ "" ;
}
2007-11-26 18:40:44 +01:00
[ userRoles setObject : accessRole forKey : prefix ] ;
}
2007-04-26 03:16:19 +02:00
return accessRole ;
}
2009-06-04 02:40:21 +02:00
- ( void ) initializeQuickTablesAclsInContext : ( WOContext * ) localContext
{
NSString * login , * role , * permission ;
iCalAccessClass currentClass ;
unsigned int permStrIndex ;
[ super initializeQuickTablesAclsInContext : localContext ] ;
2014-02-06 20:21:36 +01:00
/ * We assume "userCanAccessAllObjects" will be set after calling the super method . * /
2009-06-04 02:51:47 +02:00
if ( ! userCanAccessAllObjects )
2009-06-04 02:40:21 +02:00
{
login = [ [ localContext activeUser ] login ] ;
permStrIndex = [ @ "Component" length ] ;
}
for ( currentClass = 0 ; currentClass < iCalAccessClassCount ; currentClass + + )
{
2009-06-04 02:51:47 +02:00
if ( userCanAccessAllObjects )
2009-06-04 02:40:21 +02:00
userCanAccessObjectsClassifiedAs [ currentClass ] = YES ;
else
{
role = [ self roleForComponentsWithAccessClass : currentClass
forUser : login ] ;
if ( [ role length ] )
{
permission = [ role substringFromIndex : permStrIndex ] ;
userCanAccessObjectsClassifiedAs [ currentClass ]
= ( [ permission isEqualToString : @ "Viewer" ]
|| [ permission isEqualToString : @ "DAndTViewer" ]
|| [ permission isEqualToString : @ "Modifier" ]
|| [ permission isEqualToString : @ "Responder" ] ) ;
}
}
}
}
2006-12-14 22:20:13 +01:00
- ( NSArray * ) fetchFreeBusyInfosFrom : ( NSCalendarDate * ) _startDate
2006-08-16 00:04:37 +02:00
to : ( NSCalendarDate * ) _endDate
2006-06-15 21:34:10 +02:00
{
static NSArray * infos = nil ; // TODO : move to a plist file
2006-10-26 02:08:24 +02:00
if ( ! infos )
2011-03-30 04:14:56 +02:00
infos = [ [ NSArray alloc ] initWithObjects : @ "c_content" , @ "c_partmails" , @ "c_partstates" ,
2008-11-20 20:17:59 +01:00
@ "c_isopaque" , @ "c_status" , @ "c_cycleinfo" , @ "c_orgmail" , nil ] ;
2006-06-15 21:34:10 +02:00
2008-12-30 20:48:33 +01:00
// We MUST include the protected information when checking for freebusy info as
2008-12-23 19:43:37 +01:00
// we rely on the c_partmails / c_partstates fields for many operations .
2008-05-16 17:52:19 +02:00
return [ self fetchFields : infos
from : _startDate to : _endDate
2007-11-21 18:23:51 +01:00
title : nil
2008-05-16 17:52:19 +02:00
component : @ "vevent"
2008-12-23 19:43:37 +01:00
additionalFilters : nil
includeProtectedInformation : YES ] ;
2006-10-26 02:08:24 +02:00
}
2006-06-15 21:34:10 +02:00
2006-08-16 00:04:37 +02:00
- ( NSArray * ) fetchCoreInfosFrom : ( NSCalendarDate * ) _startDate
2006-10-11 20:48:25 +02:00
to : ( NSCalendarDate * ) _endDate
2007-11-21 18:23:51 +01:00
title : ( NSString * ) title
2006-10-11 20:48:25 +02:00
component : ( id ) _component
2008-05-16 17:52:19 +02:00
{
return [ self fetchCoreInfosFrom : _startDate to : _endDate title : title
component : _component additionalFilters : nil ] ;
}
- ( NSArray * ) fetchCoreInfosFrom : ( NSCalendarDate * ) _startDate
to : ( NSCalendarDate * ) _endDate
title : ( NSString * ) title
component : ( id ) _component
additionalFilters : ( NSString * ) filters
2006-06-15 21:34:10 +02:00
{
static NSArray * infos = nil ; // TODO : move to a plist file
2006-08-16 00:04:37 +02:00
2006-10-11 20:48:25 +02:00
if ( ! infos )
2008-06-13 22:22:51 +02:00
infos = [ [ NSArray alloc ] initWithObjects : @ "c_name" , @ "c_content" ,
@ "c_creationdate" , @ "c_lastmodified" ,
@ "c_version" , @ "c_component" , @ "c_title" ,
@ "c_location" , @ "c_orgmail" , @ "c_status" ,
2010-05-16 19:13:11 +02:00
@ "c_category" , @ "c_classification" , @ "c_isallday" ,
2008-06-13 22:22:51 +02:00
@ "c_isopaque" , @ "c_participants" , @ "c_partmails" ,
@ "c_partstates" , @ "c_sequence" , @ "c_priority" ,
2015-05-13 19:12:15 +02:00
@ "c_cycleinfo" , @ "c_iscycle" , @ "c_nextalarm" , @ "c_description" , nil ] ;
2006-10-11 20:48:25 +02:00
2007-11-21 18:23:51 +01:00
return [ self fetchFields : infos from : _startDate to : _endDate title : title
2008-05-16 17:52:19 +02:00
component : _component
2008-12-23 19:43:37 +01:00
additionalFilters : filters
includeProtectedInformation : NO ] ;
2006-06-15 21:34:10 +02:00
}
2009-04-22 23:02:11 +02:00
- ( NSArray * ) fetchAlarmInfosFrom : ( NSNumber * ) _startUTCDate
to : ( NSNumber * ) _endUTCDate
{
static NSArray * nameFields = nil ;
EOQualifier * qualifier ;
GCSFolder * folder ;
NSArray * records ;
NSString * sql ;
if ( ! nameFields )
nameFields = [ [ NSArray alloc ] initWithObjects : @ "c_name" , @ "c_nextalarm" , @ "c_iscycle" , nil ] ;
folder = [ self ocsFolder ] ;
if ( ! folder )
{
[ self errorWithFormat : @ "(%s): missing folder for fetch!" ,
__PRETTY _FUNCTION __ ] ;
return nil ;
}
2014-12-17 19:57:49 +01:00
sql = [ NSString stringWithFormat : @ "((c_nextalarm <= %u) AND (c_nextalarm >= %u)) OR ((c_nextalarm > 0) AND (c_nextalarm <= %u) AND (c_enddate > %u))" ,
[ _endUTCDate unsignedIntValue ] , [ _startUTCDate unsignedIntValue ] , [ _startUTCDate unsignedIntValue ] , [ _startUTCDate unsignedIntValue ] ] ;
2009-04-22 23:02:11 +02:00
qualifier = [ EOQualifier qualifierWithQualifierFormat : sql ] ;
records = [ folder fetchFields : nameFields matchingQualifier : qualifier ] ;
return records ;
}
2006-06-15 21:34:10 +02:00
/ * URL generation * /
2006-08-16 00:04:37 +02:00
- ( NSString * ) baseURLForAptWithUID : ( NSString * ) _uid
inContext : ( id ) _ctx
{
2006-06-15 21:34:10 +02:00
// TODO : who calls this ?
NSString * url ;
if ( [ _uid length ] = = 0 )
return nil ;
url = [ self baseURLInContext : _ctx ] ;
2007-06-01 06:15:56 +02:00
if ( ! [ url hasSuffix : @ "/" ] )
url = [ url stringByAppendingString : @ "/" ] ;
2006-06-15 21:34:10 +02:00
// TODO : this should run a query to determine the uid !
return [ url stringByAppendingString : _uid ] ;
}
2015-01-26 21:45:42 +01:00
- ( NSString * ) _baseCalDAVURL
{
NSString * davURL ;
if ( ! baseCalDAVURL )
{
davURL = [ [ self realDavURL ] absoluteString ] ;
if ( [ davURL hasSuffix : @ "/" ] )
baseCalDAVURL = [ davURL substringToIndex : [ davURL length ] - 1 ] ;
else
baseCalDAVURL = davURL ;
[ baseCalDAVURL retain ] ;
}
return baseCalDAVURL ;
}
- ( NSString * ) _basePublicCalDAVURL
{
NSString * davURL ;
if ( ! basePublicCalDAVURL )
{
davURL = [ [ self publicDavURL ] absoluteString ] ;
if ( [ davURL hasSuffix : @ "/" ] )
basePublicCalDAVURL = [ davURL substringToIndex : [ davURL length ] - 1 ] ;
else
basePublicCalDAVURL = davURL ;
[ basePublicCalDAVURL retain ] ;
}
return basePublicCalDAVURL ;
}
- ( NSString * ) calDavURL
{
return [ NSString stringWithFormat : @ "%@/" , [ self _baseCalDAVURL ] ] ;
}
- ( NSString * ) webDavICSURL
{
return [ NSString stringWithFormat : @ "%@.ics" , [ self _baseCalDAVURL ] ] ;
}
- ( NSString * ) webDavXMLURL
{
return [ NSString stringWithFormat : @ "%@.xml" , [ self _baseCalDAVURL ] ] ;
}
- ( NSString * ) publicCalDavURL
{
return [ NSString stringWithFormat : @ "%@/" , [ self _basePublicCalDAVURL ] ] ;
}
- ( NSString * ) publicWebDavICSURL
{
return [ NSString stringWithFormat : @ "%@.ics" , [ self _basePublicCalDAVURL ] ] ;
}
- ( NSString * ) publicWebDavXMLURL
{
return [ NSString stringWithFormat : @ "%@.xml" , [ self _basePublicCalDAVURL ] ] ;
}
2006-06-15 21:34:10 +02:00
/ * folder management * /
2007-11-08 18:12:30 +01:00
- ( BOOL ) create
{
BOOL rc ;
2009-11-29 05:19:32 +01:00
SOGoUserSettings * userSettings ;
2007-11-08 18:12:30 +01:00
NSMutableDictionary * calendarSettings ;
SOGoUser * ownerUser ;
rc = [ super create ] ;
if ( rc )
{
2009-08-25 23:28:24 +02:00
ownerUser = [ SOGoUser userWithLogin : [ self ownerInContext : context ] ] ;
2007-11-08 18:12:30 +01:00
userSettings = [ ownerUser userSettings ] ;
calendarSettings = [ userSettings objectForKey : @ "Calendar" ] ;
if ( ! calendarSettings )
{
calendarSettings = [ NSMutableDictionary dictionary ] ;
[ userSettings setObject : calendarSettings forKey : @ "Calendar" ] ;
}
[ userSettings synchronize ] ;
}
return rc ;
}
2006-06-15 21:34:10 +02:00
2010-10-08 21:53:04 +02:00
- ( void ) removeFolderSettings : ( NSMutableDictionary * ) moduleSettings
withReference : ( NSString * ) reference
{
NSMutableArray * refArray ;
NSMutableDictionary * refDict ;
refDict = [ moduleSettings objectForKey : @ "FreeBusyExclusions" ] ;
[ refDict removeObjectForKey : reference ] ;
refDict = [ moduleSettings objectForKey : @ "FolderColors" ] ;
[ refDict removeObjectForKey : reference ] ;
refDict = [ moduleSettings objectForKey : @ "FolderShowAlarms" ] ;
[ refDict removeObjectForKey : reference ] ;
refDict = [ moduleSettings objectForKey : @ "FolderShowTasks" ] ;
[ refDict removeObjectForKey : reference ] ;
2016-04-26 17:37:38 +02:00
refDict = [ moduleSettings objectForKey : @ "FolderSynchronize" ] ;
[ refDict removeObjectForKey : reference ] ;
refDict = [ moduleSettings objectForKey : @ "NotifyOnExternalModifications" ] ;
[ refDict removeObjectForKey : reference ] ;
refDict = [ moduleSettings objectForKey : @ "NotifyOnPersonalModifications" ] ;
[ refDict removeObjectForKey : reference ] ;
refDict = [ moduleSettings objectForKey : @ "NotifyUserOnPersonalModifications" ] ;
[ refDict removeObjectForKey : reference ] ;
2016-04-27 21:25:01 +02:00
refArray = [ moduleSettings objectForKey : @ "FoldersOrder" ] ;
[ refArray removeObject : nameInContainer ] ;
2010-10-08 21:53:04 +02:00
refArray = [ moduleSettings objectForKey : @ "InactiveFolders" ] ;
[ refArray removeObject : nameInContainer ] ;
[ super removeFolderSettings : moduleSettings
withReference : reference ] ;
}
2006-08-16 00:04:37 +02:00
- ( id ) lookupHomeFolderForUID : ( NSString * ) _uid
inContext : ( id ) _ctx
{
2006-06-15 21:34:10 +02:00
// TODO : DUP to SOGoGroupFolder
NSException * error = nil ;
NSArray * path ;
id ctx , result ;
if ( ! [ _uid isNotNull ] )
return nil ;
2007-06-01 06:15:56 +02:00
2006-06-15 21:34:10 +02:00
/ * create subcontext , so that we don ' t destroy our environment * /
2007-04-11 21:08:58 +02:00
if ( ( ctx = [ context createSubContext ] ) = = nil ) {
2006-06-15 21:34:10 +02:00
[ self errorWithFormat : @ "could not create SOPE subcontext!" ] ;
return nil ;
}
/ * build path * /
path = _uid ! = nil ? [ NSArray arrayWithObjects : & _uid count : 1 ] : nil ;
/ * traverse path * /
result = [ [ ctx application ] traversePathArray : path inContext : ctx
error : & error acquire : NO ] ;
if ( error ! = nil ) {
2007-07-27 19:30:57 +02:00
[ self errorWithFormat : @ "folder lookup failed (c_uid=%@): %@" ,
2006-06-15 21:34:10 +02:00
_uid , error ] ;
return nil ;
}
[ self debugWithFormat : @ "Note: got folder for uid %@ path %@: %@" ,
_uid , [ path componentsJoinedByString : @ "=>" ] , result ] ;
2008-08-18 17:21:23 +02:00
2006-06-15 21:34:10 +02:00
return result ;
}
2009-03-23 22:19:55 +01:00
//
// This method returns an array containing all the calendar folders
// of a specific user , excluding her / his subscriptions .
//
- ( NSArray * ) lookupCalendarFoldersForUID : ( NSString * ) theUID
{
NSArray * aFolders ;
2011-08-08 20:52:17 +02:00
SOGoUser * theUser ;
2009-03-23 22:19:55 +01:00
NSEnumerator * e ;
NSMutableArray * aUserFolders ;
SOGoAppointmentFolders * aParent ;
2011-08-08 20:52:17 +02:00
SOGoFolder * aFolder ;
2009-03-23 22:19:55 +01:00
aUserFolders = [ NSMutableArray arrayWithCapacity : 16 ] ;
2011-08-08 20:52:17 +02:00
theUser = [ SOGoUser userWithLogin : theUID ] ;
aParent = [ theUser calendarsFolderInContext : context ] ;
2015-09-11 02:07:42 +02:00
if ( [ aParent isKindOfClass : [ NSException class ] ] )
return nil ;
2009-03-23 22:19:55 +01:00
aFolders = [ aParent subFolders ] ;
e = [ aFolders objectEnumerator ] ;
2011-08-08 20:52:17 +02:00
while ( ( aFolder = [ e nextObject ] ) )
2009-03-23 22:19:55 +01:00
{
if ( ! [ aFolder isSubscription ] )
[ aUserFolders addObject : aFolder ] ;
}
return aUserFolders ;
}
2006-08-16 00:04:37 +02:00
- ( NSArray * ) lookupCalendarFoldersForUIDs : ( NSArray * ) _uids
inContext : ( id ) _ctx
{
2006-06-15 21:34:10 +02:00
/ * Note : can return NSNull objects in the array ! * /
NSMutableArray * folders ;
NSEnumerator * e ;
2007-09-15 00:01:02 +02:00
NSString * uid , * ownerLogin ;
2010-07-15 19:05:29 +02:00
SOGoUser * user ;
2007-09-15 00:01:02 +02:00
id folder ;
ownerLogin = [ self ownerInContext : context ] ;
2006-06-15 21:34:10 +02:00
if ( [ _uids count ] = = 0 ) return nil ;
folders = [ NSMutableArray arrayWithCapacity : 16 ] ;
e = [ _uids objectEnumerator ] ;
2007-09-15 00:01:02 +02:00
while ( ( uid = [ e nextObject ] ) )
{
if ( [ uid isEqualToString : ownerLogin ] )
folder = self ;
else
{
2010-07-15 19:05:29 +02:00
user = [ SOGoUser userWithLogin : uid ] ;
folder = [ user personalCalendarFolderInContext : context ] ;
2007-09-15 00:01:02 +02:00
if ( ! [ folder isNotNull ] )
[ self logWithFormat : @ "Note: did not find folder for uid: '%@'" , uid ] ;
}
2007-11-07 16:58:43 +01:00
if ( folder )
[ folders addObject : folder ] ;
2007-09-15 00:01:02 +02:00
}
2006-06-15 21:34:10 +02:00
return folders ;
}
2006-08-16 00:04:37 +02:00
- ( NSArray * ) lookupFreeBusyObjectsForUIDs : ( NSArray * ) _uids
inContext : ( id ) _ctx
{
2006-06-15 21:34:10 +02:00
/ * Note : can return NSNull objects in the array ! * /
NSMutableArray * objs ;
NSEnumerator * e ;
NSString * uid ;
if ( [ _uids count ] = = 0 ) return nil ;
objs = [ NSMutableArray arrayWithCapacity : 16 ] ;
e = [ _uids objectEnumerator ] ;
2008-05-16 17:52:19 +02:00
while ( ( uid = [ e nextObject ] ) )
{
id obj ;
2006-06-15 21:34:10 +02:00
2008-05-16 17:52:19 +02:00
obj = [ self lookupHomeFolderForUID : uid inContext : nil ] ;
if ( [ obj isNotNull ] )
{
obj = [ obj lookupName : @ "freebusy.ifb" inContext : nil acquire : NO ] ;
if ( [ obj isKindOfClass : [ NSException class ] ] )
obj = nil ;
}
if ( ! [ obj isNotNull ] )
[ self logWithFormat : @ "Note: did not find freebusy.ifb for uid: '%@'" ,
uid ] ;
2006-06-15 21:34:10 +02:00
2008-05-16 17:52:19 +02:00
/ * Note : intentionally add ' null ' folders to allow a mapping * /
if ( ! obj )
obj = [ NSNull null ] ;
[ objs addObject : obj ] ;
}
2006-06-15 21:34:10 +02:00
return objs ;
}
2006-08-16 00:04:37 +02:00
- ( NSArray * ) uidsFromICalPersons : ( NSArray * ) _persons
{
2006-06-15 21:34:10 +02:00
/ * Note : can return NSNull objects in the array ! * /
NSMutableArray * uids ;
2009-09-25 16:42:33 +02:00
SOGoUserManager * um ;
2006-06-15 21:34:10 +02:00
unsigned i , count ;
2008-06-30 20:52:20 +02:00
iCalPerson * person ;
NSString * email ;
NSString * uid ;
2006-06-15 21:34:10 +02:00
2008-06-30 20:52:20 +02:00
if ( _persons )
2008-05-16 17:52:19 +02:00
{
2008-06-30 20:52:20 +02:00
count = [ _persons count ] ;
uids = [ NSMutableArray arrayWithCapacity : count + 1 ] ;
2009-09-25 16:42:33 +02:00
um = [ SOGoUserManager sharedUserManager ] ;
2008-06-30 20:52:20 +02:00
for ( i = 0 ; i < count ; i + + )
{
person = [ _persons objectAtIndex : i ] ;
email = [ person rfc822Email ] ;
if ( [ email isNotNull ] )
uid = [ um getUIDForEmail : email ] ;
else
uid = nil ;
if ( ! uid )
uid = ( NSString * ) [ NSNull null ] ;
[ uids addObject : uid ] ;
}
2006-06-15 21:34:10 +02:00
}
2008-06-30 20:52:20 +02:00
else
uids = nil ;
2008-05-16 17:52:19 +02:00
2006-06-15 21:34:10 +02:00
return uids ;
}
2008-06-30 20:52:20 +02:00
- ( NSArray * ) lookupCalendarFoldersForICalPerson : ( NSArray * ) _persons
inContext : ( id ) _ctx
2006-06-15 21:34:10 +02:00
{
/ * Note : can return NSNull objects in the array ! * /
2008-06-30 20:52:20 +02:00
NSArray * uids , * folders ;
2006-06-15 21:34:10 +02:00
2008-06-30 20:52:20 +02:00
uids = [ self uidsFromICalPersons : _persons ] ;
if ( uids )
folders = [ self lookupCalendarFoldersForUIDs : uids
inContext : _ctx ] ;
else
folders = nil ;
2006-06-15 21:34:10 +02:00
2008-06-30 20:52:20 +02:00
return folders ;
2006-06-15 21:34:10 +02:00
}
/ * folder type * /
2007-02-09 22:21:35 +01:00
- ( NSString * ) folderType
{
return @ "Appointment" ;
}
2007-09-15 00:01:02 +02:00
- ( BOOL ) isActive
2007-08-24 20:47:32 +02:00
{
2009-11-29 05:19:32 +01:00
SOGoUserSettings * settings ;
2008-05-06 01:39:07 +02:00
NSArray * inactiveFolders ;
2007-08-24 20:47:32 +02:00
2007-09-15 00:01:02 +02:00
settings = [ [ context activeUser ] userSettings ] ;
2008-05-06 01:39:07 +02:00
inactiveFolders
= [ [ settings objectForKey : @ "Calendar" ] objectForKey : @ "InactiveFolders" ] ;
2007-08-24 20:47:32 +02:00
2008-06-13 22:22:51 +02:00
return ( ! [ inactiveFolders containsObject : nameInContainer ] ) ;
2007-08-24 20:47:32 +02:00
}
2015-01-26 21:45:42 +01:00
- ( BOOL ) isWebCalendar
{
return ( [ self isKindOfClass : [ SOGoWebAppointmentFolder class ] ] ) ;
}
2012-04-19 16:24:37 +02:00
- ( NSString * ) importComponent : ( iCalEntityObject * ) event
timezone : ( iCalTimeZone * ) timezone
2009-09-02 21:14:15 +02:00
{
SOGoAppointmentObject * object ;
2012-04-19 16:24:37 +02:00
NSMutableString * content ;
2012-11-17 21:38:29 +01:00
NSString * uid ;
2009-09-02 21:14:15 +02:00
2015-12-01 15:26:52 +01:00
// We first look if the event has any / or + in its UID . If that ' s the case
// we generate a new UID based on a GUID
2012-11-17 21:38:29 +01:00
uid = [ event uid ] ;
2015-12-01 15:26:52 +01:00
if ( [ uid rangeOfCharacterFromSet : [ NSCharacterSet characterSetWithCharactersInString : @ "+/" ] ] . location ! = NSNotFound )
2012-11-17 21:38:29 +01:00
{
uid = [ self globallyUniqueObjectId ] ;
[ event setUid : uid ] ;
}
2015-12-01 15:26:52 +01:00
else
{
// We also look if there ' s an event with the same UID in our calendar . If not ,
// let ' s reuse what is in the event , otherwise generate a new GUID and use it .
object = [ self lookupName : uid
inContext : context
acquire : NO ] ;
if ( object && ! [ object isKindOfClass : [ NSException class ] ] )
{
uid = [ self globallyUniqueObjectId ] ;
[ event setUid : uid ] ;
}
}
2012-11-17 21:38:29 +01:00
2016-12-21 17:43:08 +01:00
// If the UID isn ' t ending with the ".ics" extension , let ' s add it to avoid
// confusing broken CalDAV client ( like Nokia N9 and Korganizer ) that relies
// on this ( see #2308 )
if ( ! [ [ uid lowercaseString ] hasSuffix : @ ".ics" ] )
uid = [ NSString stringWithFormat : @ "%@.ics" , uid ] ;
2009-09-02 21:14:15 +02:00
object = [ SOGoAppointmentObject objectWithName : uid
inContainer : self ] ;
2009-09-28 15:25:14 +02:00
[ object setIsNew : YES ] ;
2012-04-19 16:24:37 +02:00
content = [ NSMutableString stringWithString : @ "BEGIN:VCALENDAR\n" ] ;
2015-06-09 19:38:10 +02:00
[ content appendFormat : @ "PRODID:-//Inverse inc./SOGo %@//EN\n" , SOGoVersion ] ;
2012-04-19 16:24:37 +02:00
if ( timezone )
[ content appendFormat : @ "%@\n" , [ timezone versitString ] ] ;
[ content appendFormat : @ "%@\nEND:VCALENDAR" , [ event versitString ] ] ;
2014-07-30 20:51:00 +02:00
return ( [ object saveCalendar : [ iCalCalendar parseSingleFromSource : content ] ] = = nil ) ? uid : nil ;
2009-09-02 21:14:15 +02:00
}
2011-04-16 03:35:06 +02:00
/ * *
* Import all components of a vCalendar .
* @ param calendar the calendar to import
* @ return the number of components imported
* /
2009-09-10 19:26:57 +02:00
- ( int ) importCalendar : ( iCalCalendar * ) calendar
{
2011-04-12 16:12:22 +02:00
NSArray * vtimezones ;
2009-09-23 17:00:50 +02:00
NSMutableArray * components ;
2012-04-19 16:24:37 +02:00
NSMutableDictionary * timezones , * uids ;
2014-07-30 20:51:00 +02:00
NSString * tzId , * uid , * originalUid ;
2011-04-12 16:12:22 +02:00
iCalEntityObject * element ;
iCalTimeZone * timezone ;
2012-04-19 16:24:37 +02:00
iCalCalendar * masterCalendar ;
2011-04-16 03:35:06 +02:00
iCalEvent * event ;
2013-01-25 16:21:28 +01:00
NSAutoreleasePool * pool ;
2011-03-04 15:14:12 +01:00
2009-09-10 19:26:57 +02:00
int imported , count , i ;
2012-06-19 15:17:48 +02:00
2009-09-10 19:26:57 +02:00
imported = 0 ;
if ( calendar )
{
2011-04-12 16:12:22 +02:00
// Build a hash with the timezones includes in the calendar
vtimezones = [ calendar timezones ] ;
count = [ vtimezones count ] ;
timezones = [ NSMutableDictionary dictionaryWithCapacity : count ] ;
for ( i = 0 ; i < count ; i + + )
{
timezone = ( iCalTimeZone * ) [ vtimezones objectAtIndex : i ] ;
2012-04-19 16:24:37 +02:00
[ timezones setValue : timezone
2011-04-12 16:12:22 +02:00
forKey : [ timezone tzId ] ] ;
}
// Parse events / todos / journals and import them
2012-04-19 16:24:37 +02:00
uids = [ NSMutableDictionary dictionary ] ;
2009-09-23 17:00:50 +02:00
components = [ [ calendar events ] mutableCopy ] ;
2009-09-23 20:17:31 +02:00
[ components autorelease ] ;
2009-09-23 17:00:50 +02:00
[ components addObjectsFromArray : [ calendar todos ] ] ;
2012-04-18 18:56:13 +02:00
// [ components addObjectsFromArray : [ calendar journals ] ] ;
// [ components addObjectsFromArray : [ calendar freeBusys ] ] ;
2009-09-10 19:26:57 +02:00
count = [ components count ] ;
2013-01-25 16:21:28 +01:00
pool = [ [ NSAutoreleasePool alloc ] init ] ;
2009-09-10 19:26:57 +02:00
for ( i = 0 ; i < count ; i + + )
2011-04-12 16:12:22 +02:00
{
2013-01-25 16:21:28 +01:00
if ( i % 10 = = 0 )
{
DESTROY ( pool ) ;
pool = [ [ NSAutoreleasePool alloc ] init ] ;
}
2012-04-19 16:24:37 +02:00
timezone = nil ;
2011-04-12 16:12:22 +02:00
element = [ components objectAtIndex : i ] ;
2019-11-27 23:00:28 +01:00
if ( [ element isKindOfClass : iCalEventK ] )
2011-04-12 16:12:22 +02:00
{
2019-11-27 23:00:28 +01:00
event = ( iCalEvent * ) element ;
2020-01-29 18:50:58 +01:00
timezone = [ event adjustInContext : self -> context withTimezones : timezones ] ;
2019-11-27 23:00:28 +01:00
if ( [ event recurrenceId ] )
2011-04-16 03:35:06 +02:00
{
2019-11-27 23:00:28 +01:00
// Event is an occurrence of a repeating event
if ( ( uid = [ uids valueForKey : [ event uid ] ] ) )
2012-04-19 16:24:37 +02:00
{
2019-11-27 23:00:28 +01:00
SOGoAppointmentObject * master = [ self lookupName : uid
inContext : context
acquire : NO ] ;
if ( master )
2012-04-19 16:24:37 +02:00
{
2019-11-27 23:00:28 +01:00
// Associate the occurrence to the master event and skip the actual import process
masterCalendar = [ master calendar : NO secure : NO ] ;
[ masterCalendar addToEvents : event ] ;
if ( timezone )
[ masterCalendar addTimeZone : timezone ] ;
[ master saveCalendar : masterCalendar ] ;
continue ;
2012-04-19 16:24:37 +02:00
}
}
2011-04-16 03:35:06 +02:00
}
2011-04-12 16:12:22 +02:00
}
2012-04-19 16:24:37 +02:00
originalUid = [ element uid ] ;
if ( ( uid = [ self importComponent : element
timezone : timezone ] ) )
{
imported + + ;
2016-12-21 17:43:08 +01:00
[ uids setValue : uid forKey : originalUid ] ;
2012-04-19 16:24:37 +02:00
}
2011-04-12 16:12:22 +02:00
}
2013-01-25 16:21:28 +01:00
DESTROY ( pool ) ;
2009-09-10 19:26:57 +02:00
}
2011-04-12 16:12:22 +02:00
2009-09-10 19:26:57 +02:00
return imported ;
}
2010-01-15 00:19:19 +01:00
/ * acls * /
2016-06-23 14:58:25 +02:00
/ * Compare two permissions to set first the highest access right , if unknown , then
do nothing * /
static NSComparisonResult _comparePermissions ( id perm1 , id perm2 , void * context )
{
static NSDictionary * permMap = nil ;
NSNumber * num_1 , * num_2 ;
if ( ! permMap )
{
NSMutableArray * numberObjs ;
NSUInteger i , max = 16 ;
numberObjs = [ NSMutableArray arrayWithCapacity : max ] ;
for ( i = 0 ; i < max ; i + + )
[ numberObjs addObject : [ NSNumber numberWithInteger : i ] ] ;
/ * Build the map to compare easily * /
permMap = [ [ NSDictionary alloc ] initWithObjects : numberObjs
forKeys : [ NSArray arrayWithObjects :
SOGoRole_ObjectEraser ,
SOGoRole_ObjectCreator ,
SOGoRole_ObjectEditor ,
SOGoCalendarRole_ConfidentialModifier ,
SOGoCalendarRole_ConfidentialResponder ,
SOGoCalendarRole_ConfidentialViewer ,
SOGoCalendarRole_ConfidentialDAndTViewer ,
SOGoCalendarRole_PrivateModifier ,
SOGoCalendarRole_PrivateResponder ,
SOGoCalendarRole_PrivateViewer ,
SOGoCalendarRole_PrivateDAndTViewer ,
SOGoCalendarRole_PublicModifier ,
SOGoCalendarRole_PublicResponder ,
SOGoCalendarRole_PublicViewer ,
SOGoCalendarRole_PublicDAndTViewer ,
SOGoCalendarRole_FreeBusyReader , nil ] ] ;
[ permMap retain ] ;
}
num_1 = [ permMap objectForKey : perm1 ] ;
if ( ! num_1 )
num_1 = [ NSNumber numberWithInteger : 255 ] ;
num_2 = [ permMap objectForKey : perm2 ] ;
if ( ! num_2 )
num_2 = [ NSNumber numberWithInteger : 255 ] ;
return [ num_1 compare : num_2 ] ;
}
2010-01-15 00:19:19 +01:00
- ( NSArray * ) aclsForUser : ( NSString * ) uid
forObjectAtPath : ( NSArray * ) objectPathArray
{
NSMutableArray * aclsForUser ;
NSArray * superAcls ;
superAcls = [ super aclsForUser : uid forObjectAtPath : objectPathArray ] ;
if ( [ uid isEqualToString : [ self defaultUserID ] ] )
{
if ( superAcls )
{
aclsForUser = [ superAcls mutableCopy ] ;
[ aclsForUser autorelease ] ;
}
else
aclsForUser = [ NSMutableArray array ] ;
[ aclsForUser addObject : SoRole_Authenticated ] ;
}
else
2014-02-06 20:21:36 +01:00
{
2016-06-23 14:58:25 +02:00
/ * Sort setting the highest access right first , so in the case
of a user member of several groups , the highest access right
is checked first , for instance , in
[ SOGoAppointmentFolder : roleForComponentsWithAccessClass : forUser ] * /
aclsForUser = ( NSMutableArray * ) [ superAcls sortedArrayUsingFunction : _comparePermissions
context : NULL ] ;
2014-02-06 20:21:36 +01:00
}
2010-01-15 00:19:19 +01:00
return aclsForUser ;
}
2010-01-19 13:28:10 +01:00
/ * caldav - proxy * /
2014-02-06 20:21:36 +01:00
- ( SOGoAppointmentProxyPermission ) proxyPermissionForUserWithLogin : ( NSString * ) login
2010-01-15 00:19:19 +01:00
{
2010-01-19 13:28:10 +01:00
SOGoAppointmentProxyPermission permission ;
2010-01-15 00:19:19 +01:00
NSArray * roles ;
2010-01-19 13:28:10 +01:00
static NSArray * readRoles = nil ;
static NSArray * writeRoles = nil ;
if ( ! readRoles )
{
readRoles = [ NSArray arrayWithObjects :
SOGoCalendarRole_ConfidentialViewer ,
SOGoCalendarRole_ConfidentialDAndTViewer ,
SOGoCalendarRole_PrivateViewer ,
SOGoCalendarRole_PrivateDAndTViewer ,
SOGoCalendarRole_PublicViewer ,
SOGoCalendarRole_PublicDAndTViewer ,
nil ] ;
[ readRoles retain ] ;
}
if ( ! writeRoles )
{
writeRoles = [ NSArray arrayWithObjects :
SOGoRole_ObjectCreator ,
SOGoRole_ObjectEraser ,
SOGoCalendarRole_ConfidentialModifier ,
SOGoCalendarRole_ConfidentialResponder ,
SOGoCalendarRole_PrivateModifier ,
SOGoCalendarRole_PrivateResponder ,
SOGoCalendarRole_PublicModifier ,
SOGoCalendarRole_PublicResponder ,
nil ] ;
[ writeRoles retain ] ;
}
permission = SOGoAppointmentProxyPermissionNone ;
roles = [ self aclsForUser : login ] ;
if ( [ roles count ] )
{
if ( [ roles firstObjectCommonWithArray : readRoles ] )
permission = SOGoAppointmentProxyPermissionRead ;
if ( [ roles firstObjectCommonWithArray : writeRoles ] )
permission = SOGoAppointmentProxyPermissionWrite ;
}
return permission ;
}
- ( NSArray * ) aclUsersWithProxyWriteAccess : ( BOOL ) write
{
NSMutableArray * users ;
NSArray * aclUsers ;
NSString * aclUser ;
SOGoAppointmentProxyPermission permission ;
int count , max ;
permission = ( write
? SOGoAppointmentProxyPermissionWrite
: SOGoAppointmentProxyPermissionRead ) ;
aclUsers = [ self aclUsers ] ;
max = [ aclUsers count ] ;
users = [ NSMutableArray arrayWithCapacity : max ] ;
for ( count = 0 ; count < max ; count + + )
2010-01-15 00:19:19 +01:00
{
2010-01-19 13:28:10 +01:00
aclUser = [ aclUsers objectAtIndex : count ] ;
if ( [ self proxyPermissionForUserWithLogin : aclUser ]
= = permission )
[ users addObject : aclUser ] ;
2010-01-15 00:19:19 +01:00
}
2010-01-19 13:28:10 +01:00
return users ;
2010-01-15 00:19:19 +01:00
}
2014-06-11 16:24:04 +02:00
- ( NSNumber * ) activeTasks
2014-06-10 22:18:12 +02:00
{
NSArray * tasksList ;
NSMutableArray * fields ;
2014-06-11 16:24:04 +02:00
NSNumber * activeTasks ;
2014-06-10 22:18:12 +02:00
fields = [ NSMutableArray arrayWithObjects : @ "c_component" , @ "c_status" , nil ] ;
tasksList = [ self bareFetchFields : fields
from : nil
to : nil
title : nil
component : @ "vtodo"
2014-06-26 22:42:05 +02:00
additionalFilters : @ "c_status != 1 AND c_status != 3" ] ;
2014-06-10 22:18:12 +02:00
2014-06-11 16:24:04 +02:00
activeTasks = [ NSNumber numberWithInt : [ tasksList count ] ] ;
2014-06-10 22:18:12 +02:00
return activeTasks ;
}
2014-09-12 14:34:15 +02:00
- ( void ) findEntityForClosestAlarm : ( id * ) theEntity
timezone : ( NSTimeZone * ) theTimeZone
startDate : ( NSCalendarDate * * ) theStartDate
endDate : ( NSCalendarDate * * ) theEndDate
{
// If the event is recurring , we MUST find the right occurence .
if ( [ * theEntity hasRecurrenceRules ] )
{
NSCalendarDate * startDate , * endDate ;
NSMutableDictionary * quickRecord ;
NSCalendarDate * start , * end ;
NGCalendarDateRange * range ;
NSMutableArray * alarms ;
iCalDateTime * date ;
iCalTimeZone * tz ;
BOOL b , isEvent ;
isEvent = [ * theEntity isKindOfClass : [ iCalEvent class ] ] ;
b = NO ;
if ( isEvent )
b = [ * theEntity isAllDay ] ;
// We build a fake "quick record" . Our record must include some mandatory info , like @ "c_startdate" and @ "c_enddate"
quickRecord = [ NSMutableDictionary dictionaryWithObjectsAndKeys : [ NSNumber numberWithBool : b ] , @ "c_isallday" ,
[ NSNumber numberWithBool : [ * theEntity isRecurrent ] ] , @ "c_iscycle" ,
nil ] ;
startDate = [ * theEntity startDate ] ;
endDate = ( isEvent ? [ * theEntity endDate ] : [ * theEntity due ] ) ;
if ( [ startDate isNotNull ] )
{
if ( b )
{
// An all - day event usually doesn ' t have a timezone associated to its
// start date ; however , if it does , we convert it to GMT .
date = ( iCalDateTime * ) [ * theEntity uniqueChildWithTag : @ "dtstart" ] ;
tz = [ ( iCalDateTime * ) date timeZone ] ;
if ( tz )
startDate = [ tz computedDateForDate : startDate ] ;
}
[ quickRecord setObject : [ * theEntity quickRecordDateAsNumber : startDate
withOffset : 0
forAllDay : b ]
forKey : @ "c_startdate" ] ;
}
if ( [ endDate isNotNull ] )
{
if ( b )
{
// An all - day event usually doesn ' t have a timezone associated to its
// end date ; however , if it does , we convert it to GMT .
date = ( isEvent ? ( iCalDateTime * ) [ * theEntity uniqueChildWithTag : @ "dtend" ] : ( iCalDateTime * ) [ * theEntity uniqueChildWithTag : @ "due" ] ) ;
tz = [ ( iCalDateTime * ) date timeZone ] ;
if ( tz )
endDate = [ tz computedDateForDate : endDate ] ;
}
[ quickRecord setObject : [ * theEntity quickRecordDateAsNumber : endDate
withOffset : ( ( b ) ? -1 : 0 )
forAllDay : b ]
forKey : @ "c_enddate" ] ;
}
if ( [ * theEntity isRecurrent ] )
{
NSCalendarDate * date ;
date = [ * theEntity lastPossibleRecurrenceStartDate ] ;
if ( ! date )
{
/ * this could also be * nil * , but in the end it makes the fetchspecs
more complex - thus we set it to a "reasonable" distant future * /
date = iCalDistantFuture ;
}
[ quickRecord setObject : [ * theEntity quickRecordDateAsNumber : date
withOffset : 0 forAllDay : NO ]
forKey : @ "c_cycleenddate" ] ;
[ quickRecord setObject : [ * theEntity cycleInfo ] forKey : @ "c_cycleinfo" ] ;
}
alarms = [ NSMutableArray array ] ;
start = [ NSCalendarDate date ] ;
end = [ start addYear : 1 month : 0 day : 0 hour : 0 minute : 0 second : 0 ] ;
range = [ NGCalendarDateRange calendarDateRangeWithStartDate : start
endDate : end ] ;
[ self flattenCycleRecord : quickRecord
forRange : range
intoArray : alarms
withCalendar : [ * theEntity parent ] ] ;
if ( [ alarms count ] )
{
NSDictionary * anAlarm ;
id o ;
// Take the first alarm since it ' s the ' closest ' one
anAlarm = [ alarms objectAtIndex : 0 ] ;
// We grab the last one and we use that info . The logic is simple .
// 1. grab the RECURRENCE - ID , if found in our master event , use that
// 2. if not found , use the master ' s event info but adjust the start / end date
if ( ( o = [ [ * theEntity parent ] eventWithRecurrenceID : [ anAlarm objectForKey : @ "c_recurrence_id" ] ] ) )
{
* theEntity = o ;
* theStartDate = [ * theEntity startDate ] ;
* theEndDate = [ * theEntity endDate ] ;
}
else
{
* theStartDate = [ NSCalendarDate dateWithTimeIntervalSince1970 : [ [ anAlarm objectForKey : @ "c_startdate" ] intValue ] ] ;
* theEndDate = [ NSCalendarDate dateWithTimeIntervalSince1970 : [ [ anAlarm objectForKey : @ "c_enddate" ] intValue ] ] ;
}
[ * theStartDate setTimeZone : theTimeZone ] ;
[ * theEndDate setTimeZone : theTimeZone ] ;
}
} // if ( [ event hasRecurrenceRules ] ) . . .
}
2014-06-10 22:18:12 +02:00
2006-06-15 21:34:10 +02:00
@ end / * SOGoAppointmentFolder * /