Monotone-Parent: d320625490d77dd599853dd7e1b39027126c15f5

Monotone-Revision: c4392a8d8578caf8d80806e5cb77d1c4ee24ccd7

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2007-12-04T23:28:52
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau
2007-12-04 23:28:52 +00:00
parent c1fe6f14bb
commit 1435638871
6 changed files with 363 additions and 4 deletions
+29
View File
@@ -1,3 +1,32 @@
2007-12-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/Appointments/SOGoAppointmentFolder.m
([SOGoAppointmentFolder -davCalendarQuery:queryContext]): fixed a leak.
* SoObjects/SOGo/SOGoGCSFolder.m ([SOGoGCSFolder -davSubscribe:localContext])
([SOGoGCSFolder -davUnsubscribe:localContext]): subscribe an
unsubscribe from DAV-based accesses. We could be compatible with
Microsoft's extensions but we have no need for a "subcription id",
so we implement our own.
* SoObjects/SOGo/SOGoObject.m ([SOGoObject
-POSTAction:localContext]): new method to intercept DAV POSTs,
which we now use to implement certain custom commands such as
"subscribe" and "unsubscribe".
* SoObjects/SOGo/SOGoUserFolder.m ([SOGoUserFolder
-davNamespaces]): declare the
"urn:inverse:params:xml:ns:inverse-dav" xml ns.
([SOGoUserFolder -foldersOfType:folderTypeforUID:uid]): new method
designed to replace the UIxContactFoldersView.m mechanism for
displaying folders to subcribe to, as a common code base for both
Web and DAV-based subscriptions.
([SOGoUserFolder -foldersOfType:typematchingUID:uid]): same as
above.
([SOGoUserFolder -davCollectionQuery:queryContext]): new method
that implement a custom DAV-based protocol query for querying
folder based on specified attributes.
2007-12-03 Ludovic Marcotte <ludovic@inverse.ca>
* Main/NSException+Stacktrace.{h,m} - new files
@@ -238,8 +238,7 @@ static NSNumber *sharedYes = nil;
NSMutableArray *filters;
NSDictionary *filter;
filters = [NSMutableArray new];
filters = [NSMutableArray array];
children = [[parentNode getElementsByTagName: @"comp-filter"]
objectEnumerator];
node = [children nextObject];
@@ -268,8 +267,7 @@ static NSNumber *sharedYes = nil;
max = [filters count];
for (count = 0; count < max; count++)
{
#warning huh? why not objectAtIndex: count?
currentFilter = [filters objectAtIndex: 0];
currentFilter = [filters objectAtIndex: count];
apts = [self fetchCoreInfosFrom: [currentFilter objectForKey: @"start"]
to: [currentFilter objectForKey: @"end"]
title: [currentFilter objectForKey: @"title"]
+71
View File
@@ -25,12 +25,14 @@
#import <Foundation/NSException.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSUserDefaults.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoObject.h>
#import <NGObjWeb/SoObject+SoDAV.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOApplication.h>
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <EOControl/EOQualifier.h>
@@ -432,6 +434,75 @@ static BOOL sendFolderAdvisories = NO;
return names;
}
#warning this code should be cleaned up
#warning this code is a dup of UIxFolderActions,\
we should remove the methods there instead
- (WOResponse *) _subscribe: (BOOL) reallyDo
inContext: (WOContext *) localContext
{
WOResponse *response;
NSMutableArray *folderSubscription;
NSString *subscriptionPointer, *baseFolder, *folder;
SOGoUser *activeUser;
NSUserDefaults *ud;
NSArray *realFolderPath;
NSMutableDictionary *moduleSettings;
activeUser = [localContext activeUser];
ud = [activeUser userSettings];
baseFolder = [container nameInContainer];
moduleSettings = [ud objectForKey: baseFolder];
response = [localContext response];
if ([owner isEqualToString: [activeUser login]])
{
[response setStatus: 403];
[response appendContentString:
@"You cannot (un)subscribe to a folder that you own!"];
}
else
{
folderSubscription
= [moduleSettings objectForKey: @"SubscribedFolders"];
if (!(folderSubscription
&& [folderSubscription isKindOfClass: [NSMutableArray class]]))
{
folderSubscription = [NSMutableArray array];
[moduleSettings setObject: folderSubscription
forKey: @"SubscribedFolders"];
}
realFolderPath = [nameInContainer componentsSeparatedByString: @"_"];
if ([realFolderPath count] > 1)
folder = [realFolderPath objectAtIndex: 1];
else
folder = [realFolderPath objectAtIndex: 0];
subscriptionPointer = [NSString stringWithFormat: @"%@:%@/%@",
owner, baseFolder, folder];
if (reallyDo)
[folderSubscription addObjectUniquely: subscriptionPointer];
else
[folderSubscription removeObject: subscriptionPointer];
[ud synchronize];
[response setStatus: 204];
}
return response;
}
- (id <WOActionResults>) davSubscribe: (WOContext *) localContext
{
return [self _subscribe: YES inContext: localContext];
}
- (id <WOActionResults>) davUnsubscribe: (WOContext *) localContext
{
return [self _subscribe: NO inContext: localContext];
}
/* acls as a container */
- (NSArray *) aclUsersForObjectAtPath: (NSArray *) objectPathArray;
+37
View File
@@ -46,6 +46,7 @@
#import <NGObjWeb/NSException+HTTP.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <DOM/DOMProtocols.h>
#import <NGCards/NSDictionary+NGCards.h>
#import <UI/SOGoUI/SOGoACLAdvisory.h>
@@ -646,6 +647,42 @@ static BOOL kontactGroupDAV = YES;
return response;
}
- (NSString *) _parseXMLCommand: (id <DOMDocument>) document
{
NSString *command;
command = [[document firstChild] nodeName];
return [NSString stringWithFormat: @"%@:", command];
}
- (id) POSTAction: (id) localContext
{
id obj;
NSString *cType, *command;
id <DOMDocument> document;
SEL commandSel;
WORequest *rq;
obj = nil;
rq = [localContext request];
if ([rq isSoWebDAVRequest])
{
cType = [rq headerForKey: @"content-type"];
if ([cType isEqualToString: @"application/xml"])
{
document = [rq contentAsDOMDocument];
command = [[self _parseXMLCommand: document] davMethodToObjC];
commandSel = NSSelectorFromString (command);
if ([self respondsToSelector: commandSel])
obj = [self performSelector: commandSel withObject: localContext];
}
}
return obj;
}
- (id) GETAction: (id) localContext
{
// TODO: I guess this should really be done by SOPE (redirect to
+7
View File
@@ -36,6 +36,8 @@
/SOGo/so/znek/Calendar
*/
@class NSArray;
@class NSDictionary;
@class NSString;
@class WOContext;
@@ -49,6 +51,11 @@
- (NSString *) ownerInContext: (WOContext *) _ctx;
- (NSArray *) foldersOfType: (NSString *) folderType
forUID: (NSString *) uid;
- (NSDictionary *) foldersOfType: (NSString *) type
matchingUID: (NSString *) uid;
/* TODO: not implemented, bad bad */
// - (id)lookupFreeBusyObject;
+217
View File
@@ -21,18 +21,29 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoClassSecurityInfo.h>
#import <NGObjWeb/SoSecurityManager.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <DOM/DOMDocument.h>
#import <DOM/DOMNode.h>
#import <DOM/DOMProtocols.h>
#import <SaxObjC/SaxObjC.h>
#import <SaxObjC/XMLNamespaces.h>
#import <Appointments/SOGoAppointmentFolders.h>
#import <Appointments/SOGoFreeBusyObject.h>
#import <Contacts/SOGoContactFolders.h>
#import <Mailer/SOGoMailAccounts.h>
#import "NSDictionary+Utilities.h"
#import "LDAPUserManager.h"
#import "SOGoPermissions.h"
#import "SOGoUser.h"
@@ -96,6 +107,212 @@
return self;
}
- (NSArray *) davNamespaces
{
return [NSArray arrayWithObject: @"urn:inverse:params:xml:ns:inverse-dav"];
}
- (NSDictionary *) _parseCollectionFilters: (id <DOMDocument>) parentNode
{
NSEnumerator *children;
NGDOMNode *node;
NSMutableDictionary *filter;
NSString *componentName;
filter = [NSMutableDictionary dictionaryWithCapacity: 2];
children = [[parentNode getElementsByTagName: @"prop-match"]
objectEnumerator];
while ((node = [children nextObject]))
{
componentName = [[node attribute: @"name"] lowercaseString];
[filter setObject: [node textValue] forKey: componentName];
}
return filter;
}
#warning UIxContactsFoldersView should use these methods\
instead from now on...
- (NSArray *) _subFoldersFromFolder: (SOGoParentFolder *) parentFolder
{
NSMutableArray *folders;
NSEnumerator *subfolders;
SOGoFolder *currentFolder;
NSString *folderName;
NSMutableDictionary *currentDictionary;
SoSecurityManager *securityManager;
securityManager = [SoSecurityManager sharedSecurityManager];
folders = [NSMutableArray array];
subfolders = [[parentFolder subFolders] objectEnumerator];
while ((currentFolder = [subfolders nextObject]))
{
if (![securityManager validatePermission: SOGoPerm_AccessObject
onObject: currentFolder inContext: context])
{
folderName = [NSString stringWithFormat: @"/%@/%@",
[parentFolder nameInContainer],
[currentFolder nameInContainer]];
currentDictionary
= [NSMutableDictionary dictionaryWithCapacity: 3];
[currentDictionary setObject: [currentFolder displayName]
forKey: @"displayName"];
[currentDictionary setObject: folderName forKey: @"name"];
[currentDictionary setObject: [currentFolder folderType]
forKey: @"type"];
[folders addObject: currentDictionary];
}
}
return folders;
}
- (NSArray *) foldersOfType: (NSString *) folderType
forUID: (NSString *) uid
{
NSObject *userFolder;
SOGoParentFolder *parentFolder;
NSMutableArray *folders;
folders = [NSMutableArray array];
userFolder = [container lookupName: uid inContext: context acquire: NO];
/* FIXME: should be moved in the SOGo* classes. Maybe by having a SOGoFolderManager. */
if ([folderType length] == 0 || [folderType isEqualToString: @"calendar"])
{
parentFolder = [userFolder lookupName: @"Calendar"
inContext: context acquire: NO];
[folders
addObjectsFromArray: [self _subFoldersFromFolder: parentFolder]];
}
if ([folderType length] == 0 || [folderType isEqualToString: @"contact"])
{
parentFolder = [userFolder lookupName: @"Contacts"
inContext: context acquire: NO];
[folders
addObjectsFromArray: [self _subFoldersFromFolder: parentFolder]];
}
return folders;
}
- (NSDictionary *) foldersOfType: (NSString *) type
matchingUID: (NSString *) uid
{
NSArray *contacts, *folders;
NSEnumerator *enumerator;
NSDictionary *contact;
NSMutableDictionary *results;
results = [NSMutableDictionary dictionary];
contacts
= [[LDAPUserManager sharedUserManager] fetchContactsMatching: uid];
enumerator = [contacts objectEnumerator];
while ((contact = [enumerator nextObject]))
{
uid = [contact objectForKey: @"c_uid"];
folders = [self foldersOfType: type
forUID: [contact objectForKey: @"c_uid"]];
[results setObject: folders forKey: contact];
}
return results;
}
- (NSString *) _baseDAVURLWithSuffix: (NSString *) suffix
{
NSURL *prefixURL;
prefixURL = [NSURL URLWithString: [NSString stringWithFormat: @"../%@", suffix]
relativeToURL: [self davURL]];
return [[prefixURL standardizedURL] absoluteString];
}
- (void) _appendFolders: (NSDictionary *) users
toResponse: (WOResponse *) r
{
NSDictionary *currentContact, *currentFolder;
NSEnumerator *keys, *folders;
NSString *baseHREF, *data;
baseHREF = [self _baseDAVURLWithSuffix: @"./"];
keys = [[users allKeys] objectEnumerator];
while ((currentContact = [keys nextObject]))
{
folders = [[users objectForKey: currentContact] objectEnumerator];
while ((currentFolder = [folders nextObject]))
{
[r appendContentString: @"<D:response><D:href>"];
data = [NSString stringWithFormat: @"%@%@%@", baseHREF,
[currentContact objectForKey: @"c_uid"],
[currentFolder objectForKey: @"name"]];
[r appendContentString: data];
[r appendContentString: @"</D:href><D:propstat>"];
[r appendContentString: @"<D:status>HTTP/1.1 200 OK</D:status>"];
[r appendContentString: @"</D:propstat><D:owner>"];
data = [NSString stringWithFormat: @"%@users/%@", baseHREF,
[currentContact objectForKey: @"c_uid"]];
[r appendContentString: data];
[r appendContentString: @"</D:owner><ownerdisplayname>"];
data = [currentContact keysWithFormat: @"%{cn} <%{c_email}>"];
[r appendContentString: [data stringByEscapingXMLString]];
[r appendContentString: @"</ownerdisplayname><D:displayname>"];
data = [currentFolder objectForKey: @"displayName"];
[r appendContentString: [data stringByEscapingXMLString]];
[r appendContentString: @"</D:displayname></D:response>\r\n"];
}
}
}
- (void) _appendCollectionsMatchingFilter: (NSDictionary *) filter
toResponse: (WOResponse *) r
{
NSString *prefix, *queryOwner, *uid;
NSDictionary *folders;
prefix = [self _baseDAVURLWithSuffix: @"users/"];
queryOwner = [filter objectForKey: @"owner"];
if ([queryOwner hasPrefix: prefix])
{
uid = [queryOwner substringFromIndex: [prefix length]];
folders = [self foldersOfType: [filter objectForKey: @"resource-type"]
matchingUID: uid];
[self _appendFolders: folders toResponse: r];
}
}
- (id) davCollectionQuery: (id) queryContext
{
WOResponse *r;
NSDictionary *filter;
id <DOMDocument> document;
r = [context response];
[r setStatus: 207];
[r setContentEncoding: NSUTF8StringEncoding];
[r setHeader: @"text/xml; charset=\"utf-8\"" forKey: @"content-type"];
[r setHeader: @"no-cache" forKey: @"pragma"];
[r setHeader: @"no-cache" forKey: @"cache-control"];
[r appendContentString:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"];
[r appendContentString: @"<D:multistatus xmlns:D=\"DAV:\""
@" xmlns=\"urn:ietf:params:xml:ns:inverse-dav\">\r\n"];
document = [[context request] contentAsDOMDocument];
filter = [self _parseCollectionFilters: document];
[self _appendCollectionsMatchingFilter: filter toResponse: r];
[r appendContentString:@"</D:multistatus>\r\n"];
return r;
}
// - (SOGoGroupsFolder *) lookupGroupsFolder
// {
// return [self lookupName: @"Groups" inContext: nil acquire: NO];