mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-10-11 23:07:12 +00:00
propagate from branch 'ca.inverse.sogo.1_3_1' (head 996598fce70f35fe733debbc06cb1ae8c677afe1)
to branch 'ca.inverse.sogo' (head e16807404ac6ea20632ee7e0e21ae2db34830540) Monotone-Parent: 996598fce70f35fe733debbc06cb1ae8c677afe1 Monotone-Parent: e16807404ac6ea20632ee7e0e21ae2db34830540 Monotone-Revision: 38aeede6f54d0b954356cd2d385ba01bbdd8aecd Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2010-08-17T14:10:30 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
commit
3945cc6438
97 files changed
+3642
-1968
No files matched your search
@@ -81,6 +81,16 @@
|
||||
|
||||
#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
|
||||
|
||||
static NSNumber *sharedYes = nil;
|
||||
@@ -1065,27 +1075,10 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
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 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 *namespace, *nodeName, *nsRep;
|
||||
@@ -1103,158 +1096,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
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 *now, *rc;
|
||||
@@ -1688,211 +1529,10 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
return r;
|
||||
}
|
||||
|
||||
- (NSDictionary *) _deduceObjectNamesFromURLs: (NSArray *) urls
|
||||
- (WOResponse *) davCalendarMultiget: (WOContext *) queryContext
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
- (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;
|
||||
return [self performMultigetInContext: queryContext
|
||||
inNamespace: @"urn:ietf:params:xml:ns:caldav"];
|
||||
}
|
||||
|
||||
- (NSString *) additionalWebdavSyncFilters
|
||||
|
||||
@@ -42,10 +42,6 @@
|
||||
|
||||
@protocol SOGoContactFolder <NSObject>
|
||||
|
||||
- (void) appendObject: (NSDictionary *) object
|
||||
withBaseURL: (NSString *) baseURL
|
||||
toREPORTResponse: (WOResponse *) r;
|
||||
|
||||
- (NSArray *) lookupContactsWithFilter: (NSString *) filter
|
||||
sortBy: (NSString *) sortKey
|
||||
ordering: (NSComparisonResult) sortOrdering;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
|
||||
#import "SOGoContactGCSFolder.h"
|
||||
#import "SOGoContactSourceFolder.h"
|
||||
@@ -87,4 +88,16 @@
|
||||
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
|
||||
@@ -115,6 +115,11 @@
|
||||
return @"text/x-vcard";
|
||||
}
|
||||
|
||||
- (NSString *) davAddressData
|
||||
{
|
||||
return [self contentAsString];
|
||||
}
|
||||
|
||||
/* specialized actions */
|
||||
|
||||
- (void) save
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/SoObject+SoDAV.h>
|
||||
@@ -31,15 +32,19 @@
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGCards/CardGroup.h>
|
||||
#import <SaxObjC/XMLNamespaces.h>
|
||||
#import <EOControl/EOQualifier.h>
|
||||
#import <EOControl/EOSortOrdering.h>
|
||||
|
||||
#import <NGCards/CardGroup.h>
|
||||
#import <GDLContentStore/GCSFolder.h>
|
||||
|
||||
#import <SOGo/DOMNode+SOGo.h>
|
||||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSDictionary+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/NSObject+DAV.h>
|
||||
|
||||
#import "SOGoContactGCSEntry.h"
|
||||
#import "SOGoContactGCSList.h"
|
||||
@@ -84,7 +89,7 @@ static NSArray *folderListingFields = nil;
|
||||
- (Class) objectClassForComponentName: (NSString *) componentName
|
||||
{
|
||||
Class objectClass;
|
||||
|
||||
|
||||
if ([componentName isEqualToString: @"vcard"])
|
||||
objectClass = [SOGoContactGCSEntry class];
|
||||
else if ([componentName isEqualToString: @"vlist"])
|
||||
@@ -289,38 +294,17 @@ static NSArray *folderListingFields = nil;
|
||||
return records;
|
||||
}
|
||||
|
||||
#warning this should be unified within SOGoFolder
|
||||
- (void) appendObject: (NSDictionary *) object
|
||||
withBaseURL: (NSString *) baseURL
|
||||
toREPORTResponse: (WOResponse *) r
|
||||
- (NSDictionary *) davSQLFieldsTable
|
||||
{
|
||||
SOGoContactGCSEntry *component;
|
||||
NSString *name, *etagLine, *contactString;
|
||||
static NSMutableDictionary *davSQLFieldsTable = nil;
|
||||
|
||||
name = [object objectForKey: @"c_name"];
|
||||
component = [self lookupName: name inContext: context acquire: NO];
|
||||
if (!davSQLFieldsTable)
|
||||
{
|
||||
davSQLFieldsTable = [[super davSQLFieldsTable] mutableCopy];
|
||||
[davSQLFieldsTable setObject: @"c_content" forKey: @"{urn:ietf:params:xml:ns:carddav}address-data"];
|
||||
}
|
||||
|
||||
[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"];
|
||||
return davSQLFieldsTable;
|
||||
}
|
||||
|
||||
- (NSArray *) davComplianceClassesInContext: (id)_ctx
|
||||
@@ -359,6 +343,12 @@ static NSArray *folderListingFields = nil;
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
- (id) davAddressbookMultiget: (id) queryContext
|
||||
{
|
||||
return [self performMultigetInContext: queryContext
|
||||
inNamespace: @"urn:ietf:params:xml:ns:carddav"];
|
||||
}
|
||||
|
||||
/* sorting */
|
||||
- (NSComparisonResult) compare: (id) otherFolder
|
||||
{
|
||||
@@ -385,4 +375,22 @@ static NSArray *folderListingFields = nil;
|
||||
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 */
|
||||
@@ -34,7 +34,6 @@
|
||||
#import <NGObjWeb/SoSelectorInvocation.h>
|
||||
#import <NGObjWeb/SoUser.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <EOControl/EOSortOrdering.h>
|
||||
#import <SaxObjC/XMLNamespaces.h>
|
||||
|
||||
@@ -50,49 +49,6 @@
|
||||
|
||||
@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
|
||||
andDisplayName: (NSString *) aDisplayName
|
||||
inContainer: (id) aContainer
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
#import <SaxObjC/SaxObjC.h>
|
||||
@@ -39,6 +40,50 @@
|
||||
|
||||
@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
|
||||
toResponse: (WOResponse *) response
|
||||
context: (id) localContext
|
||||
@@ -60,9 +105,8 @@
|
||||
objectEnumerator];
|
||||
|
||||
while ((contact = [contacts nextObject]))
|
||||
[(id<SOGoContactFolder>)self appendObject: contact
|
||||
withBaseURL: baseURL
|
||||
toREPORTResponse: response];
|
||||
[self _appendObject: contact withBaseURL: baseURL
|
||||
toREPORTResponse: response];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +187,7 @@
|
||||
[self _appendComponentsMatchingFilters: filters
|
||||
toResponse: r
|
||||
context: queryContext];
|
||||
[r appendContentString:@"</D:multistatus>"];
|
||||
[r appendContentString: @"</D:multistatus>"];
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -722,7 +722,7 @@ static NSString *userAgent = nil;
|
||||
{
|
||||
// TODO: use subject for filename?
|
||||
// error = [newDraft saveAttachment:content withName:@"forward.eml"];
|
||||
signature = [ud mailSignature];
|
||||
signature = [[self mailAccountFolder] signature];
|
||||
if ([signature length])
|
||||
[self setText: [NSString stringWithFormat: @"\n-- \n%@", signature]];
|
||||
attachment = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
|
||||
@@ -50,7 +50,6 @@ typedef enum {
|
||||
|
||||
@interface SOGoMailAccount : SOGoMailBaseObject
|
||||
{
|
||||
NSString *accountName;
|
||||
SOGoMailFolder *inboxFolder;
|
||||
SOGoDraftsFolder *draftsFolder;
|
||||
SOGoSentFolder *sentFolder;
|
||||
@@ -58,14 +57,16 @@ typedef enum {
|
||||
SOGoIMAPAclStyle imapAclStyle;
|
||||
}
|
||||
|
||||
- (void) setAccountName: (NSString *) newAccountName;
|
||||
|
||||
- (SOGoIMAPAclStyle) imapAclStyle;
|
||||
- (BOOL) imapAclConformsToIMAPExt;
|
||||
|
||||
- (BOOL) supportsQuotas;
|
||||
- (BOOL) updateFilters;
|
||||
|
||||
- (NSArray *) identities;
|
||||
- (NSString *) signature;
|
||||
- (NSString *) encryption;
|
||||
|
||||
/* folder pathes */
|
||||
|
||||
- (NSArray *) allFolderPaths;
|
||||
|
||||
+107
-157
@@ -40,6 +40,7 @@
|
||||
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/SOGoAuthenticator.h>
|
||||
#import <SOGo/SOGoDomainDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
@@ -69,7 +70,6 @@ static NSString *sieveScriptName = @"sogo";
|
||||
draftsFolder = nil;
|
||||
sentFolder = nil;
|
||||
trashFolder = nil;
|
||||
accountName = nil;
|
||||
imapAclStyle = undefined;
|
||||
}
|
||||
|
||||
@@ -82,15 +82,9 @@ static NSString *sieveScriptName = @"sogo";
|
||||
[draftsFolder release];
|
||||
[sentFolder release];
|
||||
[trashFolder release];
|
||||
[accountName release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) setAccountName: (NSString *) newAccountName
|
||||
{
|
||||
ASSIGN (accountName, newAccountName);
|
||||
}
|
||||
|
||||
/* listing the available folders */
|
||||
|
||||
- (BOOL) isInDraftsFolder
|
||||
@@ -362,7 +356,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
result = [client login: [[self imap4URL] user] password: password];
|
||||
if (![[result valueForKey:@"result"] boolValue]) {
|
||||
[self errorWithFormat: @"failure. Attempting with a renewed password."];
|
||||
password = [self imap4PasswordRenewed: NO];
|
||||
password = [self imap4PasswordRenewed: YES];
|
||||
result = [client login: [[self imap4URL] user] password: password];
|
||||
}
|
||||
|
||||
@@ -475,76 +469,82 @@ static NSString *sieveScriptName = @"sogo";
|
||||
|
||||
/* IMAP4 */
|
||||
|
||||
- (BOOL) useSSL
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *) imap4LoginFromHTTP
|
||||
{
|
||||
WORequest *rq;
|
||||
NSString *s;
|
||||
NSArray *creds;
|
||||
|
||||
rq = [context request];
|
||||
|
||||
s = [rq headerForKey:@"x-webobjects-remote-user"];
|
||||
if ([s length] > 0)
|
||||
return s;
|
||||
|
||||
if ((s = [rq headerForKey:@"authorization"]) == nil) {
|
||||
/* no basic auth */
|
||||
return nil;
|
||||
}
|
||||
|
||||
creds = [SoHTTPAuthenticator parseCredentials:s];
|
||||
if ([creds count] < 2)
|
||||
/* somehow invalid */
|
||||
return nil;
|
||||
|
||||
return [creds objectAtIndex:0]; /* the user */
|
||||
}
|
||||
|
||||
- (NSString *) _urlHostString
|
||||
- (NSDictionary *) _mailAccount
|
||||
{
|
||||
NSDictionary *mailAccount;
|
||||
NSString *username, *escUsername, *hostString;
|
||||
NSArray *accounts;
|
||||
SOGoUser *user;
|
||||
|
||||
mailAccount = [[context activeUser] accountWithName: accountName];
|
||||
if (mailAccount)
|
||||
{
|
||||
username = [mailAccount objectForKey: @"userName"];
|
||||
escUsername
|
||||
= [[username stringByEscapingURL] stringByReplacingString: @"@"
|
||||
withString: @"%40"];
|
||||
hostString = [NSString stringWithFormat: @"%@@%@", escUsername,
|
||||
[mailAccount objectForKey: @"serverName"]];
|
||||
}
|
||||
user = [SOGoUser userWithLogin: [self ownerInContext: nil]];
|
||||
accounts = [user mailAccounts];
|
||||
mailAccount = [accounts objectAtIndex: [nameInContainer intValue]];
|
||||
|
||||
return mailAccount;
|
||||
}
|
||||
|
||||
- (NSArray *) identities
|
||||
{
|
||||
return [[self _mailAccount] objectForKey: @"identities"];
|
||||
}
|
||||
|
||||
- (NSString *) signature
|
||||
{
|
||||
NSArray *identities;
|
||||
NSString *signature;
|
||||
|
||||
identities = [self identities];
|
||||
if ([identities count] > 0)
|
||||
signature = [[identities objectAtIndex: 0] objectForKey: @"signature"];
|
||||
else
|
||||
hostString = @"localhost";
|
||||
signature = nil;
|
||||
|
||||
return hostString;
|
||||
return signature;
|
||||
}
|
||||
|
||||
- (NSString *) encryption
|
||||
{
|
||||
NSString *encryption;
|
||||
|
||||
encryption = [[self _mailAccount] objectForKey: @"encryption"];
|
||||
if (![encryption length])
|
||||
encryption = @"none";
|
||||
|
||||
return encryption;
|
||||
}
|
||||
|
||||
- (NSMutableString *) imap4URLString
|
||||
{
|
||||
/* private, overridden by SOGoSharedMailAccount */
|
||||
NSMutableString *urlString;
|
||||
NSString *host;
|
||||
NSMutableString *imap4URLString;
|
||||
NSDictionary *mailAccount;
|
||||
NSString *encryption, *protocol, *username, *escUsername;
|
||||
int defaultPort, port;
|
||||
|
||||
urlString = [NSMutableString string];
|
||||
|
||||
if ([self useSSL])
|
||||
[urlString appendString: @"imaps://"];
|
||||
mailAccount = [self _mailAccount];
|
||||
encryption = [mailAccount objectForKey: @"encryption"];
|
||||
if ([encryption isEqualToString: @"ssl"])
|
||||
{
|
||||
protocol = @"imaps";
|
||||
defaultPort = 993;
|
||||
}
|
||||
else
|
||||
[urlString appendString: @"imap://"];
|
||||
{
|
||||
protocol = @"imap";
|
||||
defaultPort = 143;
|
||||
}
|
||||
|
||||
username = [mailAccount objectForKey: @"userName"];
|
||||
escUsername
|
||||
= [[username stringByEscapingURL] stringByReplacingString: @"@"
|
||||
withString: @"%40"];
|
||||
imap4URLString = [NSMutableString stringWithFormat: @"%@://%@@%@",
|
||||
protocol, escUsername,
|
||||
[mailAccount objectForKey: @"serverName"]];
|
||||
port = [[mailAccount objectForKey: @"port"] intValue];
|
||||
if (port && port != defaultPort)
|
||||
[imap4URLString appendFormat: @":%d", port];
|
||||
[imap4URLString appendString: @"/"];
|
||||
|
||||
host = [self _urlHostString];
|
||||
if (![host rangeOfString: @"@"].length)
|
||||
[urlString appendFormat: @"%@@", [self imap4LoginFromHTTP]];
|
||||
[urlString appendFormat: @"%@/", host];
|
||||
|
||||
return urlString;
|
||||
return imap4URLString;
|
||||
}
|
||||
|
||||
- (NSMutableString *) traversalFromMailAccount
|
||||
@@ -552,9 +552,33 @@ static NSString *sieveScriptName = @"sogo";
|
||||
return [NSMutableString string];
|
||||
}
|
||||
|
||||
- (NSString *) imap4Login
|
||||
- (NSString *) imap4PasswordRenewed: (BOOL) renewed
|
||||
{
|
||||
return [[self imap4URL] user];
|
||||
/*
|
||||
Extract password from basic authentication.
|
||||
*/
|
||||
NSURL *imapURL;
|
||||
NSString *password;
|
||||
|
||||
if ([nameInContainer isEqualToString: @"0"])
|
||||
{
|
||||
imapURL = [self imap4URL];
|
||||
|
||||
password = [[self authenticatorInContext: context]
|
||||
imapPasswordInContext: context
|
||||
forServer: [imapURL host]
|
||||
forceRenew: renewed];
|
||||
if (!password)
|
||||
[self errorWithFormat: @"no IMAP4 password available"];
|
||||
}
|
||||
else
|
||||
{
|
||||
password = [[self _mailAccount] objectForKey: @"password"];
|
||||
if (!password)
|
||||
password = @"";
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
/* name lookup */
|
||||
@@ -610,70 +634,27 @@ static NSString *sieveScriptName = @"sogo";
|
||||
return inboxFolderName;
|
||||
}
|
||||
|
||||
- (BOOL) _migrateFolderWithPurpose: (NSString *) purpose
|
||||
withName: (NSString *) folderName
|
||||
{
|
||||
SOGoUserDefaults *ud;
|
||||
NSString *methodName;
|
||||
SEL methodSel;
|
||||
BOOL rc;
|
||||
|
||||
ud = [[context activeUser] userDefaults];
|
||||
methodName = [NSString stringWithFormat: @"set%@FolderName:", purpose];
|
||||
methodSel = NSSelectorFromString (methodName);
|
||||
if ([ud respondsToSelector: methodSel])
|
||||
{
|
||||
[ud performSelector: methodSel withObject: folderName];
|
||||
[ud synchronize];
|
||||
rc = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"method '%@' not available with user defaults"
|
||||
@" object, folder migration fails", methodName];
|
||||
rc = NO;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (NSString *) _userFolderNameWithPurpose: (NSString *) purpose
|
||||
{
|
||||
SOGoUser *user;
|
||||
SOGoUserSettings *us;
|
||||
SOGoUserDefaults *ud;
|
||||
NSMutableDictionary *mailSettings;
|
||||
NSString *folderName, *key, *methodName;
|
||||
SEL methodSel;
|
||||
NSArray *accounts;
|
||||
int accountIdx;
|
||||
NSDictionary *account;
|
||||
NSString *folderName;
|
||||
|
||||
folderName = nil;
|
||||
|
||||
user = [context activeUser];
|
||||
/* migration part: */
|
||||
us = [user userSettings];
|
||||
mailSettings = [us objectForKey: @"Mail"];
|
||||
if (mailSettings)
|
||||
user = [SOGoUser userWithLogin: [self ownerInContext: nil]];
|
||||
accounts = [user mailAccounts];
|
||||
accountIdx = [nameInContainer intValue];
|
||||
account = [accounts objectAtIndex: accountIdx];
|
||||
folderName = [[account objectForKey: @"mailboxes"]
|
||||
objectForKey: purpose];
|
||||
if (!folderName && accountIdx > 0)
|
||||
{
|
||||
key = [NSString stringWithFormat: @"%@Folder", purpose];
|
||||
folderName = [mailSettings objectForKey: key];
|
||||
if ([folderName length]
|
||||
&& [self _migrateFolderWithPurpose: purpose withName: folderName])
|
||||
{
|
||||
[mailSettings removeObjectForKey: key];
|
||||
[us synchronize];
|
||||
folderName = nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
folderName = nil;
|
||||
|
||||
if (!folderName)
|
||||
{
|
||||
ud = [[context activeUser] userDefaults];
|
||||
methodName = [NSString stringWithFormat: @"%@FolderName",
|
||||
[purpose lowercaseString]];
|
||||
methodSel = NSSelectorFromString (methodName);
|
||||
folderName = [ud performSelector: methodSel];
|
||||
account = [accounts objectAtIndex: 0];
|
||||
folderName = [[account objectForKey: @"mailboxes"]
|
||||
objectForKey: purpose];
|
||||
}
|
||||
|
||||
return folderName;
|
||||
@@ -800,40 +781,9 @@ static NSString *sieveScriptName = @"sogo";
|
||||
return [[self imap4Connection] createMailbox:_name atURL:[self imap4URL]];
|
||||
}
|
||||
|
||||
- (NSString *) shortTitle
|
||||
{
|
||||
NSString *login, *host;
|
||||
NSRange r;
|
||||
|
||||
r = [accountName rangeOfString:@"@"];
|
||||
if (r.length > 0)
|
||||
{
|
||||
login = [accountName substringToIndex:r.location];
|
||||
host = [accountName substringFromIndex:(r.location + r.length)];
|
||||
}
|
||||
else
|
||||
{
|
||||
login = nil;
|
||||
host = accountName;
|
||||
}
|
||||
|
||||
r = [host rangeOfString:@"."];
|
||||
if (r.length > 0)
|
||||
host = [host substringToIndex:r.location];
|
||||
|
||||
if ([login length] == 0)
|
||||
return host;
|
||||
|
||||
r = [login rangeOfString:@"."];
|
||||
if (r.length > 0)
|
||||
login = [login substringToIndex:r.location];
|
||||
|
||||
return [NSString stringWithFormat:@"%@@%@", login, host];
|
||||
}
|
||||
|
||||
- (NSString *) davDisplayName
|
||||
{
|
||||
return [self shortTitle];
|
||||
return [[self _mailAccount] objectForKey: @"name"];
|
||||
}
|
||||
|
||||
@end /* SOGoMailAccount */
|
||||
@@ -41,12 +41,10 @@
|
||||
@class NSMutableDictionary;
|
||||
|
||||
@interface SOGoMailAccounts : SOGoFolder
|
||||
{
|
||||
NSMutableDictionary *accountKeys;
|
||||
}
|
||||
|
||||
- (NSArray *) mailAccounts;
|
||||
|
||||
- (NSArray *) toManyRelationshipKeys;
|
||||
- (NSDictionary *) accountKeys;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -36,113 +36,55 @@
|
||||
|
||||
@implementation SOGoMailAccounts
|
||||
|
||||
/* listing the available mailboxes */
|
||||
|
||||
// - (BOOL) isInHomeFolderBranchOfLoggedInAccount: (NSString *) userLogin
|
||||
// {
|
||||
// return [[container nameInContainer] isEqualToString: userLogin];
|
||||
// }
|
||||
|
||||
- (id) init
|
||||
- (NSArray *) mailAccounts
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
accountKeys = nil;
|
||||
}
|
||||
SOGoUser *user;
|
||||
|
||||
user = [SOGoUser userWithLogin: [self ownerInContext: nil]];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[accountKeys release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) _initAccountKeys
|
||||
{
|
||||
NSArray *accounts;
|
||||
NSString *currentName;
|
||||
int count, max;
|
||||
|
||||
if (!accountKeys)
|
||||
{
|
||||
accountKeys = [NSMutableDictionary new];
|
||||
|
||||
accounts = [[context activeUser] mailAccounts];
|
||||
max = [accounts count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
currentName = [[accounts objectAtIndex: count] objectForKey: @"name"];
|
||||
[accountKeys setObject: currentName
|
||||
forKey: [currentName asCSSIdentifier]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *) accountKeys
|
||||
{
|
||||
[self _initAccountKeys];
|
||||
|
||||
return accountKeys;
|
||||
return [user mailAccounts];
|
||||
}
|
||||
|
||||
- (NSArray *) toManyRelationshipKeys
|
||||
{
|
||||
[self _initAccountKeys];
|
||||
NSMutableArray *keys;
|
||||
NSArray *accounts;
|
||||
int count, max;
|
||||
SOGoUser *user;
|
||||
|
||||
user = [SOGoUser userWithLogin: [self ownerInContext: nil]];
|
||||
accounts = [user mailAccounts];
|
||||
max = [accounts count];
|
||||
|
||||
return [accountKeys allKeys];
|
||||
keys = [NSMutableArray arrayWithCapacity: max];
|
||||
for (count = 0; count < max; count++)
|
||||
[keys addObject: [NSString stringWithFormat: @"%d", count]];
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/* name lookup */
|
||||
|
||||
// - (id) mailAccountWithName: (NSString *) _key
|
||||
// inContext: (id) _ctx
|
||||
// {
|
||||
// static Class ctClass = Nil;
|
||||
// id ct;
|
||||
|
||||
// if (ctClass == Nil)
|
||||
// ctClass = NSClassFromString(@"SOGoMailAccount");
|
||||
// if (ctClass == Nil) {
|
||||
// [self errorWithFormat:@"missing SOGoMailAccount class!"];
|
||||
// return nil;
|
||||
// }
|
||||
|
||||
// ct = [[ctClass alloc] initWithName:_key inContainer:self];
|
||||
|
||||
// return [ct autorelease];
|
||||
// }
|
||||
|
||||
- (id) lookupName: (NSString *) _key
|
||||
inContext: (id) _ctx
|
||||
acquire: (BOOL) _flag
|
||||
{
|
||||
id obj;
|
||||
NSString *accountName;
|
||||
// NSString *userLogin;
|
||||
|
||||
// userLogin = [[context activeUser] login];
|
||||
NSArray *accounts;
|
||||
SOGoUser *user;
|
||||
int keyCount;
|
||||
|
||||
// if (![self isInHomeFolderBranchOfLoggedInAccount: userLogin]) {
|
||||
// [self warnWithFormat:@ "User %@ tried to access mail hierarchy of %@",
|
||||
// userLogin, [container nameInContainer]];
|
||||
|
||||
// return [NSException exceptionWithHTTPStatus:403 /* Forbidden */
|
||||
// reason:@"Tried to access the mail of another user"];
|
||||
// }
|
||||
|
||||
/* first check attributes directly bound to the application */
|
||||
obj = [super lookupName:_key inContext:_ctx acquire:NO];
|
||||
if (!obj)
|
||||
{
|
||||
[self _initAccountKeys];
|
||||
accountName = [accountKeys objectForKey: _key];
|
||||
if ([accountName length])
|
||||
{
|
||||
obj = [SOGoMailAccount objectWithName: _key inContainer: self];
|
||||
[obj setAccountName: accountName];
|
||||
}
|
||||
user = [SOGoUser userWithLogin: [self ownerInContext: nil]];
|
||||
accounts = [user mailAccounts];
|
||||
|
||||
keyCount = [_key intValue];
|
||||
if ([_key isEqualToString: [NSString stringWithFormat: @"%d", keyCount]]
|
||||
&& keyCount > -1 && keyCount < [accounts count])
|
||||
obj = [SOGoMailAccount objectWithName: _key inContainer: self];
|
||||
else
|
||||
obj = [NSException exceptionWithHTTPStatus: 404 /* Not Found */];
|
||||
}
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
- (NSMutableString *) traversalFromMailAccount;
|
||||
|
||||
- (NSURL *) imap4URL;
|
||||
- (NSString *) imap4Login;
|
||||
- (NSString *) imap4PasswordRenewed: (BOOL) renew;
|
||||
|
||||
- (void) flushMailCaches;
|
||||
|
||||
@@ -30,8 +30,7 @@
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGExtensions/NSURL+misc.h>
|
||||
|
||||
#import <SOGo/SOGoAuthenticator.h>
|
||||
|
||||
#import "SOGoMailAccount.h"
|
||||
#import "SOGoMailManager.h"
|
||||
|
||||
#import "SOGoMailBaseObject.h"
|
||||
@@ -187,44 +186,28 @@ static BOOL debugOn = YES;
|
||||
|
||||
- (NSURL *) imap4URL
|
||||
{
|
||||
SOGoMailAccount *account;
|
||||
NSString *urlString;
|
||||
|
||||
/* this could probably be handled better from NSURL but it's buggy in
|
||||
GNUstep */
|
||||
if (!imap4URL)
|
||||
imap4URL = [[NSURL alloc] initWithString: [self imap4URLString]];
|
||||
{
|
||||
account = [self mailAccountFolder];
|
||||
if ([[account encryption] isEqualToString: @"tls"])
|
||||
urlString = [NSString stringWithFormat: @"%@?tls=YES",
|
||||
[self imap4URLString]];
|
||||
else
|
||||
urlString = [self imap4URLString];
|
||||
imap4URL = [[NSURL alloc] initWithString: urlString];
|
||||
}
|
||||
|
||||
return imap4URL;
|
||||
}
|
||||
|
||||
- (NSString *) imap4Login
|
||||
{
|
||||
if (![container respondsToSelector:_cmd])
|
||||
return nil;
|
||||
|
||||
return [container imap4Login];
|
||||
}
|
||||
|
||||
- (NSString *) imap4PasswordRenewed: (BOOL) renewed
|
||||
{
|
||||
/*
|
||||
Extract password from basic authentication.
|
||||
|
||||
TODO: we might want to
|
||||
a) move the primary code to SOGoMailAccount
|
||||
b) cache the password
|
||||
*/
|
||||
NSURL *imapURL;
|
||||
NSString *password;
|
||||
|
||||
imapURL = [[self mailAccountFolder] imap4URL];
|
||||
|
||||
password = [[self authenticatorInContext: context]
|
||||
imapPasswordInContext: context
|
||||
forServer: [imapURL host]
|
||||
forceRenew: renewed];
|
||||
if (!password)
|
||||
[self errorWithFormat: @"no IMAP4 password available"];
|
||||
|
||||
return password;
|
||||
return [[self mailAccountFolder] imap4PasswordRenewed: renewed];
|
||||
}
|
||||
|
||||
- (NSMutableString *) traversalFromMailAccount
|
||||
|
||||
@@ -447,7 +447,7 @@ static NSString *defaultUserID = @"anyone";
|
||||
inContext: (id) localContext
|
||||
{
|
||||
NSArray *folders;
|
||||
NSString *currentFolderName;
|
||||
NSString *currentFolderName, *currentAccountName;
|
||||
NSMutableString *imapDestinationFolder;
|
||||
NGImap4Client *client;
|
||||
id result;
|
||||
@@ -458,31 +458,45 @@ static NSString *defaultUserID = @"anyone";
|
||||
folders = [[destinationFolder componentsSeparatedByString: @"/"]
|
||||
resultsOfSelector: @selector (fromCSSIdentifier)];
|
||||
max = [folders count];
|
||||
for (count = 2; count < max; count++)
|
||||
if (max > 1)
|
||||
{
|
||||
currentFolderName
|
||||
= [[folders objectAtIndex: count] substringFromIndex: 6];
|
||||
[imapDestinationFolder appendFormat: @"/%@", currentFolderName];
|
||||
currentAccountName = [[self mailAccountFolder] nameInContainer];
|
||||
if ([[folders objectAtIndex: 1] isEqualToString: currentAccountName])
|
||||
{
|
||||
for (count = 2; count < max; count++)
|
||||
{
|
||||
currentFolderName
|
||||
= [[folders objectAtIndex: count] substringFromIndex: 6];
|
||||
[imapDestinationFolder appendFormat: @"/%@", currentFolderName];
|
||||
}
|
||||
|
||||
client = [[self imap4Connection] client];
|
||||
[imap4 selectFolder: [self imap4URL]];
|
||||
|
||||
// We make sure the destination IMAP folder exist, if not, we create it.
|
||||
result = [[client status: imapDestinationFolder
|
||||
flags: [NSArray arrayWithObject: @"UIDVALIDITY"]]
|
||||
objectForKey: @"result"];
|
||||
if (![result boolValue])
|
||||
result = [[self imap4Connection] createMailbox: imapDestinationFolder
|
||||
atURL: [[self mailAccountFolder] imap4URL]];
|
||||
if (!result || [result boolValue])
|
||||
result = [client copyUids: uids toFolder: imapDestinationFolder];
|
||||
|
||||
if ([[result valueForKey: @"result"] boolValue])
|
||||
result = nil;
|
||||
else
|
||||
result = [NSException exceptionWithHTTPStatus: 500
|
||||
reason: @"Couldn't copy UIDs."];
|
||||
}
|
||||
else
|
||||
result = [NSException exceptionWithHTTPStatus: 500
|
||||
reason: @"Cannot copy messages across different accounts."];
|
||||
}
|
||||
|
||||
client = [[self imap4Connection] client];
|
||||
[imap4 selectFolder: [self imap4URL]];
|
||||
|
||||
// We make sure the destination IMAP folder exist, if not, we create it.
|
||||
result = [[client status: imapDestinationFolder
|
||||
flags: [NSArray arrayWithObject: @"UIDVALIDITY"]]
|
||||
objectForKey: @"result"];
|
||||
if (![result boolValue])
|
||||
result = [[self imap4Connection] createMailbox: imapDestinationFolder
|
||||
atURL: [[self mailAccountFolder] imap4URL]];
|
||||
if (!result || [result boolValue])
|
||||
result = [client copyUids: uids toFolder: imapDestinationFolder];
|
||||
|
||||
if ([[result valueForKey: @"result"] boolValue])
|
||||
result = nil;
|
||||
else
|
||||
result = [NSException exceptionWithHTTPStatus: 500 reason: @"Couldn't copy UIDs."];
|
||||
|
||||
result = [NSException exceptionWithHTTPStatus: 500
|
||||
reason: @"Invalid destination."];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1061,9 +1075,8 @@ static NSString *defaultUserID = @"anyone";
|
||||
{
|
||||
thisAccount = [self mailAccountFolder];
|
||||
mailAccount = [[user mailAccounts] objectAtIndex: 0];
|
||||
url = [NSString stringWithFormat: @"%@/%@%@",
|
||||
url = [NSString stringWithFormat: @"%@/0%@",
|
||||
[self soURLToBaseContainerForUser: uid],
|
||||
[mailAccount objectForKey: @"name"],
|
||||
otherUsersPath];
|
||||
}
|
||||
else
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
|
||||
#import "SOGoMailAccount.h"
|
||||
#import "SOGoMailObject+Draft.h"
|
||||
#import "SOGoMailForward.h"
|
||||
|
||||
@@ -221,7 +222,7 @@
|
||||
SOGoUserDefaults *ud;
|
||||
|
||||
ud = [[context activeUser] userDefaults];
|
||||
signature = [ud mailSignature];
|
||||
signature = [[sourceMail mailAccountFolder] signature];
|
||||
if ([signature length])
|
||||
mailSignature = [NSString stringWithFormat: @"-- \n%@", signature];
|
||||
else
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifndef S_GO_SOOBJECTS_SOGO_DOMNODE_SOGO_H
|
||||
#define S_GO_SOOBJECTS_SOGO_DOMNODE_SOGO_H
|
||||
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMNode.h>
|
||||
|
||||
@class DOMElement;
|
||||
|
||||
@@ -28,8 +28,15 @@
|
||||
|
||||
- (NSString *) jsonRepresentation
|
||||
{
|
||||
NSString *jsonRepresentation;
|
||||
|
||||
return [NSString stringWithFormat: @"%@", self];
|
||||
jsonRepresentation = [NSString stringWithFormat: @"%@", self];
|
||||
if ([jsonRepresentation isEqualToString: @"YES"])
|
||||
jsonRepresentation = @"true";
|
||||
else if ([jsonRepresentation isEqualToString: @"NO"])
|
||||
jsonRepresentation = @"false";
|
||||
|
||||
return jsonRepresentation;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -37,6 +37,8 @@
|
||||
|
||||
- (NSArray *) userSources;
|
||||
|
||||
- (BOOL) mailAuxiliaryUserAccountsEnabled;
|
||||
|
||||
- (NSString *) mailDomain;
|
||||
- (NSString *) imapServer;
|
||||
- (NSString *) imapAclStyle;
|
||||
@@ -60,6 +62,7 @@
|
||||
- (NSArray *) calendarDefaultRoles;
|
||||
- (NSArray *) contactsDefaultRoles;
|
||||
- (NSArray *) mailPollingIntervals;
|
||||
- (BOOL) mailCheckAllUnseenCounts;
|
||||
|
||||
- (NSString *) calendarDefaultCategoryColor;
|
||||
|
||||
|
||||
@@ -98,6 +98,11 @@
|
||||
return [self stringForKey: @"OCSFolderInfoURL"];
|
||||
}
|
||||
|
||||
- (BOOL) mailAuxiliaryUserAccountsEnabled
|
||||
{
|
||||
return [self boolForKey: @"SOGoMailAuxiliaryUserAccountsEnabled"];
|
||||
}
|
||||
|
||||
- (NSString *) mailDomain
|
||||
{
|
||||
return [self stringForKey: @"SOGoMailDomain"];
|
||||
@@ -193,6 +198,11 @@
|
||||
return [self arrayForKey: @"SOGoMailPollingIntervals"];
|
||||
}
|
||||
|
||||
- (BOOL) mailCheckAllUnseenCounts
|
||||
{
|
||||
return [self boolForKey: @"SOGoMailCheckAllUnseenCounts"];
|
||||
}
|
||||
|
||||
- (NSString *) smtpServer
|
||||
{
|
||||
return [self stringForKey: @"SOGoSMTPServer"];
|
||||
|
||||
@@ -121,6 +121,10 @@
|
||||
|
||||
- (NSString *) davCollectionTag;
|
||||
|
||||
/* multiget helper */
|
||||
- (WOResponse *) performMultigetInContext: (WOContext *) queryContext
|
||||
inNamespace: (NSString *) namespace;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __SOGo_SOGoGCSFolder_H__ */
|
||||
@@ -1685,4 +1685,392 @@ static NSArray *childRecordFields = nil;
|
||||
[_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 */
|
||||
@@ -40,7 +40,6 @@
|
||||
@class NSMutableArray;
|
||||
@class NSMutableDictionary;
|
||||
@class NSString;
|
||||
@class NSURL;
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@@ -69,7 +68,7 @@
|
||||
NSString *domainId;
|
||||
NSString *language;
|
||||
NSArray *allEmails;
|
||||
NSArray *mailAccounts;
|
||||
NSMutableArray *mailAccounts;
|
||||
NSString *cn;
|
||||
BOOL propagateCache;
|
||||
}
|
||||
|
||||
+130
-114
@@ -436,53 +436,145 @@
|
||||
}
|
||||
|
||||
/* mail */
|
||||
- (NSArray *) mailAccounts
|
||||
- (BOOL) _migrateFolderWithPurpose: (NSString *) purpose
|
||||
withName: (NSString *) folderName
|
||||
{
|
||||
NSMutableDictionary *mailAccount, *identity;
|
||||
NSString *methodName;
|
||||
SEL methodSel;
|
||||
BOOL rc;
|
||||
|
||||
[self userDefaults];
|
||||
methodName = [NSString stringWithFormat: @"set%@FolderName:", purpose];
|
||||
methodSel = NSSelectorFromString (methodName);
|
||||
if ([_defaults respondsToSelector: methodSel])
|
||||
{
|
||||
[_defaults performSelector: methodSel withObject: folderName];
|
||||
rc = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"method '%@' not available with user defaults"
|
||||
@" object, folder migration fails", methodName];
|
||||
rc = NO;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (void) _migrateFolderSettings
|
||||
{
|
||||
NSMutableDictionary *mailSettings;
|
||||
NSString *folderName, *key;
|
||||
BOOL migrated;
|
||||
NSString **purpose;
|
||||
NSString *purposes[] = { @"Drafts", @"Sent", @"Trash", nil };
|
||||
|
||||
[self userSettings];
|
||||
mailSettings = [_settings objectForKey: @"Mail"];
|
||||
if (mailSettings)
|
||||
{
|
||||
migrated = NO;
|
||||
purpose = purposes;
|
||||
while (*purpose)
|
||||
{
|
||||
key = [NSString stringWithFormat: @"%@Folder", *purpose];
|
||||
folderName = [mailSettings objectForKey: key];
|
||||
if ([folderName length]
|
||||
&& [self _migrateFolderWithPurpose: *purpose
|
||||
withName: folderName])
|
||||
{
|
||||
migrated = YES;
|
||||
[mailSettings removeObjectForKey: key];
|
||||
folderName = nil;
|
||||
}
|
||||
purpose++;
|
||||
}
|
||||
if (migrated)
|
||||
{
|
||||
[_settings synchronize];
|
||||
[self userDefaults];
|
||||
[_defaults synchronize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _appendSystemMailAccount
|
||||
{
|
||||
NSMutableDictionary *mailAccount, *identity, *mailboxes;
|
||||
NSMutableArray *identities;
|
||||
NSString *fullName, *imapLogin, *imapServer;
|
||||
NSString *fullName, *imapLogin, *imapServer, *signature;
|
||||
NSArray *mails;
|
||||
unsigned int count, max;
|
||||
|
||||
mailAccount = [NSMutableDictionary new];
|
||||
|
||||
imapLogin = [[SOGoUserManager sharedUserManager]
|
||||
getImapLoginForUID: login];
|
||||
imapServer = [self _fetchFieldForUser: @"c_imaphostname"];
|
||||
if (!imapServer)
|
||||
imapServer = [[self domainDefaults] imapServer];
|
||||
|
||||
[mailAccount setObject: imapLogin forKey: @"userName"];
|
||||
[mailAccount setObject: imapServer forKey: @"serverName"];
|
||||
|
||||
identities = [NSMutableArray new];
|
||||
mails = [self allEmails];
|
||||
[mailAccount setObject: [mails objectAtIndex: 0] forKey: @"name"];
|
||||
|
||||
max = [mails count];
|
||||
if (max > 1)
|
||||
max--;
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
identity = [NSMutableDictionary new];
|
||||
fullName = [self cn];
|
||||
if (![fullName length])
|
||||
fullName = login;
|
||||
[identity setObject: fullName forKey: @"fullName"];
|
||||
[identity setObject: [mails objectAtIndex: count] forKey: @"email"];
|
||||
signature = [[self userDefaults] mailSignature];
|
||||
if (signature)
|
||||
[identity setObject: signature forKey: @"signature"];
|
||||
[identities addObject: identity];
|
||||
[identity release];
|
||||
}
|
||||
[[identities objectAtIndex: 0] setObject: [NSNumber numberWithBool: YES]
|
||||
forKey: @"isDefault"];
|
||||
|
||||
[mailAccount setObject: identities forKey: @"identities"];
|
||||
[identities release];
|
||||
|
||||
mailboxes = [NSMutableDictionary new];
|
||||
|
||||
[self userDefaults];
|
||||
[self _migrateFolderSettings];
|
||||
[mailboxes setObject: [_defaults draftsFolderName]
|
||||
forKey: @"Drafts"];
|
||||
[mailboxes setObject: [_defaults sentFolderName]
|
||||
forKey: @"Sent"];
|
||||
[mailboxes setObject: [_defaults trashFolderName]
|
||||
forKey: @"Trash"];
|
||||
[mailAccount setObject: mailboxes forKey: @"mailboxes"];
|
||||
[mailboxes release];
|
||||
|
||||
[mailAccounts addObject: mailAccount];
|
||||
[mailAccount release];
|
||||
}
|
||||
|
||||
- (NSArray *) mailAccounts
|
||||
{
|
||||
NSArray *auxAccounts;
|
||||
|
||||
if (!mailAccounts)
|
||||
{
|
||||
imapLogin = [[SOGoUserManager sharedUserManager]
|
||||
getImapLoginForUID: login];
|
||||
imapServer = [self _fetchFieldForUser: @"c_imaphostname"];
|
||||
if (!imapServer)
|
||||
imapServer = [[self domainDefaults] imapServer];
|
||||
mailAccount = [NSMutableDictionary new];
|
||||
[mailAccount setObject: imapLogin forKey: @"userName"];
|
||||
[mailAccount setObject: imapServer forKey: @"serverName"];
|
||||
|
||||
identities = [NSMutableArray new];
|
||||
mails = [self allEmails];
|
||||
[mailAccount setObject: [mails objectAtIndex: 0]
|
||||
forKey: @"name"];
|
||||
|
||||
max = [mails count];
|
||||
if (max > 1)
|
||||
max--;
|
||||
for (count = 0; count < max; count++)
|
||||
mailAccounts = [NSMutableArray new];
|
||||
[self _appendSystemMailAccount];
|
||||
if ([[self domainDefaults] mailAuxiliaryUserAccountsEnabled])
|
||||
{
|
||||
identity = [NSMutableDictionary new];
|
||||
fullName = [self cn];
|
||||
if (![fullName length])
|
||||
fullName = login;
|
||||
[identity setObject: fullName forKey: @"fullName"];
|
||||
[identity setObject: [mails objectAtIndex: count] forKey: @"email"];
|
||||
[identities addObject: identity];
|
||||
[identity release];
|
||||
auxAccounts = [[self userDefaults] auxiliaryMailAccounts];
|
||||
if (auxAccounts)
|
||||
[mailAccounts addObjectsFromArray: auxAccounts];
|
||||
}
|
||||
[[identities objectAtIndex: 0] setObject: [NSNumber numberWithBool: YES]
|
||||
forKey: @"isDefault"];
|
||||
|
||||
[mailAccount setObject: identities forKey: @"identities"];
|
||||
[identities release];
|
||||
|
||||
mailAccounts = [NSArray arrayWithObject: mailAccount];
|
||||
[mailAccounts retain];
|
||||
[mailAccount release];
|
||||
}
|
||||
|
||||
return mailAccounts;
|
||||
@@ -505,60 +597,6 @@
|
||||
return mailAccount;
|
||||
}
|
||||
|
||||
/*
|
||||
@interface SOGoMailIdentity : NSObject
|
||||
{
|
||||
NSString *name;
|
||||
NSString *email;
|
||||
NSString *replyTo;
|
||||
NSString *organization;
|
||||
NSString *signature;
|
||||
NSString *vCard;
|
||||
NSString *sentFolderName;
|
||||
NSString *sentBCC;
|
||||
NSString *draftsFolderName;
|
||||
NSString *templatesFolderName;
|
||||
struct
|
||||
{
|
||||
int composeHTML:1;
|
||||
int reserved:31;
|
||||
} idFlags;
|
||||
}
|
||||
|
||||
- (void) setName: (NSString *) _value;
|
||||
- (NSString *) name;
|
||||
|
||||
- (void) setEmail: (NSString *) _value;
|
||||
- (NSString *) email;
|
||||
|
||||
- (void) setReplyTo: (NSString *) _value;
|
||||
- (NSString *) replyTo;
|
||||
|
||||
- (void) setOrganization: (NSString *) _value;
|
||||
- (NSString *) organization;
|
||||
|
||||
- (void) setSignature: (NSString *) _value;
|
||||
- (NSString *) signature;
|
||||
- (BOOL) hasSignature;
|
||||
|
||||
- (void) setVCard: (NSString *) _value;
|
||||
- (NSString *) vCard;
|
||||
- (BOOL) hasVCard;
|
||||
|
||||
- (void) setSentFolderName: (NSString *) _value;
|
||||
- (NSString *) sentFolderName;
|
||||
|
||||
- (void) setSentBCC: (NSString *) _value;
|
||||
- (NSString *) sentBCC;
|
||||
|
||||
- (void) setDraftsFolderName: (NSString *) _value;
|
||||
- (NSString *) draftsFolderName;
|
||||
|
||||
- (void) setTemplatesFolderName: (NSString *) _value;
|
||||
- (NSString *) templatesFolderName;
|
||||
|
||||
@end */
|
||||
|
||||
- (NSArray *) allIdentities
|
||||
{
|
||||
NSArray *identities;
|
||||
@@ -603,28 +641,6 @@
|
||||
ignoringRights: YES];
|
||||
}
|
||||
|
||||
// - (id) schedulingCalendarInContext: (id) _ctx
|
||||
// {
|
||||
// /* Note: watch out for cyclic references */
|
||||
// id folder;
|
||||
|
||||
// folder = [(WOContext *)_ctx objectForKey:@"ActiveUserCalendar"];
|
||||
// if (folder != nil)
|
||||
// return [folder isNotNull] ? folder : nil;
|
||||
|
||||
// folder = [self homeFolderInContext:_ctx];
|
||||
// if ([folder isKindOfClass:[NSException class]])
|
||||
// return folder;
|
||||
|
||||
// folder = [folder lookupName:@"Calendar" inContext:_ctx acquire:NO];
|
||||
// if ([folder isKindOfClass:[NSException class]])
|
||||
// return folder;
|
||||
|
||||
// [(WOContext *)_ctx setObject:folder ? folder : [NSNull null]
|
||||
// forKey:@"ActiveUserCalendar"];
|
||||
// return folder;
|
||||
// }
|
||||
|
||||
- (NSArray *) rolesForObject: (NSObject *) object
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
|
||||
@@ -122,6 +122,9 @@ extern NSString *SOGoWeekStartFirstFullWeek;
|
||||
- (void) setMailUseOutlookStyleReplies: (BOOL) newValue;
|
||||
- (BOOL) mailUseOutlookStyleReplies;
|
||||
|
||||
- (void) setAuxiliaryMailAccounts: (NSArray *) newAccounts;
|
||||
- (NSArray *) auxiliaryMailAccounts;
|
||||
|
||||
- (void) setCalendarCategories: (NSArray *) newValues;
|
||||
- (NSArray *) calendarCategories;
|
||||
|
||||
|
||||
@@ -511,6 +511,16 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek";
|
||||
return [self boolForKey: @"SOGoMailUseOutlookStyleReplies"];
|
||||
}
|
||||
|
||||
- (void) setAuxiliaryMailAccounts: (NSArray *) newAccounts
|
||||
{
|
||||
[self setObject: newAccounts forKey: @"AuxiliaryMailAccounts"];
|
||||
}
|
||||
|
||||
- (NSArray *) auxiliaryMailAccounts
|
||||
{
|
||||
return [self arrayForKey: @"AuxiliaryMailAccounts"];
|
||||
}
|
||||
|
||||
- (void) setCalendarCategories: (NSArray *) newValues
|
||||
{
|
||||
[self setObject: newValues forKey: @"SOGoCalendarCategories"];
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#include "SOGoSource.h"
|
||||
#import "SOGoSource.h"
|
||||
|
||||
@class NSArray;
|
||||
@class NSDictionary;
|
||||
|
||||
@@ -20,6 +20,12 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 1
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
@@ -35,14 +41,9 @@
|
||||
#import <GDLAccess/EOAdaptorContext.h>
|
||||
#import <GDLAccess/EOAttribute.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#import "SOGoConstants.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
#include "SQLSource.h"
|
||||
|
||||
#include "SOGoConstants.h"
|
||||
#import "SQLSource.h"
|
||||
|
||||
/**
|
||||
* The view MUST contain the following columns:
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
- (BOOL) isIPhone;
|
||||
- (BOOL) isICal;
|
||||
- (BOOL) isICal4;
|
||||
- (BOOL) isAddressBookApp;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -137,4 +137,14 @@
|
||||
return [self isAppleDAVWithSubstring: @"iCal/4."];
|
||||
}
|
||||
|
||||
- (BOOL) isAddressBookApp
|
||||
{
|
||||
WEClientCapabilities *cc;
|
||||
|
||||
cc = [self clientCapabilities];
|
||||
|
||||
return ([[cc userAgent] rangeOfString: @"CFNetwork"].location != NSNotFound
|
||||
&& [[cc userAgent] rangeOfString: @"Darwin"].location != NSNotFound);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in new issue
Block a user