]> err.no Git - scalable-opengroupware.org/blob - SoObjects/Contacts/SOGoContactGCSFolder.m
074048b8a2f5f38a2e96d319ec6a770fca5d0939
[scalable-opengroupware.org] / SoObjects / Contacts / SOGoContactGCSFolder.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 <Foundation/NSArray.h>
23 #import <Foundation/NSString.h>
24
25 #import <NGObjWeb/NSException+HTTP.h>
26 #import <NGObjWeb/SoObject+SoDAV.h>
27 #import <NGObjWeb/WOContext.h>
28 #import <NGObjWeb/WORequest.h>
29 #import <NGObjWeb/WOResponse.h>
30 #import <NGExtensions/NSObject+Logs.h>
31 #import <NGExtensions/NSString+misc.h>
32 #import <EOControl/EOQualifier.h>
33 #import <EOControl/EOSortOrdering.h>
34 #import <GDLContentStore/GCSFolder.h>
35
36 #import <SoObjects/SOGo/NSDictionary+Utilities.h>
37 #import "SOGoContactGCSEntry.h"
38 #import "SOGoContactGCSFolder.h"
39
40 #define folderListingFields [NSArray arrayWithObjects: @"c_name", @"c_cn", \
41                                      @"c_givenname", @"c_sn", @"c_screenname", \
42                                      @"c_o", @"c_mail", @"c_telephonenumber", \
43                                      nil]
44
45 @implementation SOGoContactGCSFolder
46
47 /* name lookup */
48
49 - (id <SOGoContactObject>) lookupContactWithId: (NSString *) recordId
50 {
51   SOGoContactGCSEntry *contact;
52
53   if ([recordId length] > 0)
54     contact = [SOGoContactGCSEntry objectWithName: recordId
55                                    inContainer: self];
56   else
57     contact = nil;
58
59   return contact;
60 }
61
62 - (id) lookupName: (NSString *) _key
63         inContext: (WOContext *) _ctx
64           acquire: (BOOL) _flag
65 {
66   id obj;
67   BOOL isPut;
68
69   isPut = NO;
70   obj = [super lookupName:_key inContext:_ctx acquire:NO];
71   
72   if (!obj)
73     {
74       if ([[[_ctx request] method] isEqualToString: @"PUT"])
75         {
76           if ([_key isEqualToString: @"PUT"])
77             isPut = YES;
78           else
79             obj = [SOGoContactGCSEntry objectWithName: _key
80                                        inContainer: self];
81         }
82       else
83         obj = [self lookupContactWithId: _key];
84     }
85 //   if (!(obj || isPut))
86 //     obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */];
87
88 // #if 0
89 //     if ([[self ocsFolder] versionOfContentWithName:_key])
90 // #endif
91 //       return [self contactWithName:_key inContext:_ctx];
92 //   }
93
94   /* return 404 to stop acquisition */
95   return obj;
96 }
97
98 /* fetching */
99 - (EOQualifier *) _qualifierForFilter: (NSString *) filter
100 {
101   NSString *qs;
102   EOQualifier *qualifier;
103
104   if (filter && [filter length] > 0)
105     {
106       qs = [NSString stringWithFormat:
107                        @"(c_sn isCaseInsensitiveLike: '%@%%') OR "
108                      @"(c_givenname isCaseInsensitiveLike: '%@%%') OR "
109                      @"(c_mail isCaseInsensitiveLike: '%%%@%%') OR "
110                      @"(c_telephonenumber isCaseInsensitiveLike: '%%%@%%')",
111                      filter, filter, filter, filter];
112       qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
113     }
114   else
115     qualifier = nil;
116
117   return qualifier;
118 }
119
120 - (NSArray *) _flattenedRecords: (NSArray *) records
121 {
122   NSMutableArray *newRecords;
123   NSEnumerator *oldRecords;
124   NSDictionary *oldRecord;
125   NSMutableDictionary *newRecord;
126   NSString *data;
127   
128   newRecords = [NSMutableArray arrayWithCapacity: [records count]];
129
130   oldRecords = [records objectEnumerator];
131   oldRecord = [oldRecords nextObject];
132   while (oldRecord)
133     {
134       newRecord = [NSMutableDictionary new];
135       [newRecord autorelease];
136
137       [newRecord setObject: [oldRecord objectForKey: @"c_name"]
138                  forKey: @"c_uid"];
139       [newRecord setObject: [oldRecord objectForKey: @"c_name"]
140                  forKey: @"c_name"];
141
142       data = [oldRecord objectForKey: @"c_cn"];
143       if (![data length])
144         data = [oldRecord keysWithFormat: @"%{c_givenname} %{c_sn}"];
145       [newRecord setObject: data
146                  forKey: @"displayName"];
147
148       data = [oldRecord objectForKey: @"c_mail"];
149       if (!data)
150         data = @"";
151       [newRecord setObject: data forKey: @"mail"];
152
153       data = [oldRecord objectForKey: @"c_screenname"];
154       if (!data)
155         data = @"";
156       [newRecord setObject: data forKey: @"screenName"];
157
158       data = [oldRecord objectForKey: @"c_o"];
159       if (!data)
160         data = @"";
161       [newRecord setObject: data forKey: @"org"];
162
163       data = [oldRecord objectForKey: @"c_telephonenumber"];
164       if (![data length])
165         data = @"";
166       [newRecord setObject: data forKey: @"phone"];
167
168       [newRecords addObject: newRecord];
169       oldRecord = [oldRecords nextObject];
170     }
171
172   return newRecords;
173 }
174
175 - (NSArray *) lookupContactsWithFilter: (NSString *) filter
176                                 sortBy: (NSString *) sortKey
177                               ordering: (NSComparisonResult) sortOrdering
178 {
179   NSArray *fields, *dbRecords, *records;
180   EOQualifier *qualifier;
181   EOSortOrdering *ordering;
182
183   fields = folderListingFields;
184   qualifier = [self _qualifierForFilter: filter];
185   dbRecords = [[self ocsFolder] fetchFields: fields
186                                 matchingQualifier: qualifier];
187
188   if ([dbRecords count] > 0)
189     {
190       records = [self _flattenedRecords: dbRecords];
191       ordering
192         = [EOSortOrdering sortOrderingWithKey: sortKey
193                           selector: ((sortOrdering == NSOrderedDescending)
194                                      ? EOCompareCaseInsensitiveDescending
195                                      : EOCompareCaseInsensitiveAscending)];
196       records
197         = [records sortedArrayUsingKeyOrderArray:
198                      [NSArray arrayWithObject: ordering]];
199     }
200   else
201     records = nil;
202   //  else
203   //[self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
204
205   [self debugWithFormat:@"fetched %i records.", [records count]];
206   return records;
207 }
208
209 #warning this should be unified within SOGoFolder
210 - (void) appendObject: (NSDictionary *) object
211           withBaseURL: (NSString *) baseURL
212      toREPORTResponse: (WOResponse *) r
213 {
214   SOGoContactGCSEntry *component;
215   NSString *name, *etagLine, *contactString;
216
217   name = [object objectForKey: @"c_name"];
218   component = [self lookupName: name inContext: context acquire: NO];
219
220   [r appendContentString: @"  <D:response>\r\n"];
221   [r appendContentString: @"    <D:href>"];
222   [r appendContentString: baseURL];
223   if (![baseURL hasSuffix: @"/"])
224     [r appendContentString: @"/"];
225   [r appendContentString: name];
226   [r appendContentString: @"</D:href>\r\n"];
227
228   [r appendContentString: @"    <D:propstat>\r\n"];
229   [r appendContentString: @"      <D:prop>\r\n"];
230   etagLine = [NSString stringWithFormat: @"        <D:getetag>%@</D:getetag>\r\n",
231                        [component davEntityTag]];
232   [r appendContentString: etagLine];
233   [r appendContentString: @"      </D:prop>\r\n"];
234   [r appendContentString: @"      <D:status>HTTP/1.1 200 OK</D:status>\r\n"];
235   [r appendContentString: @"    </D:propstat>\r\n"];
236   [r appendContentString: @"    <C:addressbook-data>"];
237   contactString = [[component contentAsString] stringByEscapingXMLString];
238   [r appendContentString: contactString];
239   [r appendContentString: @"</C:addressbook-data>\r\n"];
240   [r appendContentString: @"  </D:response>\r\n"];
241 }
242
243 - (NSArray *) davComplianceClassesInContext: (id)_ctx
244 {
245   NSMutableArray *classes;
246   NSArray *primaryClasses;
247
248   classes = [NSMutableArray new];
249   [classes autorelease];
250
251   primaryClasses = [super davComplianceClassesInContext: _ctx];
252   if (primaryClasses)
253     [classes addObjectsFromArray: primaryClasses];
254   [classes addObject: @"access-control"];
255   [classes addObject: @"addressbook-access"];
256
257   return classes;
258 }
259
260 - (NSArray *) davNamespaces
261 {
262   return [NSArray arrayWithObject: @"urn:ietf:params:xml:ns:carddav"];
263 }
264
265 - (NSString *) groupDavResourceType
266 {
267   return @"vcard-collection";
268 }
269
270 /* sorting */
271 - (NSComparisonResult) compare: (id) otherFolder
272 {
273   NSComparisonResult comparison;
274
275   if ([NSStringFromClass([otherFolder class])
276                         isEqualToString: @"SOGoContactLDAPFolder"])
277     comparison = NSOrderedAscending;
278   else
279     comparison = [super compare: otherFolder];
280
281   return comparison;
282 }
283
284 /* folder type */
285
286 - (NSString *) folderType
287 {
288   return @"Contact";
289 }
290
291 - (NSString *) outlookFolderClass
292 {
293   return @"IPF.Contact";
294 }
295
296 @end /* SOGoContactGCSFolder */