]> err.no Git - scalable-opengroupware.org/blob - SoObjects/Appointments/SOGoGroupAppointmentFolder.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1091 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / SoObjects / Appointments / SOGoGroupAppointmentFolder.m
1 /*
2   Copyright (C) 2004-2005 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #import <NGCards/iCalEntityObject.h>
23 #import <SOGo/SOGoGroupFolder.h>
24
25 #include "SOGoGroupAppointmentFolder.h"
26 #include "common.h"
27
28 @implementation SOGoGroupAppointmentFolder
29
30 + (int)version {
31   return [super version] + 0 /* v1 */;
32 }
33 + (void)initialize {
34   NSAssert2([super version] == 1,
35             @"invalid superclass (%@) version %i !",
36             NSStringFromClass([self superclass]), [super version]);
37 }
38
39 - (void)dealloc {
40   [self->uidToFolder release];
41   [super dealloc];
42 }
43
44 /* looking up shared objects */
45
46 - (SOGoGroupsFolder *)lookupGroupsFolder {
47   return [[self container] lookupGroupsFolder];
48 }
49
50 /* selection */
51
52 - (NSArray *)calendarUIDs {
53   return [[self container] valueForKey:@"uids"];
54 }
55
56 /* folders */
57
58 - (void)resetFolderCaches {
59   [self->uidToFolder release]; self->uidToFolder = nil;
60 }
61
62 - (SOGoAppointmentFolder *)folderForUID:(NSString *)_uid {
63   if (self->uidToFolder == nil) {
64     // TODO: can we trigger a fetch?
65     [self errorWithFormat:
66             @"called -folderForUID method before fetchCoreInfos .."];
67     return nil;
68   }
69   
70   return [self->uidToFolder objectForKey:_uid];
71 }
72
73 /* merging */
74
75 - (BOOL)doesRecord:(NSDictionary *)_rec conflictWith:(NSDictionary *)_other {
76   if (_rec == _other) 
77     return NO;
78   if ([_rec isEqual:_other])
79     return NO;
80   
81   return YES;
82 }
83
84 - (NSDictionary *)_registerConflictingRecord:(NSDictionary *)_other
85   inRecord:(NSDictionary *)_record
86 {
87   NSMutableArray *conflicts;
88   
89   if (_record == nil) return _other;
90   if (_other  == nil) return _record;
91   
92   if ((conflicts = [_record objectForKey:@"conflicts"]) == nil) {
93     NSMutableDictionary *md;
94     
95     md = [[_record mutableCopy] autorelease];
96     conflicts = [NSMutableArray arrayWithCapacity:4];
97     [md setObject:conflicts forKey:@"conflicts"];
98     _record = md;
99   }
100   [conflicts addObject:_other];
101   return _record;
102 }
103
104 /* functionality */
105
106 - (SOGoAppointmentFolder *)calendarFolderForMemberFolder:(id)_folder {
107   SOGoAppointmentFolder *aptFolder;
108   
109   if (![_folder isNotNull])
110     return nil;
111   
112   aptFolder = [_folder lookupName:@"Calendar" inContext:nil acquire:NO];
113   if (![aptFolder isNotNull])
114     return nil;
115   
116   if (![aptFolder respondsToSelector:@selector(fetchCoreInfosFrom:to:component:)]) {
117     [self errorWithFormat:@"folder does not implemented required API: %@",
118             _folder];
119     return nil;
120   }
121   return aptFolder;
122 }
123
124 /* overridden */
125 - (NSArray *) fetchFields: (NSArray *) _fields
126                      from: (NSCalendarDate *) _startDate
127                        to: (NSCalendarDate *) _endDate
128                 component: (id) _component
129 {
130   NSArray             *folders;
131   NSMutableArray      *result;
132   NSMutableDictionary *uidToRecord;
133   unsigned            i, count;
134   SoSecurityManager *securityManager;
135
136   securityManager = [SoSecurityManager sharedSecurityManager];
137
138   folders = [[self container] memberFolders];
139   [self resetFolderCaches];
140   
141   if ((count = [folders count]) == 0)
142     return [NSArray array];
143   
144   if (self->uidToFolder == nil)
145     self->uidToFolder = [[NSMutableDictionary alloc] initWithCapacity:7*count];
146   else
147     [self->uidToFolder removeAllObjects];
148   
149   uidToRecord = [NSMutableDictionary dictionaryWithCapacity:(7 * count)];
150   result      = [NSMutableArray arrayWithCapacity:(7 * count)];
151   for (i = 0; i < count; i++) {
152     SOGoAppointmentFolder *aptFolder;
153     id                    results;
154     NSDictionary          *record;
155
156     aptFolder = [self calendarFolderForMemberFolder:
157                         [folders objectAtIndex:i]];
158     if (![aptFolder isNotNull]) {
159       [self debugWithFormat:@"did not find a Calendar folder in folder: %@",
160               [folders objectAtIndex:i]];
161       continue;
162     }
163
164     if ([securityManager validatePermission: SoPerm_AccessContentsInformation
165                          onObject: aptFolder
166                          inContext: context]) {
167       [self debugWithFormat:@"no permission to read the content of calendar: %@",
168             [folders objectAtIndex:i]];
169       continue;
170     }
171
172     results = [aptFolder fetchFields: _fields
173                          from: _startDate
174                          to: _endDate
175                          component: _component];
176     if (![results isNotNull]) continue;
177     
178     results = [results objectEnumerator];
179     while ((record = [results nextObject])) {
180       NSString     *uid;
181       NSDictionary *existingRecord;
182       
183       uid = [record objectForKey:@"uid"];
184       if (![uid isNotNull]) {
185         [self warnWithFormat:@"record without uid: %@", result];
186         [result addObject:record];
187         continue;
188       }
189       
190       if ((existingRecord = [uidToRecord objectForKey:uid]) == nil) {
191         /* record not yet in result set */
192         [uidToRecord setObject:record forKey:uid];
193         [result addObject:record];
194         
195         [self->uidToFolder setObject:aptFolder forKey:uid];
196       }
197       else if ([self doesRecord:existingRecord conflictWith:record]) {
198         /* record already registered and it conflicts (diff values) */
199         NSDictionary *newRecord;
200         int idx;
201         
202         newRecord = [self _registerConflictingRecord:record 
203                           inRecord:existingRecord];
204         [uidToRecord setObject:newRecord forKey:uid];
205         
206         if ((idx = [result indexOfObject:existingRecord]) != NSNotFound)
207           [result replaceObjectAtIndex:idx withObject:newRecord];
208       }
209       else {
210         /* record already registered, but values in sync, nothing to do */
211       }
212     }
213   }
214   return result;
215 }
216
217
218 /* URL generation */
219
220 - (NSString *)baseURLForAptWithUID:(NSString *)_uid inContext:(id)_ctx {
221   /* Note: fetchCore must have been called before this works */
222   SOGoAppointmentFolder *folder;
223   
224   if ([_uid length] == 0) {
225     [self errorWithFormat:@"got invalid UID."];
226     return nil;
227   }
228   
229   if ((folder = [self folderForUID:_uid]) == nil) {
230     [self errorWithFormat:@"did not find a folder containing UID: '%@'",
231             _uid];
232     return nil;
233   }
234   if (![folder respondsToSelector:_cmd]) {
235     [self errorWithFormat:@"found folder cannot construct UID URLs: %@",
236             folder];
237     return nil;
238   }
239   
240   [self debugWithFormat:@"found ID %@ in folder: %@", _uid, folder];
241   
242   return [folder baseURLForAptWithUID:_uid inContext:_ctx];
243 }
244
245 @end /* SOGoGroupAppointmentFolder */