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