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:
Ludovic Marcotte committed 2010-08-17 14:10:30 +00:00
commit 3945cc6438
97 files changed
+3642 -1968

No files matched your search

+13 -373
View File
@@ -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
-4
View File
@@ -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;
+13
View File
@@ -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
+5
View File
@@ -115,6 +115,11 @@
return @"text/x-vcard";
}
- (NSString *) davAddressData
{
return [self contentAsString];
}
/* specialized actions */
- (void) save
+39 -31
View File
@@ -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
+48 -4
View File
@@ -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;
}
+1 -1
View File
@@ -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:
+4 -3
View File
@@ -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
View File
@@ -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 */
+2 -4
View File
@@ -41,12 +41,10 @@
@class NSMutableDictionary;
@interface SOGoMailAccounts : SOGoFolder
{
NSMutableDictionary *accountKeys;
}
- (NSArray *) mailAccounts;
- (NSArray *) toManyRelationshipKeys;
- (NSDictionary *) accountKeys;
@end
+28 -86
View File
@@ -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 */];
}
-1
View File
@@ -69,7 +69,6 @@
- (NSMutableString *) traversalFromMailAccount;
- (NSURL *) imap4URL;
- (NSString *) imap4Login;
- (NSString *) imap4PasswordRenewed: (BOOL) renew;
- (void) flushMailCaches;
+14 -31
View File
@@ -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
+38 -25
View File
@@ -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
+2 -1
View File
@@ -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
+1
View File
@@ -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;
+8 -1
View File
@@ -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
+3
View File
@@ -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;
+10
View File
@@ -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"];
+4
View File
@@ -121,6 +121,10 @@
- (NSString *) davCollectionTag;
/* multiget helper */
- (WOResponse *) performMultigetInContext: (WOContext *) queryContext
inNamespace: (NSString *) namespace;
@end
#endif /* __SOGo_SOGoGCSFolder_H__ */
+388
View File
@@ -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 */
+1 -2
View File
@@ -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
View File
@@ -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
{
+3
View File
@@ -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;
+10
View File
@@ -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"];
+1 -1
View File
@@ -25,7 +25,7 @@
#import <Foundation/NSObject.h>
#include "SOGoSource.h"
#import "SOGoSource.h"
@class NSArray;
@class NSDictionary;
+8 -7
View File
@@ -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:
+1
View File
@@ -34,6 +34,7 @@
- (BOOL) isIPhone;
- (BOOL) isICal;
- (BOOL) isICal4;
- (BOOL) isAddressBookApp;
@end
+10
View File
@@ -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