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