02111-1307, USA.
*/
+#import <Foundation/NSArray.h>
+#import <Foundation/NSString.h>
+
+#import <NGObjWeb/NSException+HTTP.h>
+#import <NGObjWeb/SoObject+SoDAV.h>
+#import <NGObjWeb/WOContext.h>
+#import <NGObjWeb/WORequest.h>
+#import <NGExtensions/NSObject+Logs.h>
+#import <NGExtensions/NSString+misc.h>
+#import <EOControl/EOQualifier.h>
+#import <EOControl/EOSortOrdering.h>
#import <GDLContentStore/GCSFolder.h>
-#import "common.h"
-
+#import <SoObjects/SOGo/NSDictionary+Utilities.h>
#import "SOGoContactGCSEntry.h"
#import "SOGoContactGCSFolder.h"
-#define folderListingFields [NSArray arrayWithObjects: @"c_name", @"cn", \
- @"givenname", @"screenname", \
- @"o", @"mail", @"telephonenumber", \
+#define folderListingFields [NSArray arrayWithObjects: @"c_name", @"c_cn", \
+ @"c_givenname", @"c_sn", @"c_screenname", \
+ @"c_o", @"c_mail", @"c_telephonenumber", \
nil]
@implementation SOGoContactGCSFolder
-+ (id <SOGoContactFolder>) contactFolderWithName: (NSString *) aName
- andDisplayName: (NSString *) aDisplayName
- inContainer: (SOGoObject *) aContainer
-{
- SOGoContactGCSFolder *folder;
-
- folder = [[self alloc] initWithName: aName
- andDisplayName: aDisplayName
- inContainer: aContainer];
- [folder autorelease];
-
- return folder;
-}
-
-- (void) dealloc
-{
- [displayName release];
- [super dealloc];
-}
-
-- (id <SOGoContactFolder>) initWithName: (NSString *) newName
- andDisplayName: (NSString *) newDisplayName
- inContainer: (SOGoObject *) newContainer
-{
- if ((self = [self initWithName: newName
- inContainer: newContainer]))
- ASSIGN (displayName, newDisplayName);
-
- return self;
-}
-
-- (NSString *) displayName
-{
- return displayName;
-}
-
/* name lookup */
- (id <SOGoContactObject>) lookupContactWithId: (NSString *) recordId
acquire: (BOOL) _flag
{
id obj;
+ BOOL isPut;
- /* first check attributes directly bound to the application */
+ isPut = NO;
obj = [super lookupName:_key inContext:_ctx acquire:NO];
+
if (!obj)
{
if ([[[_ctx request] method] isEqualToString: @"PUT"])
- {
- obj = [[SOGoContactGCSEntry alloc] initWithName: _key
- inContainer: self];
- [obj autorelease];
- }
+ {
+ if ([_key isEqualToString: @"PUT"])
+ isPut = YES;
+ else
+ obj = [SOGoContactGCSEntry objectWithName: _key
+ inContainer: self];
+ }
else
obj = [self lookupContactWithId: _key];
}
- if (!obj)
- obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */];
+// if (!(obj || isPut))
+// obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */];
// #if 0
// if ([[self ocsFolder] versionOfContentWithName:_key])
if (filter && [filter length] > 0)
{
qs = [NSString stringWithFormat:
- @"(sn isCaseInsensitiveLike: '%@%%') OR "
- @"(givenname isCaseInsensitiveLike: '%@%%') OR "
- @"(mail isCaseInsensitiveLike: '%@%%') OR "
- @"(telephonenumber isCaseInsensitiveLike: '%%%@%%')",
+ @"(c_sn isCaseInsensitiveLike: '%@%%') OR "
+ @"(c_givenname isCaseInsensitiveLike: '%@%%') OR "
+ @"(c_mail isCaseInsensitiveLike: '%@%%') OR "
+ @"(c_telephonenumber isCaseInsensitiveLike: '%%%@%%')",
filter, filter, filter, filter];
qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
}
return qualifier;
}
+- (NSArray *) _flattenedRecords: (NSArray *) records
+{
+ NSMutableArray *newRecords;
+ NSEnumerator *oldRecords;
+ NSDictionary *oldRecord;
+ NSMutableDictionary *newRecord;
+ NSString *data;
+
+ newRecords = [NSMutableArray arrayWithCapacity: [records count]];
+
+ oldRecords = [records objectEnumerator];
+ oldRecord = [oldRecords nextObject];
+ while (oldRecord)
+ {
+ newRecord = [NSMutableDictionary new];
+ [newRecord autorelease];
+
+ [newRecord setObject: [oldRecord objectForKey: @"c_name"]
+ forKey: @"c_uid"];
+ [newRecord setObject: [oldRecord objectForKey: @"c_name"]
+ forKey: @"c_name"];
+
+ data = [oldRecord objectForKey: @"c_cn"];
+ if (![data length])
+ data = [oldRecord keysWithFormat: @"%{c_givenname} %{c_sn}"];
+ [newRecord setObject: data
+ forKey: @"displayName"];
+
+ data = [oldRecord objectForKey: @"c_mail"];
+ if (!data)
+ data = @"";
+ [newRecord setObject: data forKey: @"mail"];
+
+ data = [oldRecord objectForKey: @"c_screenname"];
+ if (!data)
+ data = @"";
+ [newRecord setObject: data forKey: @"screenName"];
+
+ data = [oldRecord objectForKey: @"c_o"];
+ if (!data)
+ data = @"";
+ [newRecord setObject: data forKey: @"org"];
+
+ data = [oldRecord objectForKey: @"c_telephonenumber"];
+ if (![data length])
+ data = @"";
+ [newRecord setObject: data forKey: @"phone"];
+
+ [newRecords addObject: newRecord];
+ oldRecord = [oldRecords nextObject];
+ }
+
+ return newRecords;
+}
+
- (NSArray *) lookupContactsWithFilter: (NSString *) filter
sortBy: (NSString *) sortKey
ordering: (NSComparisonResult) sortOrdering
{
- NSArray *fields, *records;
+ NSArray *fields, *dbRecords, *records;
EOQualifier *qualifier;
EOSortOrdering *ordering;
-// NSLog (@"fetching records matching '%@', sorted by '%@' in order %d",
-// filter, sortKey, sortOrdering);
-
fields = folderListingFields;
qualifier = [self _qualifierForFilter: filter];
- records = [[self ocsFolder] fetchFields: fields
- matchingQualifier: qualifier];
- if ([records count] > 1)
+ dbRecords = [[self ocsFolder] fetchFields: fields
+ matchingQualifier: qualifier];
+
+ if ([dbRecords count] > 0)
{
+ records = [self _flattenedRecords: dbRecords];
ordering
= [EOSortOrdering sortOrderingWithKey: sortKey
selector: ((sortOrdering == NSOrderedDescending)
[NSArray arrayWithObject: ordering]];
}
else
- [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
+ records = nil;
+ // else
+ //[self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
- //[self debugWithFormat:@"fetched %i records.", [records count]];
+ [self debugWithFormat:@"fetched %i records.", [records count]];
return records;
}
-- (NSString *) groupDavResourceType
+- (void) appendObject: (NSDictionary *) object
+ withBaseURL: (NSString *) baseURL
+ toREPORTResponse: (WOResponse *) r
{
- return @"vcard-collection";
+ SOGoContactGCSEntry *component;
+ Class componentClass;
+ NSString *name, *etagLine, *contactString;
+
+ name = [object objectForKey: @"c_name"];
+ componentClass = [SOGoContactGCSEntry class];
+
+ component = [componentClass objectWithName: name inContainer: self];
+
+ [r appendContentString: @" <D:response>\r\n"];
+ [r appendContentString: @" <D:href>"];
+ [r appendContentString: baseURL];
+ if (![baseURL hasSuffix: @"/"])
+ [r appendContentString: @"/"];
+ [r appendContentString: name];
+ [r appendContentString: @"</D:href>\r\n"];
+
+ [r appendContentString: @" <D:propstat>\r\n"];
+ [r appendContentString: @" <D:prop>\r\n"];
+ etagLine = [NSString stringWithFormat: @" <D:getetag>%@</D:getetag>\r\n",
+ [component davEntityTag]];
+ [r appendContentString: etagLine];
+ [r appendContentString: @" </D:prop>\r\n"];
+ [r appendContentString: @" <D:status>HTTP/1.1 200 OK</D:status>\r\n"];
+ [r appendContentString: @" </D:propstat>\r\n"];
+ [r appendContentString: @" <C:addressbook-data>"];
+ contactString = [[component contentAsString] stringByEscapingXMLString];
+ [r appendContentString: contactString];
+ [r appendContentString: @"</C:addressbook-data>\r\n"];
+ [r appendContentString: @" </D:response>\r\n"];
+}
+
+- (NSArray *) davComplianceClassesInContext: (id)_ctx
+{
+ NSMutableArray *classes;
+ NSArray *primaryClasses;
+
+ classes = [NSMutableArray new];
+ [classes autorelease];
+
+ primaryClasses = [super davComplianceClassesInContext: _ctx];
+ if (primaryClasses)
+ [classes addObjectsFromArray: primaryClasses];
+ [classes addObject: @"access-control"];
+ [classes addObject: @"addressbook-access"];
+
+ return classes;
}
-- (NSException *) delete
+- (NSArray *) davNamespaces
{
- return (([nameInContainer isEqualToString: @"personal"])
- ? [NSException exceptionWithHTTPStatus: 403
- reason: @"the 'personal' folder cannot be deleted"]
- : [super delete]);
+ return [NSArray arrayWithObject: @"urn:ietf:params:xml:ns:carddav"];
+}
+
+- (NSString *) groupDavResourceType
+{
+ return @"vcard-collection";
}
// /* GET */
// return r;
// }
+/* sorting */
+- (NSComparisonResult) compare: (id) otherFolder
+{
+ NSComparisonResult comparison;
+
+ if ([NSStringFromClass([otherFolder class])
+ isEqualToString: @"SOGoContactLDAPFolder"])
+ comparison = NSOrderedAscending;
+ else
+ comparison = [super compare: otherFolder];
+
+ return comparison;
+}
+
/* folder type */
- (NSString *) folderType