1 /* SOGoAppointmentFolderObject.m - this file is part of SOGo 2 * 3 * Copyright (C) 2010-2012 Inverse inc. 4 * 5 * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca> 6 * 7 * This file is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This file is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; see the file COPYING. If not, write to 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 * Boston, MA 02111-1307, USA. 21 */ 22 23#import <Foundation/NSArray.h> 24#import <Foundation/NSAutoreleasePool.h> 25#import <Foundation/NSCalendarDate.h> 26#import <Foundation/NSDictionary.h> 27#import <Foundation/NSString.h> 28 29#import <NGObjWeb/WOContext+SoObjects.h> 30#import <NGObjWeb/WOResponse.h> 31#import <NGExtensions/NSObject+Logs.h> 32 33#import <NGCards/iCalCalendar.h> 34#import <NGCards/iCalTimeZone.h> 35 36#import <SOGo/SOGoBuild.h> 37#import <SOGo/SOGoDomainDefaults.h> 38#import <SOGo/SOGoUser.h> 39 40#import "SOGoAppointmentFolder.h" 41#import "SOGoCalendarComponent.h" 42 43#import "SOGoAppointmentFolderObject.h" 44 45static NSArray *contentFields = nil; 46 47@implementation SOGoAppointmentFolderObject 48 49+ (void) initialize 50{ 51 if (!contentFields) 52 contentFields = [[NSArray alloc] initWithObjects: @"c_name", @"c_version", 53 @"c_lastmodified", @"c_creationdate", 54 @"c_component", @"c_content", nil]; 55} 56 57- (id) init 58{ 59 int davCalendarStartTimeLimit; 60 SOGoUser *user; 61 62 if ((self = [super init])) 63 { 64 folder = nil; 65 66 user = [context activeUser]; 67 davCalendarStartTimeLimit 68 = [[user domainDefaults] davCalendarStartTimeLimit]; 69 /* 43200 = 60 * 60 * 24 / 2 */ 70 davTimeHalfLimitSeconds = davCalendarStartTimeLimit * 43200; 71 } 72 73 return self; 74} 75 76- (void) dealloc 77{ 78 [folder release]; 79 [super dealloc]; 80} 81 82- (BOOL) isFolderish 83{ 84 return NO; 85} 86 87- (SOGoAppointmentFolder *) _folder 88{ 89 NSString *folderName; 90 int length; 91 92 if (!folder) 93 { 94 length = [nameInContainer length]; 95 if (length > 3) 96 { 97 folderName = [nameInContainer substringToIndex: length - 4]; 98 folder = [container lookupName: folderName 99 inContext: context 100 acquire: NO]; 101 [folder retain]; 102 } 103 } 104 105 return folder; 106} 107 108- (NSArray *) aclsForUser: (NSString *) login 109{ 110 return [[self _folder] aclsForUser: login]; 111} 112 113- (void) _extractTimeZones: (NSArray *) timeZones 114 intoDictionary: (NSMutableDictionary *) tzDict 115{ 116 int count, max; 117 iCalTimeZone *timeZone; 118 NSString *tzId; 119 120 max = [timeZones count]; 121 for (count = 0; count < max; count++) 122 { 123 timeZone = [timeZones objectAtIndex: count]; 124 tzId = [timeZone tzId]; 125 if (![tzDict objectForKey: tzId]) 126 [tzDict setObject: timeZone forKey: tzId]; 127 } 128} 129 130- (void) _extractCalendarsData: (NSArray *) calendars 131 intoTimeZones: (NSMutableDictionary *) timeZones 132 andComponents: (NSMutableArray *) components 133{ 134 int count, max; 135 iCalCalendar *calendar; 136 137 max = [calendars count]; 138 for (count = 0; count < max; count++) 139 { 140 calendar = [calendars objectAtIndex: count]; 141 [self _extractTimeZones: [calendar timezones] 142 intoDictionary: timeZones]; 143 [components addObjectsFromArray: [calendar allObjects]]; 144 } 145} 146 147- (NSArray *) _fetchFolderRecords 148{ 149 NSCalendarDate *start, *end; 150 151 if (davTimeHalfLimitSeconds) 152 { 153 start = [[NSCalendarDate date] addYear: 0 154 month: 0 155 day: 0 156 hour: 0 157 minute: 0 158 second: -davTimeHalfLimitSeconds]; 159 end = [start addYear: 0 160 month: 0 161 day: 0 162 hour: 0 163 minute: 0 164 second: (2 * davTimeHalfLimitSeconds)]; 165 } 166 else 167 { 168 start = nil; 169 end = nil; 170 } 171 172 return [[self _folder] bareFetchFields: contentFields 173 from: start 174 to: end 175 title: nil 176 component: nil 177 additionalFilters: nil]; 178} 179 180- (NSArray *) _folderCalendars 181{ 182 NSArray *records; 183 NSMutableArray *calendars; 184 SOGoCalendarComponent *component; 185 NSAutoreleasePool *pool; 186 int count, max; 187 iCalCalendar *calendar; 188 NSString *name; 189 190 records = [self _fetchFolderRecords]; 191 max = [records count]; 192 calendars = [NSMutableArray arrayWithCapacity: max]; 193 pool = nil; 194 195 // This can consume a significant amount of memory so 196 // we use a local autorelease pool to avoid running 197 // out of memory. 198 for (count = 0; count < max; count++) 199 { 200 if (count % 100 == 0) 201 { 202 RELEASE(pool); 203 pool = [[NSAutoreleasePool alloc] init]; 204 } 205 206 name = [[records objectAtIndex: count] objectForKey: @"c_name"]; 207 component = [folder lookupName: name 208 inContext: context 209 acquire: NO]; 210 calendar = [component calendar: NO secure: !activeUserIsOwner]; 211 if (calendar) 212 [calendars addObject: calendar]; 213 else 214 [self errorWithFormat: @"record with c_name '%@' should obviously not" 215 @" be listed here", name]; 216 } 217 218 RELEASE(pool); 219 220 return calendars; 221} 222 223- (iCalCalendar *) contentCalendar 224{ 225 NSArray *calendars; 226 iCalCalendar *calendar; 227 NSMutableDictionary *timeZones; 228 NSMutableArray *components; 229 230 calendars = [self _folderCalendars]; 231 timeZones = [NSMutableDictionary dictionaryWithCapacity: 16]; 232 components = [NSMutableArray arrayWithCapacity: [calendars count] * 2]; 233 [self _extractCalendarsData: calendars 234 intoTimeZones: timeZones andComponents: components]; 235 236 calendar = [iCalCalendar groupWithTag: @"vcalendar"]; 237 [calendar setMethod: @"PUBLISH"]; 238 [calendar setVersion: @"2.0"]; 239 [calendar setProdID: [NSString stringWithFormat: 240 @"-//Inverse inc./SOGo %@//EN", 241 SOGoVersion]]; 242 [calendar addChildren: [timeZones allValues]]; 243 [calendar addChildren: components]; 244 245 return calendar; 246} 247 248- (id) davEntityTag 249{ 250 return [[self _folder] davCollectionTag]; 251} 252 253- (NSString *) contentAsString 254{ 255 [self subclassResponsibility: _cmd]; 256 257 return nil; 258} 259 260- (NSString *) davContentType 261{ 262 [self subclassResponsibility: _cmd]; 263 264 return nil; 265} 266 267- (NSString *) displayName 268{ 269 return [[self _folder] displayName]; 270} 271 272- (NSString *) davDisplayName 273{ 274 return [self displayName]; 275} 276 277@end 278