merge of '87eb8bb69f68316e6f95f8206ea9f665209d2b0f'
and 'e78fc689c78de581aaf34ccdcebebddeb142c5b3' Monotone-Parent: 87eb8bb69f68316e6f95f8206ea9f665209d2b0f Monotone-Parent: e78fc689c78de581aaf34ccdcebebddeb142c5b3 Monotone-Revision: 60c12b841698957b704b47490a125477543c7dc3 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-08-12T14:06:56 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
commit
9371987226
29
ChangeLog
29
ChangeLog
|
@ -1,3 +1,32 @@
|
||||||
|
2010-08-12 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
|
* SoObjects/Contacts/SOGoFolder+CardDAV.m:
|
||||||
|
(_appendObject:withBaseURL:toREPORTResponse:): moved method here
|
||||||
|
from SOGOContact{GCS,Source}Folder since its implementation was
|
||||||
|
mostly the same in the two classes and never invoked anywhere
|
||||||
|
else.
|
||||||
|
Modified to return both "address-data" and "addressbook-data"
|
||||||
|
(draft rev < 4) unless we parse the requested props appropriately.
|
||||||
|
|
||||||
|
* SoObjects/Contacts/SOGoContactGCSFolder.m
|
||||||
|
(-davAddressbookMultiget): new method that responds the
|
||||||
|
CardDAV addressbook-multiget report.
|
||||||
|
(-davSQLFieldsTable): new overriden method that adds support for
|
||||||
|
the CardDAV address-data property.
|
||||||
|
|
||||||
|
* SoObjects/Appointments/SOGoAppointmentFolder.m
|
||||||
|
(-davCalendarMultiget:): make use of the new method below.
|
||||||
|
|
||||||
|
* SoObjects/SOGo/SOGoGCSFolder.m
|
||||||
|
(-performMultigetInContext:inNamespace:): collection-type
|
||||||
|
independent form of -[SOGoAppointmentFolder davCalendarMultiget:],
|
||||||
|
moved along with all its private methods.
|
||||||
|
|
||||||
|
* SoObjects/Contacts/SOGoContactFolders.m
|
||||||
|
(-toManyRelationshipKeys): new overriden method to return only the
|
||||||
|
personal addressbook when the request is performed by
|
||||||
|
AddressBook.app.
|
||||||
|
|
||||||
2010-08-11 Francis Lachapelle <flachapelle@inverse.ca>
|
2010-08-11 Francis Lachapelle <flachapelle@inverse.ca>
|
||||||
|
|
||||||
* UI/WebServerResources/MailerUI.js (refreshMessage): if the
|
* UI/WebServerResources/MailerUI.js (refreshMessage): if the
|
||||||
|
|
|
@ -81,6 +81,16 @@
|
||||||
|
|
||||||
#define defaultColor @"#AAAAAA"
|
#define defaultColor @"#AAAAAA"
|
||||||
|
|
||||||
|
@interface SOGoGCSFolder (SOGoPrivate)
|
||||||
|
|
||||||
|
- (void) appendObject: (NSDictionary *) object
|
||||||
|
properties: (NSString **) properties
|
||||||
|
count: (unsigned int) propertiesCount
|
||||||
|
withBaseURL: (NSString *) baseURL
|
||||||
|
toBuffer: (NSMutableString *) r;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation SOGoAppointmentFolder
|
@implementation SOGoAppointmentFolder
|
||||||
|
|
||||||
static NSNumber *sharedYes = nil;
|
static NSNumber *sharedYes = nil;
|
||||||
|
@ -1065,27 +1075,10 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||||
return ma;
|
return ma;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) _appendPropstat: (NSDictionary *) propstat
|
|
||||||
toBuffer: (NSMutableString *) r
|
|
||||||
{
|
|
||||||
NSArray *properties;
|
|
||||||
unsigned int count, max;
|
|
||||||
|
|
||||||
[r appendString: @"<D:propstat><D:prop>"];
|
|
||||||
properties = [propstat objectForKey: @"properties"];
|
|
||||||
max = [properties count];
|
|
||||||
for (count = 0; count < max; count++)
|
|
||||||
[r appendString: [properties objectAtIndex: count]];
|
|
||||||
[r appendString: @"</D:prop><D:status>"];
|
|
||||||
[r appendString: [propstat objectForKey: @"status"]];
|
|
||||||
[r appendString: @"</D:status></D:propstat>"];
|
|
||||||
}
|
|
||||||
|
|
||||||
#warning we should use the EOFetchSpecification for that!!! (see doPROPFIND:)
|
#warning we should use the EOFetchSpecification for that!!! (see doPROPFIND:)
|
||||||
|
|
||||||
#warning components in calendar-data query are ignored
|
#warning components in calendar-data query are ignored
|
||||||
|
|
||||||
#warning the two following methods should be replaced with the new dav rendering mechanism
|
|
||||||
- (NSString *) _nodeTagForProperty: (NSString *) property
|
- (NSString *) _nodeTagForProperty: (NSString *) property
|
||||||
{
|
{
|
||||||
NSString *namespace, *nodeName, *nsRep;
|
NSString *namespace, *nodeName, *nsRep;
|
||||||
|
@ -1103,158 +1096,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||||
return [NSString stringWithFormat: @"%@:%@", nsRep, nodeName];
|
return [NSString stringWithFormat: @"%@:%@", nsRep, nodeName];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) _nodeTag: (NSString *) property
|
|
||||||
{
|
|
||||||
static NSMutableDictionary *tags = nil;
|
|
||||||
NSString *nodeTag;
|
|
||||||
|
|
||||||
if (!tags)
|
|
||||||
tags = [NSMutableDictionary new];
|
|
||||||
nodeTag = [tags objectForKey: property];
|
|
||||||
if (!nodeTag)
|
|
||||||
{
|
|
||||||
nodeTag = [self _nodeTagForProperty: property];
|
|
||||||
[tags setObject: nodeTag forKey: property];
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodeTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString **) _properties: (NSString **) properties
|
|
||||||
count: (unsigned int) propertiesCount
|
|
||||||
ofObject: (NSDictionary *) object
|
|
||||||
{
|
|
||||||
SOGoCalendarComponent *sogoObject;
|
|
||||||
NSString **currentProperty;
|
|
||||||
NSString **values, **currentValue;
|
|
||||||
SEL methodSel;
|
|
||||||
|
|
||||||
// NSLog (@"_properties:ofObject:: %@", [NSDate date]);
|
|
||||||
|
|
||||||
values = NSZoneMalloc (NULL,
|
|
||||||
(propertiesCount + 1) * sizeof (NSString *));
|
|
||||||
*(values + propertiesCount) = nil;
|
|
||||||
|
|
||||||
//c = [self objectClassForComponentName: [object objectForKey: @"c_component"]];
|
|
||||||
|
|
||||||
#warning TODO: determine why this commented invocation takes so long...
|
|
||||||
// sogoObject = [self createChildComponentWithRecord: object];
|
|
||||||
|
|
||||||
sogoObject = [SOGoCalendarComponent objectWithRecord: object
|
|
||||||
inContainer: self];
|
|
||||||
[sogoObject setComponentTag: [object objectForKey: @"c_component"]];
|
|
||||||
|
|
||||||
currentProperty = properties;
|
|
||||||
currentValue = values;
|
|
||||||
while (*currentProperty)
|
|
||||||
{
|
|
||||||
methodSel = SOGoSelectorForPropertyGetter (*currentProperty);
|
|
||||||
if (methodSel && [sogoObject respondsToSelector: methodSel])
|
|
||||||
*currentValue = [[sogoObject performSelector: methodSel]
|
|
||||||
stringByEscapingXMLString];
|
|
||||||
currentProperty++;
|
|
||||||
currentValue++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NSLog (@"/_properties:ofObject:: %@", [NSDate date]);
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *) _propstats: (NSString **) properties
|
|
||||||
count: (unsigned int) propertiesCount
|
|
||||||
ofObject: (NSDictionary *) object
|
|
||||||
{
|
|
||||||
NSMutableArray *propstats, *properties200, *properties404, *propDict;
|
|
||||||
NSString **property, **values, **currentValue;
|
|
||||||
NSString *propertyValue, *nodeTag;
|
|
||||||
|
|
||||||
// NSLog (@"_propstats:ofObject:: %@", [NSDate date]);
|
|
||||||
|
|
||||||
propstats = [NSMutableArray array];
|
|
||||||
|
|
||||||
properties200 = [NSMutableArray array];
|
|
||||||
properties404 = [NSMutableArray array];
|
|
||||||
|
|
||||||
values = [self _properties: properties count: propertiesCount
|
|
||||||
ofObject: object];
|
|
||||||
currentValue = values;
|
|
||||||
|
|
||||||
property = properties;
|
|
||||||
while (*property)
|
|
||||||
{
|
|
||||||
nodeTag = [self _nodeTag: *property];
|
|
||||||
if (*currentValue)
|
|
||||||
{
|
|
||||||
propertyValue = [NSString stringWithFormat: @"<%@>%@</%@>",
|
|
||||||
nodeTag, *currentValue, nodeTag];
|
|
||||||
propDict = properties200;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
propertyValue = [NSString stringWithFormat: @"<%@/>", nodeTag];
|
|
||||||
propDict = properties404;
|
|
||||||
}
|
|
||||||
[propDict addObject: propertyValue];
|
|
||||||
property++;
|
|
||||||
currentValue++;
|
|
||||||
}
|
|
||||||
free (values);
|
|
||||||
|
|
||||||
if ([properties200 count])
|
|
||||||
[propstats addObject: [NSDictionary dictionaryWithObjectsAndKeys:
|
|
||||||
properties200, @"properties",
|
|
||||||
@"HTTP/1.1 200 OK", @"status",
|
|
||||||
nil]];
|
|
||||||
if ([properties404 count])
|
|
||||||
[propstats addObject: [NSDictionary dictionaryWithObjectsAndKeys:
|
|
||||||
properties404, @"properties",
|
|
||||||
@"HTTP/1.1 404 Not Found", @"status",
|
|
||||||
nil]];
|
|
||||||
// NSLog (@"/_propstats:ofObject:: %@", [NSDate date]);
|
|
||||||
|
|
||||||
return propstats;
|
|
||||||
}
|
|
||||||
|
|
||||||
#warning We need to use the new DAV utilities here...
|
|
||||||
#warning this is baddddd because we return a single-valued dictionary containing \
|
|
||||||
a cname which may not event exist... the logic behind appendObject:... should be \
|
|
||||||
rethought, especially since we may start using SQL views
|
|
||||||
|
|
||||||
- (void) appendObject: (NSDictionary *) object
|
|
||||||
properties: (NSString **) properties
|
|
||||||
count: (unsigned int) propertiesCount
|
|
||||||
withBaseURL: (NSString *) baseURL
|
|
||||||
toBuffer: (NSMutableString *) r
|
|
||||||
{
|
|
||||||
NSArray *propstats;
|
|
||||||
unsigned int count, max;
|
|
||||||
|
|
||||||
[r appendFormat: @"<D:response><D:href>"];
|
|
||||||
[r appendString: baseURL];
|
|
||||||
[r appendString: [object objectForKey: @"c_name"]];
|
|
||||||
[r appendString: @"</D:href>"];
|
|
||||||
|
|
||||||
// NSLog (@"(appendPropstats...): %@", [NSDate date]);
|
|
||||||
propstats = [self _propstats: properties count: propertiesCount
|
|
||||||
ofObject: object];
|
|
||||||
max = [propstats count];
|
|
||||||
for (count = 0; count < max; count++)
|
|
||||||
[self _appendPropstat: [propstats objectAtIndex: count]
|
|
||||||
toBuffer: r];
|
|
||||||
// NSLog (@"/(appendPropstats...): %@", [NSDate date]);
|
|
||||||
|
|
||||||
[r appendString: @"</D:response>"];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) appendMissingObjectRef: (NSString *) href
|
|
||||||
toBuffer: (NSMutableString *) r
|
|
||||||
{
|
|
||||||
[r appendString: @"<D:response><D:href>"];
|
|
||||||
[r appendString: href];
|
|
||||||
[r appendString: @"</D:href><D:status>HTTP/1.1 404 Not Found</D:status></D:response>"];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSCalendarDate *) _getMaxStartDate
|
- (NSCalendarDate *) _getMaxStartDate
|
||||||
{
|
{
|
||||||
NSCalendarDate *now, *rc;
|
NSCalendarDate *now, *rc;
|
||||||
|
@ -1688,211 +1529,10 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *) _deduceObjectNamesFromURLs: (NSArray *) urls
|
- (WOResponse *) davCalendarMultiget: (WOContext *) queryContext
|
||||||
{
|
{
|
||||||
unsigned int count, max;
|
return [self performMultigetInContext: queryContext
|
||||||
NSString *url, *componentURLPath, *cName, *baseURLString;
|
inNamespace: @"urn:ietf:params:xml:ns:caldav"];
|
||||||
NSMutableDictionary *cNames;
|
|
||||||
NSURL *componentURL, *baseURL;
|
|
||||||
NSArray *urlComponents;
|
|
||||||
|
|
||||||
max = [urls count];
|
|
||||||
cNames = [NSMutableDictionary dictionaryWithCapacity: max];
|
|
||||||
baseURL = [self davURL];
|
|
||||||
baseURLString = [self davURLAsString];
|
|
||||||
|
|
||||||
for (count = 0; count < max; count++)
|
|
||||||
{
|
|
||||||
url = [NSString stringWithFormat: @"%@/%@",
|
|
||||||
[[urls objectAtIndex: count] stringByDeletingLastPathComponent],
|
|
||||||
[[[urls objectAtIndex: count] lastPathComponent] stringByEscapingURL]];
|
|
||||||
componentURL = [[NSURL URLWithString: url relativeToURL: baseURL]
|
|
||||||
standardizedURL];
|
|
||||||
componentURLPath = [componentURL absoluteString];
|
|
||||||
if ([componentURLPath rangeOfString: baseURLString].location
|
|
||||||
!= NSNotFound)
|
|
||||||
{
|
|
||||||
urlComponents = [componentURLPath componentsSeparatedByString: @"/"];
|
|
||||||
cName = [[urls objectAtIndex: count] lastPathComponent];
|
|
||||||
[cNames setObject: [urls objectAtIndex: count] forKey: cName];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *) _fetchComponentsWithNames: (NSArray *) cNames
|
|
||||||
fields: (NSArray *) fields
|
|
||||||
{
|
|
||||||
NSMutableString *filterString;
|
|
||||||
NSArray *records;
|
|
||||||
|
|
||||||
// NSLog (@"fetchComponentsWithNames");
|
|
||||||
filterString = [NSMutableString string];
|
|
||||||
[filterString appendFormat: @"c_name='%@'",
|
|
||||||
[cNames componentsJoinedByString: @"' OR c_name='"]];
|
|
||||||
// NSLog (@"fetchComponentsWithNames: query");
|
|
||||||
records = [self bareFetchFields: fields
|
|
||||||
from: nil to: nil
|
|
||||||
title: nil
|
|
||||||
component: nil
|
|
||||||
additionalFilters: filterString];
|
|
||||||
// NSLog (@"/fetchComponentsWithNames");
|
|
||||||
|
|
||||||
return records;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define maxQuerySize 2500
|
|
||||||
#define baseQuerySize 160
|
|
||||||
#define idQueryOverhead 13
|
|
||||||
|
|
||||||
- (NSArray *) _fetchComponentsMatchingObjectNames: (NSArray *) cNames
|
|
||||||
fields: (NSArray *) fields
|
|
||||||
{
|
|
||||||
NSMutableArray *components;
|
|
||||||
NSArray *records;
|
|
||||||
NSMutableArray *currentNames;
|
|
||||||
unsigned int count, max, currentSize, queryNameLength;
|
|
||||||
NSString *currentName;
|
|
||||||
|
|
||||||
// NSLog (@"fetching components matching names");
|
|
||||||
|
|
||||||
currentNames = [NSMutableArray array];
|
|
||||||
currentSize = baseQuerySize;
|
|
||||||
|
|
||||||
max = [cNames count];
|
|
||||||
components = [NSMutableArray arrayWithCapacity: max];
|
|
||||||
for (count = 0; count < max; count++)
|
|
||||||
{
|
|
||||||
currentName = [cNames objectAtIndex: count];
|
|
||||||
queryNameLength = idQueryOverhead + [currentName length];
|
|
||||||
if ((currentSize + queryNameLength)
|
|
||||||
> maxQuerySize)
|
|
||||||
{
|
|
||||||
records = [self _fetchComponentsWithNames: currentNames fields: fields];
|
|
||||||
[components addObjectsFromArray: records];
|
|
||||||
[currentNames removeAllObjects];
|
|
||||||
currentSize = baseQuerySize;
|
|
||||||
}
|
|
||||||
[currentNames addObject: currentName];
|
|
||||||
currentSize += queryNameLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
records = [self _fetchComponentsWithNames: currentNames fields: fields];
|
|
||||||
[components addObjectsFromArray: records];
|
|
||||||
|
|
||||||
// NSLog (@"/fetching components matching names");
|
|
||||||
|
|
||||||
return components;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSDictionary *) _fetchComponentsMatchingURLs: (NSArray *) urls
|
|
||||||
fields: (NSArray *) fields
|
|
||||||
{
|
|
||||||
NSMutableDictionary *components;
|
|
||||||
NSDictionary *cnames, *record;
|
|
||||||
NSString *recordURL;
|
|
||||||
NSArray *records;
|
|
||||||
unsigned int count, max;
|
|
||||||
|
|
||||||
components = [NSMutableDictionary dictionary];
|
|
||||||
|
|
||||||
cnames = [self _deduceObjectNamesFromURLs: urls];
|
|
||||||
records = [self _fetchComponentsMatchingObjectNames: [cnames allKeys]
|
|
||||||
fields: fields];
|
|
||||||
max = [records count];
|
|
||||||
for (count = 0; count < max; count++)
|
|
||||||
{
|
|
||||||
record = [records objectAtIndex: count];
|
|
||||||
recordURL = [cnames objectForKey: [record objectForKey: @"c_name"]];
|
|
||||||
if (recordURL)
|
|
||||||
[components setObject: record forKey: recordURL];
|
|
||||||
}
|
|
||||||
|
|
||||||
return components;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) _appendComponentProperties: (NSDictionary *) properties
|
|
||||||
matchingURLs: (id <DOMNodeList>) refs
|
|
||||||
toResponse: (WOResponse *) response
|
|
||||||
{
|
|
||||||
NSObject <DOMElement> *element;
|
|
||||||
NSDictionary *currentComponent, *components;
|
|
||||||
NSString *currentURL, *baseURL, *currentField;
|
|
||||||
NSString **propertiesArray;
|
|
||||||
NSMutableArray *urls, *fields;
|
|
||||||
NSMutableString *buffer;
|
|
||||||
unsigned int count, max, propertiesCount;
|
|
||||||
NSEnumerator *addFields;
|
|
||||||
|
|
||||||
baseURL = [self davURLAsString];
|
|
||||||
#warning review this when fixing http://www.scalableogo.org/bugs/view.php?id=276
|
|
||||||
if (![baseURL hasSuffix: @"/"])
|
|
||||||
baseURL = [NSString stringWithFormat: @"%@/", baseURL];
|
|
||||||
|
|
||||||
urls = [NSMutableArray array];
|
|
||||||
max = [refs length];
|
|
||||||
for (count = 0; count < max; count++)
|
|
||||||
{
|
|
||||||
element = [refs objectAtIndex: count];
|
|
||||||
currentURL = [[element firstChild] nodeValue];
|
|
||||||
[urls addObject: currentURL];
|
|
||||||
}
|
|
||||||
|
|
||||||
propertiesArray = [[properties allKeys] asPointersOfObjects];
|
|
||||||
propertiesCount = [properties count];
|
|
||||||
|
|
||||||
fields = [NSMutableArray arrayWithObjects: @"c_name", @"c_component", nil];
|
|
||||||
addFields = [[properties allValues] objectEnumerator];
|
|
||||||
while ((currentField = [addFields nextObject]))
|
|
||||||
if ([currentField length])
|
|
||||||
[fields addObjectUniquely: currentField];
|
|
||||||
|
|
||||||
components = [self _fetchComponentsMatchingURLs: urls fields: fields];
|
|
||||||
max = [urls count];
|
|
||||||
// NSLog (@"adding properties with url");
|
|
||||||
buffer = [NSMutableString stringWithCapacity: max*512];
|
|
||||||
for (count = 0; count < max; count++)
|
|
||||||
{
|
|
||||||
currentComponent = [components objectForKey: [urls objectAtIndex: count]];
|
|
||||||
if (currentComponent)
|
|
||||||
[self appendObject: currentComponent
|
|
||||||
properties: propertiesArray
|
|
||||||
count: propertiesCount
|
|
||||||
withBaseURL: baseURL
|
|
||||||
toBuffer: buffer];
|
|
||||||
else
|
|
||||||
[self appendMissingObjectRef: currentURL
|
|
||||||
toBuffer: buffer];
|
|
||||||
}
|
|
||||||
[response appendContentString: buffer];
|
|
||||||
// NSLog (@"/adding properties with url");
|
|
||||||
|
|
||||||
NSZoneFree (NULL, propertiesArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) davCalendarMultiget: (id) queryContext
|
|
||||||
{
|
|
||||||
WOResponse *r;
|
|
||||||
id <DOMDocument> document;
|
|
||||||
DOMElement *documentElement, *propElement;
|
|
||||||
|
|
||||||
r = [context response];
|
|
||||||
[r prepareDAVResponse];
|
|
||||||
[r appendContentString: @"<D:multistatus xmlns:D=\"DAV:\""
|
|
||||||
@" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">"];
|
|
||||||
|
|
||||||
document = [[context request] contentAsDOMDocument];
|
|
||||||
documentElement = (DOMElement *) [document documentElement];
|
|
||||||
propElement = [documentElement firstElementWithTag: @"prop"
|
|
||||||
inNamespace: @"DAV:"];
|
|
||||||
|
|
||||||
[self _appendComponentProperties: [self parseDAVRequestedProperties: propElement]
|
|
||||||
matchingURLs: [documentElement getElementsByTagName: @"href"]
|
|
||||||
toResponse: r];
|
|
||||||
[r appendContentString:@"</D:multistatus>"];
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) additionalWebdavSyncFilters
|
- (NSString *) additionalWebdavSyncFilters
|
||||||
|
|
|
@ -42,10 +42,6 @@
|
||||||
|
|
||||||
@protocol SOGoContactFolder <NSObject>
|
@protocol SOGoContactFolder <NSObject>
|
||||||
|
|
||||||
- (void) appendObject: (NSDictionary *) object
|
|
||||||
withBaseURL: (NSString *) baseURL
|
|
||||||
toREPORTResponse: (WOResponse *) r;
|
|
||||||
|
|
||||||
- (NSArray *) lookupContactsWithFilter: (NSString *) filter
|
- (NSArray *) lookupContactsWithFilter: (NSString *) filter
|
||||||
sortBy: (NSString *) sortKey
|
sortBy: (NSString *) sortKey
|
||||||
ordering: (NSComparisonResult) sortOrdering;
|
ordering: (NSComparisonResult) sortOrdering;
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||||
#import <SOGo/SOGoUser.h>
|
#import <SOGo/SOGoUser.h>
|
||||||
#import <SOGo/SOGoUserManager.h>
|
#import <SOGo/SOGoUserManager.h>
|
||||||
|
#import <SOGo/WORequest+SOGo.h>
|
||||||
|
|
||||||
#import "SOGoContactGCSFolder.h"
|
#import "SOGoContactGCSFolder.h"
|
||||||
#import "SOGoContactSourceFolder.h"
|
#import "SOGoContactSourceFolder.h"
|
||||||
|
@ -87,4 +88,16 @@
|
||||||
return [self labelForKey: @"Personal Address Book"];
|
return [self labelForKey: @"Personal Address Book"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSArray *) toManyRelationshipKeys
|
||||||
|
{
|
||||||
|
NSMutableArray *keys;
|
||||||
|
|
||||||
|
if ([[context request] isAddressBookApp])
|
||||||
|
keys = [NSMutableArray arrayWithObject: @"personal"];
|
||||||
|
else
|
||||||
|
keys = (NSMutableArray *) [super toManyRelationshipKeys];
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#import <Foundation/NSArray.h>
|
#import <Foundation/NSArray.h>
|
||||||
#import <Foundation/NSEnumerator.h>
|
#import <Foundation/NSEnumerator.h>
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
|
#import <Foundation/NSURL.h>
|
||||||
|
|
||||||
#import <NGObjWeb/NSException+HTTP.h>
|
#import <NGObjWeb/NSException+HTTP.h>
|
||||||
#import <NGObjWeb/SoObject+SoDAV.h>
|
#import <NGObjWeb/SoObject+SoDAV.h>
|
||||||
|
@ -31,15 +32,23 @@
|
||||||
#import <NGObjWeb/WOResponse.h>
|
#import <NGObjWeb/WOResponse.h>
|
||||||
#import <NGExtensions/NSObject+Logs.h>
|
#import <NGExtensions/NSObject+Logs.h>
|
||||||
#import <NGExtensions/NSString+misc.h>
|
#import <NGExtensions/NSString+misc.h>
|
||||||
#import <NGCards/CardGroup.h>
|
#import <NGExtensions/NSNull+misc.h>
|
||||||
|
#import <DOM/DOMElement.h>
|
||||||
|
#import <DOM/DOMProtocols.h>
|
||||||
|
#import <SaxObjC/XMLNamespaces.h>
|
||||||
#import <EOControl/EOQualifier.h>
|
#import <EOControl/EOQualifier.h>
|
||||||
#import <EOControl/EOSortOrdering.h>
|
#import <EOControl/EOSortOrdering.h>
|
||||||
|
|
||||||
|
#import <NGCards/CardGroup.h>
|
||||||
#import <GDLContentStore/GCSFolder.h>
|
#import <GDLContentStore/GCSFolder.h>
|
||||||
|
|
||||||
|
#import <SOGo/DOMNode+SOGo.h>
|
||||||
#import <SOGo/SOGoCache.h>
|
#import <SOGo/SOGoCache.h>
|
||||||
#import <SOGo/NSArray+Utilities.h>
|
#import <SOGo/NSArray+Utilities.h>
|
||||||
#import <SOGo/NSDictionary+Utilities.h>
|
#import <SOGo/NSDictionary+Utilities.h>
|
||||||
#import <SOGo/NSString+Utilities.h>
|
#import <SOGo/NSString+Utilities.h>
|
||||||
|
#import <SOGo/NSObject+DAV.h>
|
||||||
|
#import <SOGo/WOResponse+SOGo.h>
|
||||||
|
|
||||||
#import "SOGoContactGCSEntry.h"
|
#import "SOGoContactGCSEntry.h"
|
||||||
#import "SOGoContactGCSList.h"
|
#import "SOGoContactGCSList.h"
|
||||||
|
@ -84,7 +93,7 @@ static NSArray *folderListingFields = nil;
|
||||||
- (Class) objectClassForComponentName: (NSString *) componentName
|
- (Class) objectClassForComponentName: (NSString *) componentName
|
||||||
{
|
{
|
||||||
Class objectClass;
|
Class objectClass;
|
||||||
|
|
||||||
if ([componentName isEqualToString: @"vcard"])
|
if ([componentName isEqualToString: @"vcard"])
|
||||||
objectClass = [SOGoContactGCSEntry class];
|
objectClass = [SOGoContactGCSEntry class];
|
||||||
else if ([componentName isEqualToString: @"vlist"])
|
else if ([componentName isEqualToString: @"vlist"])
|
||||||
|
@ -289,38 +298,17 @@ static NSArray *folderListingFields = nil;
|
||||||
return records;
|
return records;
|
||||||
}
|
}
|
||||||
|
|
||||||
#warning this should be unified within SOGoFolder
|
- (NSDictionary *) davSQLFieldsTable
|
||||||
- (void) appendObject: (NSDictionary *) object
|
|
||||||
withBaseURL: (NSString *) baseURL
|
|
||||||
toREPORTResponse: (WOResponse *) r
|
|
||||||
{
|
{
|
||||||
SOGoContactGCSEntry *component;
|
static NSMutableDictionary *davSQLFieldsTable = nil;
|
||||||
NSString *name, *etagLine, *contactString;
|
|
||||||
|
|
||||||
name = [object objectForKey: @"c_name"];
|
if (!davSQLFieldsTable)
|
||||||
component = [self lookupName: name inContext: context acquire: NO];
|
{
|
||||||
|
davSQLFieldsTable = [[super davSQLFieldsTable] mutableCopy];
|
||||||
|
[davSQLFieldsTable setObject: @"c_content" forKey: @"{urn:ietf:params:xml:ns:carddav}address-data"];
|
||||||
|
}
|
||||||
|
|
||||||
[r appendContentString: @" <D:response>\r\n"];
|
return davSQLFieldsTable;
|
||||||
[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
|
- (NSArray *) davComplianceClassesInContext: (id)_ctx
|
||||||
|
@ -359,6 +347,12 @@ static NSArray *folderListingFields = nil;
|
||||||
return resourceType;
|
return resourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id) davAddressbookMultiget: (id) queryContext
|
||||||
|
{
|
||||||
|
return [self performMultigetInContext: queryContext
|
||||||
|
inNamespace: @"urn:ietf:params:xml:ns:carddav"];
|
||||||
|
}
|
||||||
|
|
||||||
/* sorting */
|
/* sorting */
|
||||||
- (NSComparisonResult) compare: (id) otherFolder
|
- (NSComparisonResult) compare: (id) otherFolder
|
||||||
{
|
{
|
||||||
|
@ -385,4 +379,22 @@ static NSArray *folderListingFields = nil;
|
||||||
return @"IPF.Contact";
|
return @"IPF.Contact";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: multiget reorg */
|
||||||
|
- (NSString *) _nodeTagForProperty: (NSString *) property
|
||||||
|
{
|
||||||
|
NSString *namespace, *nodeName, *nsRep;
|
||||||
|
NSRange nsEnd;
|
||||||
|
|
||||||
|
nsEnd = [property rangeOfString: @"}"];
|
||||||
|
namespace
|
||||||
|
= [property substringFromRange: NSMakeRange (1, nsEnd.location - 1)];
|
||||||
|
nodeName = [property substringFromIndex: nsEnd.location + 1];
|
||||||
|
if ([namespace isEqualToString: XMLNS_CARDDAV])
|
||||||
|
nsRep = @"C";
|
||||||
|
else
|
||||||
|
nsRep = @"D";
|
||||||
|
|
||||||
|
return [NSString stringWithFormat: @"%@:%@", nsRep, nodeName];
|
||||||
|
}
|
||||||
|
|
||||||
@end /* SOGoContactGCSFolder */
|
@end /* SOGoContactGCSFolder */
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#import <NGObjWeb/SoSelectorInvocation.h>
|
#import <NGObjWeb/SoSelectorInvocation.h>
|
||||||
#import <NGObjWeb/SoUser.h>
|
#import <NGObjWeb/SoUser.h>
|
||||||
#import <NGExtensions/NSString+misc.h>
|
#import <NGExtensions/NSString+misc.h>
|
||||||
#import <NGExtensions/NSObject+Logs.h>
|
|
||||||
#import <EOControl/EOSortOrdering.h>
|
#import <EOControl/EOSortOrdering.h>
|
||||||
#import <SaxObjC/XMLNamespaces.h>
|
#import <SaxObjC/XMLNamespaces.h>
|
||||||
|
|
||||||
|
@ -50,49 +49,6 @@
|
||||||
|
|
||||||
@implementation SOGoContactSourceFolder
|
@implementation SOGoContactSourceFolder
|
||||||
|
|
||||||
#warning this should be unified within SOGoFolder
|
|
||||||
- (void) appendObject: (NSDictionary *) object
|
|
||||||
withBaseURL: (NSString *) baseURL
|
|
||||||
toREPORTResponse: (WOResponse *) r
|
|
||||||
{
|
|
||||||
SOGoContactLDIFEntry *component;
|
|
||||||
NSString *name, *etagLine, *contactString;
|
|
||||||
|
|
||||||
name = [object objectForKey: @"c_name"];
|
|
||||||
if ([name length])
|
|
||||||
{
|
|
||||||
component = [self lookupName: name inContext: context acquire: NO];
|
|
||||||
|
|
||||||
if ([component isKindOfClass: [NSException class]])
|
|
||||||
{
|
|
||||||
[self logWithFormat: @"Object with name '%@' not found. You likely have a LDAP configuration issue.", name];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[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"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (id) folderWithName: (NSString *) aName
|
+ (id) folderWithName: (NSString *) aName
|
||||||
andDisplayName: (NSString *) aDisplayName
|
andDisplayName: (NSString *) aDisplayName
|
||||||
inContainer: (id) aContainer
|
inContainer: (id) aContainer
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#import <NGObjWeb/WOContext.h>
|
#import <NGObjWeb/WOContext.h>
|
||||||
#import <NGObjWeb/WORequest.h>
|
#import <NGObjWeb/WORequest.h>
|
||||||
#import <NGObjWeb/WOResponse.h>
|
#import <NGObjWeb/WOResponse.h>
|
||||||
|
#import <NGExtensions/NSObject+Logs.h>
|
||||||
#import <NGExtensions/NSString+misc.h>
|
#import <NGExtensions/NSString+misc.h>
|
||||||
#import <DOM/DOMProtocols.h>
|
#import <DOM/DOMProtocols.h>
|
||||||
#import <SaxObjC/SaxObjC.h>
|
#import <SaxObjC/SaxObjC.h>
|
||||||
|
@ -39,6 +40,50 @@
|
||||||
|
|
||||||
@implementation SOGoFolder (CardDAV)
|
@implementation SOGoFolder (CardDAV)
|
||||||
|
|
||||||
|
- (void) _appendObject: (NSDictionary *) object
|
||||||
|
withBaseURL: (NSString *) baseURL
|
||||||
|
toREPORTResponse: (WOResponse *) r
|
||||||
|
{
|
||||||
|
id component;
|
||||||
|
NSString *name, *etagLine, *contactString;
|
||||||
|
|
||||||
|
name = [object objectForKey: @"c_name"];
|
||||||
|
if ([name length])
|
||||||
|
{
|
||||||
|
component = [self lookupName: name inContext: context acquire: NO];
|
||||||
|
if ([component isKindOfClass: [NSException class]])
|
||||||
|
{
|
||||||
|
[self logWithFormat: @"Object with name '%@' not found. You likely have a LDAP configuration issue.", name];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#warning we provide both "address-data" and "addressbook-data" for compatibility reasons, we should actually check which one has been queried
|
||||||
|
[r appendContentString: @"<D:response>"
|
||||||
|
@"<D:href>"];
|
||||||
|
[r appendContentString: baseURL];
|
||||||
|
if (![baseURL hasSuffix: @"/"])
|
||||||
|
[r appendContentString: @"/"];
|
||||||
|
[r appendContentString: name];
|
||||||
|
[r appendContentString: @"</D:href>"
|
||||||
|
@"<D:propstat>"
|
||||||
|
@"<D:prop>"];
|
||||||
|
etagLine = [NSString stringWithFormat: @"<D:getetag>%@</D:getetag>",
|
||||||
|
[component davEntityTag]];
|
||||||
|
[r appendContentString: etagLine];
|
||||||
|
[r appendContentString: @"</D:prop>"
|
||||||
|
@"<D:status>HTTP/1.1 200 OK</D:status>"
|
||||||
|
@"</D:propstat>"
|
||||||
|
@"<C:addressbook-data>"];
|
||||||
|
contactString = [[component contentAsString] stringByEscapingXMLString];
|
||||||
|
[r appendContentString: contactString];
|
||||||
|
[r appendContentString: @"</C:addressbook-data>"
|
||||||
|
@"<C:address-data>"];
|
||||||
|
[r appendContentString: contactString];
|
||||||
|
[r appendContentString: @"</C:address-data>"
|
||||||
|
@"</D:response>"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void) _appendComponentsMatchingFilters: (NSArray *) filters
|
- (void) _appendComponentsMatchingFilters: (NSArray *) filters
|
||||||
toResponse: (WOResponse *) response
|
toResponse: (WOResponse *) response
|
||||||
context: (id) localContext
|
context: (id) localContext
|
||||||
|
@ -60,9 +105,8 @@
|
||||||
objectEnumerator];
|
objectEnumerator];
|
||||||
|
|
||||||
while ((contact = [contacts nextObject]))
|
while ((contact = [contacts nextObject]))
|
||||||
[(id<SOGoContactFolder>)self appendObject: contact
|
[self _appendObject: contact withBaseURL: baseURL
|
||||||
withBaseURL: baseURL
|
toREPORTResponse: response];
|
||||||
toREPORTResponse: response];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +187,7 @@
|
||||||
[self _appendComponentsMatchingFilters: filters
|
[self _appendComponentsMatchingFilters: filters
|
||||||
toResponse: r
|
toResponse: r
|
||||||
context: queryContext];
|
context: queryContext];
|
||||||
[r appendContentString:@"</D:multistatus>"];
|
[r appendContentString: @"</D:multistatus>"];
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,10 @@
|
||||||
|
|
||||||
- (NSString *) davCollectionTag;
|
- (NSString *) davCollectionTag;
|
||||||
|
|
||||||
|
/* multiget helper */
|
||||||
|
- (WOResponse *) performMultigetInContext: (WOContext *) queryContext
|
||||||
|
inNamespace: (NSString *) namespace;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif /* __SOGo_SOGoGCSFolder_H__ */
|
#endif /* __SOGo_SOGoGCSFolder_H__ */
|
||||||
|
|
|
@ -1685,4 +1685,392 @@ static NSArray *childRecordFields = nil;
|
||||||
[_ms appendFormat:@" ocs=%@", [self ocsPath]];
|
[_ms appendFormat:@" ocs=%@", [self ocsPath]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tmp: multiget */
|
||||||
|
|
||||||
|
- (NSArray *) _fetchComponentsWithNames: (NSArray *) cNames
|
||||||
|
fields: (NSArray *) fields
|
||||||
|
{
|
||||||
|
NSArray *records;
|
||||||
|
NSString *sqlFilter;
|
||||||
|
NSMutableString *filterString;
|
||||||
|
EOQualifier *qualifier;
|
||||||
|
|
||||||
|
sqlFilter = [self aclSQLListingFilter];
|
||||||
|
if (sqlFilter)
|
||||||
|
{
|
||||||
|
filterString = [NSMutableString stringWithCapacity: 8192];
|
||||||
|
[filterString appendFormat: @"(c_name='%@')",
|
||||||
|
[cNames componentsJoinedByString: @"' OR c_name='"]];
|
||||||
|
if ([sqlFilter length] > 0)
|
||||||
|
[filterString appendFormat: @" AND (%@)", sqlFilter];
|
||||||
|
qualifier = [EOQualifier qualifierWithQualifierFormat: filterString];
|
||||||
|
records = [[self ocsFolder] fetchFields: fields
|
||||||
|
matchingQualifier: qualifier];
|
||||||
|
if (![records isNotNull])
|
||||||
|
{
|
||||||
|
[self errorWithFormat: @"(%s): fetch failed!", __PRETTY_FUNCTION__];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
records = [NSArray array];
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define maxQuerySize 2500
|
||||||
|
#define baseQuerySize 160
|
||||||
|
#define idQueryOverhead 13
|
||||||
|
|
||||||
|
- (NSArray *) _fetchComponentsMatchingObjectNames: (NSArray *) cNames
|
||||||
|
fields: (NSArray *) fields
|
||||||
|
{
|
||||||
|
NSMutableArray *components;
|
||||||
|
NSArray *records;
|
||||||
|
NSMutableArray *currentNames;
|
||||||
|
unsigned int count, max, currentSize, queryNameLength;
|
||||||
|
NSString *currentName;
|
||||||
|
|
||||||
|
// NSLog (@"fetching components matching names");
|
||||||
|
|
||||||
|
currentNames = [NSMutableArray array];
|
||||||
|
currentSize = baseQuerySize;
|
||||||
|
|
||||||
|
max = [cNames count];
|
||||||
|
components = [NSMutableArray arrayWithCapacity: max];
|
||||||
|
for (count = 0; count < max; count++)
|
||||||
|
{
|
||||||
|
currentName = [cNames objectAtIndex: count];
|
||||||
|
queryNameLength = idQueryOverhead + [currentName length];
|
||||||
|
if ((currentSize + queryNameLength)
|
||||||
|
> maxQuerySize)
|
||||||
|
{
|
||||||
|
records = [self _fetchComponentsWithNames: currentNames fields: fields];
|
||||||
|
[components addObjectsFromArray: records];
|
||||||
|
[currentNames removeAllObjects];
|
||||||
|
currentSize = baseQuerySize;
|
||||||
|
}
|
||||||
|
[currentNames addObject: currentName];
|
||||||
|
currentSize += queryNameLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
records = [self _fetchComponentsWithNames: currentNames fields: fields];
|
||||||
|
[components addObjectsFromArray: records];
|
||||||
|
|
||||||
|
// NSLog (@"/fetching components matching names");
|
||||||
|
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *) _deduceObjectNamesFromURLs: (NSArray *) urls
|
||||||
|
{
|
||||||
|
unsigned int count, max;
|
||||||
|
NSString *url, *componentURLPath, *cName, *baseURLString;
|
||||||
|
NSMutableDictionary *cNames;
|
||||||
|
NSURL *componentURL, *baseURL;
|
||||||
|
NSArray *urlComponents;
|
||||||
|
|
||||||
|
max = [urls count];
|
||||||
|
cNames = [NSMutableDictionary dictionaryWithCapacity: max];
|
||||||
|
baseURL = [self davURL];
|
||||||
|
baseURLString = [self davURLAsString];
|
||||||
|
|
||||||
|
for (count = 0; count < max; count++)
|
||||||
|
{
|
||||||
|
url = [NSString stringWithFormat: @"%@/%@",
|
||||||
|
[[urls objectAtIndex: count] stringByDeletingLastPathComponent],
|
||||||
|
[[[urls objectAtIndex: count] lastPathComponent] stringByEscapingURL]];
|
||||||
|
componentURL = [[NSURL URLWithString: url relativeToURL: baseURL]
|
||||||
|
standardizedURL];
|
||||||
|
componentURLPath = [componentURL absoluteString];
|
||||||
|
if ([componentURLPath rangeOfString: baseURLString].location
|
||||||
|
!= NSNotFound)
|
||||||
|
{
|
||||||
|
urlComponents = [componentURLPath componentsSeparatedByString: @"/"];
|
||||||
|
cName = [[urls objectAtIndex: count] lastPathComponent];
|
||||||
|
[cNames setObject: [urls objectAtIndex: count] forKey: cName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *) _fetchComponentsMatchingURLs: (NSArray *) urls
|
||||||
|
fields: (NSArray *) fields
|
||||||
|
{
|
||||||
|
NSMutableDictionary *components;
|
||||||
|
NSDictionary *cnames, *record;
|
||||||
|
NSString *recordURL;
|
||||||
|
NSArray *records;
|
||||||
|
unsigned int count, max;
|
||||||
|
|
||||||
|
components = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
cnames = [self _deduceObjectNamesFromURLs: urls];
|
||||||
|
records = [self _fetchComponentsMatchingObjectNames: [cnames allKeys]
|
||||||
|
fields: fields];
|
||||||
|
max = [records count];
|
||||||
|
for (count = 0; count < max; count++)
|
||||||
|
{
|
||||||
|
record = [records objectAtIndex: count];
|
||||||
|
recordURL = [cnames objectForKey: [record objectForKey: @"c_name"]];
|
||||||
|
if (recordURL)
|
||||||
|
[components setObject: record forKey: recordURL];
|
||||||
|
}
|
||||||
|
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
#warning the two following methods should be replaced with the new dav rendering mechanism
|
||||||
|
- (NSString *) _nodeTagForProperty: (NSString *) property
|
||||||
|
{
|
||||||
|
[self subclassResponsibility: _cmd];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) _nodeTag: (NSString *) property
|
||||||
|
{
|
||||||
|
static NSMutableDictionary *tags = nil;
|
||||||
|
NSString *nodeTag;
|
||||||
|
|
||||||
|
if (!tags)
|
||||||
|
tags = [NSMutableDictionary new];
|
||||||
|
nodeTag = [tags objectForKey: property];
|
||||||
|
if (!nodeTag)
|
||||||
|
{
|
||||||
|
nodeTag = [self _nodeTagForProperty: property];
|
||||||
|
[tags setObject: nodeTag forKey: property];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString **) _properties: (NSString **) properties
|
||||||
|
count: (unsigned int) propertiesCount
|
||||||
|
ofObject: (NSDictionary *) object
|
||||||
|
{
|
||||||
|
SOGoContentObject *sogoObject;
|
||||||
|
NSString **currentProperty;
|
||||||
|
NSString **values, **currentValue;
|
||||||
|
SEL methodSel;
|
||||||
|
|
||||||
|
// NSLog (@"_properties:ofObject:: %@", [NSDate date]);
|
||||||
|
|
||||||
|
values = NSZoneMalloc (NULL,
|
||||||
|
(propertiesCount + 1) * sizeof (NSString *));
|
||||||
|
*(values + propertiesCount) = nil;
|
||||||
|
|
||||||
|
//c = [self objectClassForComponentName: [object objectForKey: @"c_component"]];
|
||||||
|
|
||||||
|
sogoObject = [self createChildComponentWithRecord: object];
|
||||||
|
currentProperty = properties;
|
||||||
|
currentValue = values;
|
||||||
|
while (*currentProperty)
|
||||||
|
{
|
||||||
|
methodSel = SOGoSelectorForPropertyGetter (*currentProperty);
|
||||||
|
if (methodSel && [sogoObject respondsToSelector: methodSel])
|
||||||
|
*currentValue = [[sogoObject performSelector: methodSel]
|
||||||
|
stringByEscapingXMLString];
|
||||||
|
currentProperty++;
|
||||||
|
currentValue++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NSLog (@"/_properties:ofObject:: %@", [NSDate date]);
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *) _propstats: (NSString **) properties
|
||||||
|
count: (unsigned int) propertiesCount
|
||||||
|
ofObject: (NSDictionary *) object
|
||||||
|
{
|
||||||
|
NSMutableArray *propstats, *properties200, *properties404, *propDict;
|
||||||
|
NSString **property, **values, **currentValue;
|
||||||
|
NSString *propertyValue, *nodeTag;
|
||||||
|
|
||||||
|
// NSLog (@"_propstats:ofObject:: %@", [NSDate date]);
|
||||||
|
|
||||||
|
propstats = [NSMutableArray array];
|
||||||
|
|
||||||
|
properties200 = [NSMutableArray array];
|
||||||
|
properties404 = [NSMutableArray array];
|
||||||
|
|
||||||
|
values = [self _properties: properties count: propertiesCount
|
||||||
|
ofObject: object];
|
||||||
|
currentValue = values;
|
||||||
|
|
||||||
|
property = properties;
|
||||||
|
while (*property)
|
||||||
|
{
|
||||||
|
nodeTag = [self _nodeTag: *property];
|
||||||
|
if (*currentValue)
|
||||||
|
{
|
||||||
|
propertyValue = [NSString stringWithFormat: @"<%@>%@</%@>",
|
||||||
|
nodeTag, *currentValue, nodeTag];
|
||||||
|
propDict = properties200;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
propertyValue = [NSString stringWithFormat: @"<%@/>", nodeTag];
|
||||||
|
propDict = properties404;
|
||||||
|
}
|
||||||
|
[propDict addObject: propertyValue];
|
||||||
|
property++;
|
||||||
|
currentValue++;
|
||||||
|
}
|
||||||
|
free (values);
|
||||||
|
|
||||||
|
if ([properties200 count])
|
||||||
|
[propstats addObject: [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
properties200, @"properties",
|
||||||
|
@"HTTP/1.1 200 OK", @"status",
|
||||||
|
nil]];
|
||||||
|
if ([properties404 count])
|
||||||
|
[propstats addObject: [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
properties404, @"properties",
|
||||||
|
@"HTTP/1.1 404 Not Found", @"status",
|
||||||
|
nil]];
|
||||||
|
// NSLog (@"/_propstats:ofObject:: %@", [NSDate date]);
|
||||||
|
|
||||||
|
return propstats;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) _appendPropstat: (NSDictionary *) propstat
|
||||||
|
toBuffer: (NSMutableString *) r
|
||||||
|
{
|
||||||
|
NSArray *properties;
|
||||||
|
unsigned int count, max;
|
||||||
|
|
||||||
|
[r appendString: @"<D:propstat><D:prop>"];
|
||||||
|
properties = [propstat objectForKey: @"properties"];
|
||||||
|
max = [properties count];
|
||||||
|
for (count = 0; count < max; count++)
|
||||||
|
[r appendString: [properties objectAtIndex: count]];
|
||||||
|
[r appendString: @"</D:prop><D:status>"];
|
||||||
|
[r appendString: [propstat objectForKey: @"status"]];
|
||||||
|
[r appendString: @"</D:status></D:propstat>"];
|
||||||
|
}
|
||||||
|
|
||||||
|
#warning We need to use the new DAV utilities here...
|
||||||
|
#warning this is baddddd because we return a single-valued dictionary containing \
|
||||||
|
a cname which may not event exist... the logic behind appendObject:... should be \
|
||||||
|
rethought, especially since we may start using SQL views
|
||||||
|
|
||||||
|
- (void) appendObject: (NSDictionary *) object
|
||||||
|
properties: (NSString **) properties
|
||||||
|
count: (unsigned int) propertiesCount
|
||||||
|
withBaseURL: (NSString *) baseURL
|
||||||
|
toBuffer: (NSMutableString *) r
|
||||||
|
{
|
||||||
|
NSArray *propstats;
|
||||||
|
unsigned int count, max;
|
||||||
|
|
||||||
|
[r appendFormat: @"<D:response><D:href>"];
|
||||||
|
[r appendString: baseURL];
|
||||||
|
[r appendString: [object objectForKey: @"c_name"]];
|
||||||
|
[r appendString: @"</D:href>"];
|
||||||
|
|
||||||
|
// NSLog (@"(appendPropstats...): %@", [NSDate date]);
|
||||||
|
propstats = [self _propstats: properties count: propertiesCount
|
||||||
|
ofObject: object];
|
||||||
|
max = [propstats count];
|
||||||
|
for (count = 0; count < max; count++)
|
||||||
|
[self _appendPropstat: [propstats objectAtIndex: count]
|
||||||
|
toBuffer: r];
|
||||||
|
// NSLog (@"/(appendPropstats...): %@", [NSDate date]);
|
||||||
|
|
||||||
|
[r appendString: @"</D:response>"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) appendMissingObjectRef: (NSString *) href
|
||||||
|
toBuffer: (NSMutableString *) r
|
||||||
|
{
|
||||||
|
[r appendString: @"<D:response><D:href>"];
|
||||||
|
[r appendString: href];
|
||||||
|
[r appendString: @"</D:href><D:status>HTTP/1.1 404 Not Found</D:status></D:response>"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) _appendComponentProperties: (NSDictionary *) properties
|
||||||
|
matchingURLs: (id <DOMNodeList>) refs
|
||||||
|
toResponse: (WOResponse *) response
|
||||||
|
{
|
||||||
|
NSObject <DOMElement> *element;
|
||||||
|
NSDictionary *currentComponent, *components;
|
||||||
|
NSString *currentURL, *baseURL, *currentField;
|
||||||
|
NSString **propertiesArray;
|
||||||
|
NSMutableArray *urls, *fields;
|
||||||
|
NSMutableString *buffer;
|
||||||
|
unsigned int count, max, propertiesCount;
|
||||||
|
NSEnumerator *addFields;
|
||||||
|
|
||||||
|
baseURL = [self davURLAsString];
|
||||||
|
#warning review this when fixing http://www.scalableogo.org/bugs/view.php?id=276
|
||||||
|
if (![baseURL hasSuffix: @"/"])
|
||||||
|
baseURL = [NSString stringWithFormat: @"%@/", baseURL];
|
||||||
|
|
||||||
|
urls = [NSMutableArray array];
|
||||||
|
max = [refs length];
|
||||||
|
for (count = 0; count < max; count++)
|
||||||
|
{
|
||||||
|
element = [refs objectAtIndex: count];
|
||||||
|
currentURL = [[element firstChild] nodeValue];
|
||||||
|
[urls addObject: currentURL];
|
||||||
|
}
|
||||||
|
|
||||||
|
propertiesArray = [[properties allKeys] asPointersOfObjects];
|
||||||
|
propertiesCount = [properties count];
|
||||||
|
|
||||||
|
fields = [NSMutableArray arrayWithObjects: @"c_name", @"c_component", nil];
|
||||||
|
addFields = [[properties allValues] objectEnumerator];
|
||||||
|
while ((currentField = [addFields nextObject]))
|
||||||
|
if ([currentField length])
|
||||||
|
[fields addObjectUniquely: currentField];
|
||||||
|
|
||||||
|
components = [self _fetchComponentsMatchingURLs: urls fields: fields];
|
||||||
|
max = [urls count];
|
||||||
|
// NSLog (@"adding properties with url");
|
||||||
|
buffer = [NSMutableString stringWithCapacity: max*512];
|
||||||
|
for (count = 0; count < max; count++)
|
||||||
|
{
|
||||||
|
currentComponent = [components objectForKey: [urls objectAtIndex: count]];
|
||||||
|
if (currentComponent)
|
||||||
|
[self appendObject: currentComponent
|
||||||
|
properties: propertiesArray
|
||||||
|
count: propertiesCount
|
||||||
|
withBaseURL: baseURL
|
||||||
|
toBuffer: buffer];
|
||||||
|
else
|
||||||
|
[self appendMissingObjectRef: currentURL
|
||||||
|
toBuffer: buffer];
|
||||||
|
}
|
||||||
|
[response appendContentString: buffer];
|
||||||
|
// NSLog (@"/adding properties with url");
|
||||||
|
|
||||||
|
NSZoneFree (NULL, propertiesArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (WOResponse *) performMultigetInContext: (WOContext *) queryContext
|
||||||
|
inNamespace: (NSString *) namespace
|
||||||
|
{
|
||||||
|
WOResponse *r;
|
||||||
|
id <DOMDocument> document;
|
||||||
|
DOMElement *documentElement, *propElement;
|
||||||
|
|
||||||
|
r = [context response];
|
||||||
|
[r prepareDAVResponse];
|
||||||
|
[r appendContentString:
|
||||||
|
[NSString stringWithFormat: @"<D:multistatus xmlns:D=\"DAV:\""
|
||||||
|
@" xmlns:C=\"%@\">", namespace]];
|
||||||
|
document = [[queryContext request] contentAsDOMDocument];
|
||||||
|
documentElement = (DOMElement *) [document documentElement];
|
||||||
|
propElement = [documentElement firstElementWithTag: @"prop"
|
||||||
|
inNamespace: @"DAV:"];
|
||||||
|
[self _appendComponentProperties: [self parseDAVRequestedProperties: propElement]
|
||||||
|
matchingURLs: [documentElement getElementsByTagName: @"href"]
|
||||||
|
toResponse: r];
|
||||||
|
[r appendContentString:@"</D:multistatus>"];
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
@end /* SOGoFolder */
|
@end /* SOGoFolder */
|
||||||
|
|
Loading…
Reference in a new issue