]> err.no Git - scalable-opengroupware.org/blob - SoObjects/Contacts/SOGoContactLDAPFolder.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1245 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / SoObjects / Contacts / SOGoContactLDAPFolder.m
1 /* SOGoContactLDAPFolder.m - this file is part of SOGo
2  *
3  * Copyright (C) 2006 Inverse groupe conseil
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/NSDictionary.h>
25 #import <Foundation/NSString.h>
26
27 #import <NGObjWeb/NSException+HTTP.h>
28 #import <NGObjWeb/SoObject.h>
29 #import <NGObjWeb/WOApplication.h>
30 #import <NGObjWeb/WOContext.h>
31 #import <NGObjWeb/WOContext+SoObjects.h>
32 #import <NGObjWeb/SoUser.h>
33 #import <EOControl/EOSortOrdering.h>
34 #import <SaxObjC/XMLNamespaces.h>
35
36 #import <SoObjects/SOGo/LDAPSource.h>
37 #import <SoObjects/SOGo/NSString+Utilities.h>
38 #import "SOGoContactLDIFEntry.h"
39 #import "SOGoContactLDAPFolder.h"
40 #import <NGExtensions/NSString+misc.h>
41 #import <NGObjWeb/WORequest.h>
42 #import <NGObjWeb/SoSelectorInvocation.h>
43
44 @class WOContext;
45
46 @implementation SOGoContactLDAPFolder
47
48 - (void) appendObject: (NSDictionary *) object
49           withBaseURL: (NSString *) baseURL
50      toREPORTResponse: (WOResponse *) r
51 {
52   SOGoContactLDIFEntry *component;
53   Class componentClass;
54   NSString *name, *etagLine, *contactString;
55
56   name = [object objectForKey: @"c_name"];
57   componentClass = [SOGoContactLDIFEntry class];
58
59   component = [componentClass contactEntryWithName: name
60                               withLDIFEntry: object  inContainer: self];
61
62   [r appendContentString: @"  <D:response>\r\n"];
63   [r appendContentString: @"    <D:href>"];
64   [r appendContentString: baseURL];
65   if (![baseURL hasSuffix: @"/"])
66     [r appendContentString: @"/"];
67   [r appendContentString: name];
68   [r appendContentString: @"</D:href>\r\n"];
69
70   [r appendContentString: @"    <D:propstat>\r\n"];
71   [r appendContentString: @"      <D:prop>\r\n"];
72   etagLine = [NSString stringWithFormat: @"        <D:getetag>%@</D:getetag>\r\n",
73                        [component davEntityTag]];
74   [r appendContentString: etagLine];
75   [r appendContentString: @"      </D:prop>\r\n"];
76   [r appendContentString: @"      <D:status>HTTP/1.1 200 OK</D:status>\r\n"];
77   [r appendContentString: @"    </D:propstat>\r\n"];
78   [r appendContentString: @"    <C:addressbook-data>"];
79   contactString = [[component contentAsString] stringByEscapingXMLString];
80   [r appendContentString: contactString];
81   [r appendContentString: @"</C:addressbook-data>\r\n"];
82   [r appendContentString: @"  </D:response>\r\n"];
83 }
84
85 + (id) folderWithName: (NSString *) aName
86        andDisplayName: (NSString *) aDisplayName
87           inContainer: (id) aContainer
88 {
89   id folder;
90
91   folder = [[self alloc] initWithName: aName
92                          andDisplayName: aDisplayName
93                          inContainer: aContainer];
94   [folder autorelease];
95
96   return folder;
97 }
98
99 - (id) init
100 {
101   if ((self = [super init]))
102     {
103       displayName = nil;
104       entries = nil;
105       ldapSource = nil;
106       ignoreSoObjectHunger = NO;
107     }
108
109   return self;
110 }
111
112 - (id) initWithName: (NSString *) newName
113      andDisplayName: (NSString *) newDisplayName
114         inContainer: (id) newContainer
115 {
116   if ((self = [self initWithName: newName
117                     inContainer: newContainer]))
118     {
119       ASSIGN (displayName, newDisplayName);
120     }
121
122   return self;
123 }
124
125 - (void) dealloc
126 {
127   [displayName release];
128   [entries release];
129   [ldapSource release];
130   [super dealloc];
131 }
132
133 - (void) setLDAPSource: (LDAPSource *) newLDAPSource
134 {
135   ASSIGN (ldapSource, newLDAPSource);
136 }
137
138 - (NSString *) displayName
139 {
140   return displayName;
141 }
142
143 - (NSArray *) davNamespaces
144 {
145   return [NSArray arrayWithObject: @"urn:ietf:params:xml:ns:carddav"];
146 }
147
148 - (id) lookupName: (NSString *) objectName
149         inContext: (WOContext *) lookupContext
150           acquire: (BOOL) acquire
151 {
152   id obj;
153   NSDictionary *ldifEntry;
154
155   //NSLog (@"looking up name '%@'...", objectName);
156
157   /* first check attributes directly bound to the application */
158   ignoreSoObjectHunger = YES;
159   obj = [super lookupName: objectName inContext: lookupContext acquire: NO];
160   ignoreSoObjectHunger = NO;
161
162   if (!obj)
163     {
164       ldifEntry = [ldapSource lookupContactEntry: objectName];
165 #if 0
166       obj = ((ldifEntry)
167              ? [SOGoContactLDIFEntry contactEntryWithName: objectName
168                                      withLDIFEntry: ldifEntry
169                                      inContainer: self]
170              : [NSException exceptionWithHTTPStatus: 404]);
171 #else
172       if (ldifEntry)
173         obj = [SOGoContactLDIFEntry contactEntryWithName: objectName
174                                     withLDIFEntry: ldifEntry
175                                     inContainer: self];
176       else
177         {
178           NSArray *davNamespaces;
179           NSDictionary *davInvocation;
180           NSString *objcMethod;
181           
182           davNamespaces = [self davNamespaces];
183           if ([davNamespaces count] > 0)
184             {
185               davInvocation = [objectName asDavInvocation];
186               if (davInvocation
187                   && [davNamespaces
188                        containsObject: [davInvocation objectForKey: @"ns"]])
189                 {
190                   objcMethod = [[davInvocation objectForKey: @"method"]
191                              davMethodToObjC];
192                   obj = [[SoSelectorInvocation alloc]
193                           initWithSelectorNamed:
194                             [NSString stringWithFormat: @"%@:", objcMethod]
195                           addContextParameter: YES];
196                   [obj autorelease];
197                 }
198             }
199         }
200 #endif
201     }
202
203   return obj;
204 }
205
206 - (NSArray *) toOneRelationshipKeys
207 {
208   NSArray *keys;
209
210   if (ignoreSoObjectHunger)
211     keys = nil;
212   else
213     keys = [ldapSource allEntryIDs];
214
215   return keys;
216 }
217
218 - (NSArray *) _flattenedRecords: (NSArray *) records
219 {
220   NSMutableArray *newRecords;
221   NSEnumerator *oldRecords;
222   NSDictionary *oldRecord;
223   NSMutableDictionary *newRecord;
224   NSString *data;
225   
226   newRecords = [[NSMutableArray alloc] initWithCapacity: [records count]];
227   [newRecords autorelease];
228
229   oldRecords = [records objectEnumerator];
230   oldRecord = [oldRecords nextObject];
231   while (oldRecord)
232     {
233       newRecord = [NSMutableDictionary new];
234       [newRecord autorelease];
235
236       [newRecord setObject: [oldRecord objectForKey: @"c_uid"]
237                  forKey: @"c_uid"];
238       [newRecord setObject: [oldRecord objectForKey: @"c_name"]
239                  forKey: @"c_name"];
240
241       data = [oldRecord objectForKey: @"displayName"];
242       if (!data)
243         data = [oldRecord objectForKey: @"c_cn"];
244       if (!data)
245         data = @"";
246       [newRecord setObject: data forKey: @"displayName"];
247
248       data = [oldRecord objectForKey: @"mail"];
249       if (!data)
250         data = @"";
251       [newRecord setObject: data forKey: @"mail"];
252
253       data = [oldRecord objectForKey: @"nsAIMid"];
254       if (![data length])
255         data = [oldRecord objectForKey: @"nscpaimscreenname"];
256       if (![data length])
257         data = @"";
258       [newRecord setObject: data forKey: @"screenName"];
259
260       data = [oldRecord objectForKey: @"o"];
261       if (!data)
262         data = @"";
263       [newRecord setObject: data forKey: @"org"];
264
265       data = [oldRecord objectForKey: @"telephoneNumber"];
266       if (![data length])
267         data = [oldRecord objectForKey: @"cellphone"];
268       if (![data length])
269         data = [oldRecord objectForKey: @"homePhone"];
270       if (![data length])
271         data = @"";
272       [newRecord setObject: data forKey: @"phone"];
273
274       [newRecords addObject: newRecord];
275       oldRecord = [oldRecords nextObject];
276     }
277
278   return newRecords;
279 }
280
281 - (NSArray *) lookupContactsWithFilter: (NSString *) filter
282                                 sortBy: (NSString *) sortKey
283                               ordering: (NSComparisonResult) sortOrdering
284 {
285   NSArray *records, *result;
286   EOSortOrdering *ordering;
287
288   result = nil;
289
290   if (filter && [filter length] > 0)
291     {
292       records = [self _flattenedRecords:
293                         [ldapSource fetchContactsMatching: filter]];
294       ordering
295         = [EOSortOrdering sortOrderingWithKey: sortKey
296                           selector: ((sortOrdering == NSOrderedDescending)
297                                      ? EOCompareCaseInsensitiveDescending
298                                      : EOCompareCaseInsensitiveAscending)];
299       result
300         = [records sortedArrayUsingKeyOrderArray:
301                      [NSArray arrayWithObject: ordering]];
302     }
303
304   return result;
305 }
306
307 - (NSArray *) davResourceType
308 {
309   NSArray *rType, *groupDavCollection;
310
311   groupDavCollection = [NSArray arrayWithObjects: @"vcard-collection",
312                                 XMLNS_GROUPDAV, nil];
313   rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil];
314
315   return rType;
316 }
317
318 - (NSString *) davContentType
319 {
320   return @"httpd/unix-directory";
321 }
322
323 - (BOOL) davIsCollection
324 {
325   return YES;
326 }
327
328 - (NSString *) davDisplayName
329 {
330   return displayName;
331 }
332
333 - (BOOL) isFolderish
334 {
335   return YES;
336 }
337
338 /* sorting */
339 - (NSComparisonResult) compare: (id) otherFolder
340 {
341   NSComparisonResult comparison;
342
343   if ([NSStringFromClass([otherFolder class])
344                         isEqualToString: @"SOGoContactGCSFolder"])
345     comparison = NSOrderedDescending;
346   else
347     comparison
348       = [[self displayName]
349           localizedCaseInsensitiveCompare: [otherFolder displayName]];
350
351   return comparison;
352 }
353
354 /* acls */
355 - (NSString *) ownerInContext: (WOContext *) noContext
356 {
357   return @"nobody";
358 }
359
360 /* TODO: this might change one day when we support LDAP acls */
361 - (NSArray *) aclsForUser: (NSString *) uid
362 {
363   return nil;
364 }
365
366 @end