1 /* SOGoContactLDAPFolder.m - this file is part of SOGo
3 * Copyright (C) 2006 Inverse groupe conseil
5 * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
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)
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.
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.
23 #import <Foundation/NSArray.h>
24 #import <Foundation/NSDictionary.h>
25 #import <Foundation/NSString.h>
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>
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>
46 @implementation SOGoContactLDAPFolder
48 - (void) appendObject: (NSDictionary *) object
49 withBaseURL: (NSString *) baseURL
50 toREPORTResponse: (WOResponse *) r
52 SOGoContactLDIFEntry *component;
54 NSString *name, *etagLine, *contactString;
56 name = [object objectForKey: @"c_name"];
57 componentClass = [SOGoContactLDIFEntry class];
59 component = [componentClass contactEntryWithName: name
60 withLDIFEntry: object inContainer: self];
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"];
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"];
85 + (id) folderWithName: (NSString *) aName
86 andDisplayName: (NSString *) aDisplayName
87 inContainer: (id) aContainer
91 folder = [[self alloc] initWithName: aName
92 andDisplayName: aDisplayName
93 inContainer: aContainer];
101 if ((self = [super init]))
106 ignoreSoObjectHunger = NO;
112 - (id) initWithName: (NSString *) newName
113 andDisplayName: (NSString *) newDisplayName
114 inContainer: (id) newContainer
116 if ((self = [self initWithName: newName
117 inContainer: newContainer]))
119 ASSIGN (displayName, newDisplayName);
127 [displayName release];
129 [ldapSource release];
133 - (void) setLDAPSource: (LDAPSource *) newLDAPSource
135 ASSIGN (ldapSource, newLDAPSource);
138 - (NSString *) displayName
143 - (NSArray *) davNamespaces
145 return [NSArray arrayWithObject: @"urn:ietf:params:xml:ns:carddav"];
148 - (id) lookupName: (NSString *) objectName
149 inContext: (WOContext *) lookupContext
150 acquire: (BOOL) acquire
153 NSDictionary *ldifEntry;
155 //NSLog (@"looking up name '%@'...", objectName);
157 /* first check attributes directly bound to the application */
158 ignoreSoObjectHunger = YES;
159 obj = [super lookupName: objectName inContext: lookupContext acquire: NO];
160 ignoreSoObjectHunger = NO;
164 ldifEntry = [ldapSource lookupContactEntry: objectName];
167 ? [SOGoContactLDIFEntry contactEntryWithName: objectName
168 withLDIFEntry: ldifEntry
170 : [NSException exceptionWithHTTPStatus: 404]);
173 obj = [SOGoContactLDIFEntry contactEntryWithName: objectName
174 withLDIFEntry: ldifEntry
178 NSArray *davNamespaces;
179 NSDictionary *davInvocation;
180 NSString *objcMethod;
182 davNamespaces = [self davNamespaces];
183 if ([davNamespaces count] > 0)
185 davInvocation = [objectName asDavInvocation];
188 containsObject: [davInvocation objectForKey: @"ns"]])
190 objcMethod = [[davInvocation objectForKey: @"method"]
192 obj = [[SoSelectorInvocation alloc]
193 initWithSelectorNamed:
194 [NSString stringWithFormat: @"%@:", objcMethod]
195 addContextParameter: YES];
206 - (NSArray *) toOneRelationshipKeys
210 if (ignoreSoObjectHunger)
213 keys = [ldapSource allEntryIDs];
218 - (NSArray *) _flattenedRecords: (NSArray *) records
220 NSMutableArray *newRecords;
221 NSEnumerator *oldRecords;
222 NSDictionary *oldRecord;
223 NSMutableDictionary *newRecord;
226 newRecords = [[NSMutableArray alloc] initWithCapacity: [records count]];
227 [newRecords autorelease];
229 oldRecords = [records objectEnumerator];
230 oldRecord = [oldRecords nextObject];
233 newRecord = [NSMutableDictionary new];
234 [newRecord autorelease];
236 [newRecord setObject: [oldRecord objectForKey: @"c_uid"]
238 [newRecord setObject: [oldRecord objectForKey: @"c_name"]
241 data = [oldRecord objectForKey: @"displayName"];
243 data = [oldRecord objectForKey: @"c_cn"];
246 [newRecord setObject: data forKey: @"displayName"];
248 data = [oldRecord objectForKey: @"mail"];
251 [newRecord setObject: data forKey: @"mail"];
253 data = [oldRecord objectForKey: @"nsAIMid"];
255 data = [oldRecord objectForKey: @"nscpaimscreenname"];
258 [newRecord setObject: data forKey: @"screenName"];
260 data = [oldRecord objectForKey: @"o"];
263 [newRecord setObject: data forKey: @"org"];
265 data = [oldRecord objectForKey: @"telephoneNumber"];
267 data = [oldRecord objectForKey: @"cellphone"];
269 data = [oldRecord objectForKey: @"homePhone"];
272 [newRecord setObject: data forKey: @"phone"];
274 [newRecords addObject: newRecord];
275 oldRecord = [oldRecords nextObject];
281 - (NSArray *) lookupContactsWithFilter: (NSString *) filter
282 sortBy: (NSString *) sortKey
283 ordering: (NSComparisonResult) sortOrdering
285 NSArray *records, *result;
286 EOSortOrdering *ordering;
290 if (filter && [filter length] > 0)
292 records = [self _flattenedRecords:
293 [ldapSource fetchContactsMatching: filter]];
295 = [EOSortOrdering sortOrderingWithKey: sortKey
296 selector: ((sortOrdering == NSOrderedDescending)
297 ? EOCompareCaseInsensitiveDescending
298 : EOCompareCaseInsensitiveAscending)];
300 = [records sortedArrayUsingKeyOrderArray:
301 [NSArray arrayWithObject: ordering]];
307 - (NSArray *) davResourceType
309 NSArray *rType, *groupDavCollection;
311 groupDavCollection = [NSArray arrayWithObjects: @"vcard-collection",
312 XMLNS_GROUPDAV, nil];
313 rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil];
318 - (NSString *) davContentType
320 return @"httpd/unix-directory";
323 - (BOOL) davIsCollection
328 - (NSString *) davDisplayName
339 - (NSComparisonResult) compare: (id) otherFolder
341 NSComparisonResult comparison;
343 if ([NSStringFromClass([otherFolder class])
344 isEqualToString: @"SOGoContactGCSFolder"])
345 comparison = NSOrderedDescending;
348 = [[self displayName]
349 localizedCaseInsensitiveCompare: [otherFolder displayName]];
355 - (NSString *) ownerInContext: (WOContext *) noContext
360 /* TODO: this might change one day when we support LDAP acls */
361 - (NSArray *) aclsForUser: (NSString *) uid