mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-05-25 21:35:23 +00:00
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:
@@ -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"]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user