mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-04-24 22:39:31 +00:00
merge of '61b0fdce16f6c0727e58cc97232171b41008ed41'
and 'bb276eea8dc76b5c71f49df1d23424ab19015233' Monotone-Parent: 61b0fdce16f6c0727e58cc97232171b41008ed41 Monotone-Parent: bb276eea8dc76b5c71f49df1d23424ab19015233 Monotone-Revision: f70b5b1e5f982c1feda21a5227e3bc26f8dc7f66 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-01-04T15:27:58 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
68
ChangeLog
68
ChangeLog
@@ -1,3 +1,71 @@
|
||||
2012-01-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* UI/WebServerResources/ContactsUI.js
|
||||
(onAddressBooksMenuPrepareVisibility): the "new list", "sharing" and "import"
|
||||
options are now greyed out properly, depending on the object type
|
||||
and the new attributes below.
|
||||
|
||||
* UI/Contacts/UIxContactFoldersView.m
|
||||
(-currentContactFolderAclEditing)
|
||||
(-currentContactFolderListEditing): new attribute accessors.
|
||||
|
||||
* SoObjects/SOGo/SOGoFolder.m (-sendFolderAdvisoryTemplate:):
|
||||
moved method from SOGoGCSFolder in order to make it available to
|
||||
other folder classes.
|
||||
|
||||
* SoObjects/SOGo/LDAPSource.m (-initFromUDSource:inDomain:): use
|
||||
the new setters for certain ivars + take the new "abOU" key into
|
||||
account.
|
||||
(-setListRequiresDot:, -listRequiresDot:, -setSourceID:)
|
||||
(-setDisplayName, -displayName, -setModifiers:): new accessors.
|
||||
(-_convertRecordToLDAPAttributes): we now strip object classes that
|
||||
are not supported by the server prior to remove the related fields.
|
||||
(-hasUserAddressBooks): new method that returns whether user
|
||||
addressbooks are supported, i.e. when "abOU" is set.
|
||||
(-addressBookSourcesForUser:): when "abOU" is set, returns an
|
||||
array of LDAPSource instances representing the personal
|
||||
addressbooks of the specified user.
|
||||
(-addAddressBookSource:withDisplayName:forUser:)
|
||||
(-renameAddressBookSource:withDisplayName:forUser:)
|
||||
(-removeAddressBookSource:forUser:): new methods with a
|
||||
self-explicit name.
|
||||
|
||||
* SoObjects/Contacts/SOGoContactSourceFolder.m
|
||||
(-setIsPersonalSource, -isPersonalSource): new accessors for the
|
||||
"isPersonalSource ivar".
|
||||
(-lookupName:inContext:acquire:): setup the object classes of the
|
||||
new entries to "inetorgperson" and "mozillaabpersonalpha".
|
||||
(-lookupContactsWithFilter:onCriteria:sortBy:ordering:): check
|
||||
whether "listRequiresDot" is set on the current source and return
|
||||
the full listing if not required.
|
||||
(-compare:): enhanced to treat personal sources as if they were
|
||||
regular GCS folders, in order to sort them properly.
|
||||
(-delete, -renameTo:): implemented method, required for the
|
||||
corresponding web methods.
|
||||
(-ownerInContext:) adapted method to personal sources.
|
||||
|
||||
* SoObjects/Contacts/SOGoContactFolders.m (-appendPersonalSource):
|
||||
overriden method for returning LDAP-based user addresbook sources.
|
||||
(-newFolderWithName:andNameInContainer:): idem
|
||||
(-renameLDAPAddressBook:withDisplayName:): new method that enables
|
||||
the renaming of LDAP-based user addresbook sources.
|
||||
(-removeLDAPAddressBook:): new method that enables
|
||||
the removal of LDAP-based user addresbook sources.
|
||||
|
||||
2012-01-03 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/SOGo/SOGoParentFolder.m (-appendPersonalSources): made
|
||||
method public so that it can be easily overriden in subclasses.
|
||||
|
||||
* SoObjects/SOGo/SOGoUser.m (-authenticationSource): new method
|
||||
that returned the SOGoSource instance that successfully recognized
|
||||
the user represented by the current instance.
|
||||
|
||||
* SoObjects/SOGo/SOGoUserManager.m
|
||||
(_fillContactInfosForUser:withUIDorEmail:inDomain:): we now set
|
||||
the identifier of the source that authenticated the specified user
|
||||
as the "SOGoSource" entry of the returned dictionary.
|
||||
|
||||
2012-01-02 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/WebServerResources/UIxPreferences.js (getFilterFromEditor):
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
|
||||
@interface SOGoContactFolders : SOGoParentFolder
|
||||
|
||||
- (NSException *) renameLDAPAddressBook: (NSString *) sourceID
|
||||
withDisplayName: (NSString *) newDisplayName;
|
||||
- (NSException *) removeLDAPAddressBook: (NSString *) sourceID;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SOGOCONTACTFOLDERS_H */
|
||||
|
||||
@@ -33,10 +33,12 @@
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
|
||||
#import <SOGo/NSObject+DAV.h>
|
||||
#import <SOGo/SOGoLDAPAddressBook.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
@@ -45,6 +47,7 @@
|
||||
|
||||
#import "SOGoContactGCSFolder.h"
|
||||
#import "SOGoContactSourceFolder.h"
|
||||
|
||||
#import "SOGoContactFolders.h"
|
||||
|
||||
#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav"
|
||||
@@ -60,6 +63,62 @@
|
||||
return [SOGoContactGCSFolder class];
|
||||
}
|
||||
|
||||
- (void) _fetchLDAPAddressBooks: (id <SOGoSource>) source
|
||||
{
|
||||
id <SOGoSource> abSource;
|
||||
SOGoContactSourceFolder *folder;
|
||||
NSArray *abSources;
|
||||
NSUInteger count, max;
|
||||
NSString *name;
|
||||
|
||||
abSources = [source addressBookSourcesForUser: owner];
|
||||
max = [abSources count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
abSource = [abSources objectAtIndex: count];
|
||||
name = [abSource sourceID];
|
||||
folder = [SOGoContactSourceFolder folderWithName: name
|
||||
andDisplayName: [abSource displayName]
|
||||
inContainer: self];
|
||||
[folder setSource: abSource];
|
||||
[folder setIsPersonalSource: YES];
|
||||
[subFolders setObject: folder forKey: name];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSException *) appendPersonalSources
|
||||
{
|
||||
SOGoUser *currentUser;
|
||||
NSException *result;
|
||||
id <SOGoSource> source;
|
||||
|
||||
currentUser = [context activeUser];
|
||||
source = [currentUser authenticationSource];
|
||||
if ([source hasUserAddressBooks])
|
||||
{
|
||||
result = nil;
|
||||
/* We don't handle ACLs for user LDAP addressbooks yet, therefore only
|
||||
the owner has access to his addressbooks. */
|
||||
if (activeUserIsOwner
|
||||
|| [[currentUser login] isEqualToString: owner])
|
||||
{
|
||||
[self _fetchLDAPAddressBooks: source];
|
||||
if (![subFolders objectForKey: @"personal"])
|
||||
{
|
||||
result = [source addAddressBookSource: @"personal"
|
||||
withDisplayName: [self defaultFolderName]
|
||||
forUser: owner];
|
||||
if (!result)
|
||||
[self _fetchLDAPAddressBooks: source];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
result = [super appendPersonalSources];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSException *) appendSystemSources
|
||||
{
|
||||
SOGoUserManager *um;
|
||||
@@ -101,6 +160,88 @@
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSException *) newFolderWithName: (NSString *) name
|
||||
andNameInContainer: (NSString *) newNameInContainer
|
||||
{
|
||||
SOGoUser *currentUser;
|
||||
NSException *result;
|
||||
id <SOGoSource> source;
|
||||
|
||||
currentUser = [context activeUser];
|
||||
source = [currentUser authenticationSource];
|
||||
if ([source hasUserAddressBooks])
|
||||
{
|
||||
result = nil;
|
||||
/* We don't handle ACLs for user LDAP addressbooks yet, therefore only
|
||||
the owner has access to his addressbooks. */
|
||||
if (activeUserIsOwner
|
||||
|| [[currentUser login] isEqualToString: owner])
|
||||
{
|
||||
result = [source addAddressBookSource: newNameInContainer
|
||||
withDisplayName: name
|
||||
forUser: owner];
|
||||
if (!result)
|
||||
[self _fetchLDAPAddressBooks: source];
|
||||
}
|
||||
}
|
||||
else
|
||||
result = [super newFolderWithName: name
|
||||
andNameInContainer: newNameInContainer];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSException *) renameLDAPAddressBook: (NSString *) sourceID
|
||||
withDisplayName: (NSString *) newDisplayName
|
||||
{
|
||||
NSException *result;
|
||||
SOGoUser *currentUser;
|
||||
id <SOGoSource> source;
|
||||
|
||||
currentUser = [context activeUser];
|
||||
source = [currentUser authenticationSource];
|
||||
/* We don't handle ACLs for user LDAP addressbooks yet, therefore only
|
||||
the owner has access to his addressbooks. */
|
||||
if (activeUserIsOwner
|
||||
|| [[currentUser login] isEqualToString: owner])
|
||||
result = [source renameAddressBookSource: sourceID
|
||||
withDisplayName: newDisplayName
|
||||
forUser: owner];
|
||||
else
|
||||
result = [NSException exceptionWithHTTPStatus: 403
|
||||
reason: @"operation denied"];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSException *) removeLDAPAddressBook: (NSString *) sourceID
|
||||
{
|
||||
NSException *result;
|
||||
SOGoUser *currentUser;
|
||||
id <SOGoSource> source;
|
||||
|
||||
if ([sourceID isEqualToString: @"personal"])
|
||||
result = [NSException exceptionWithHTTPStatus: 403
|
||||
reason: @"folder 'personal' cannot be deleted"];
|
||||
else
|
||||
{
|
||||
result = nil;
|
||||
currentUser = [context activeUser];
|
||||
source = [currentUser authenticationSource];
|
||||
/* We don't handle ACLs for user LDAP addressbooks yet, therefore only
|
||||
the owner has access to his addressbooks. */
|
||||
if (activeUserIsOwner
|
||||
|| [[currentUser login] isEqualToString: owner])
|
||||
result = [source removeAddressBookSource: sourceID
|
||||
forUser: owner];
|
||||
else
|
||||
result = [NSException exceptionWithHTTPStatus: 403
|
||||
reason: @"operation denied"];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSString *) defaultFolderName
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
{
|
||||
id <SOGoSource> source;
|
||||
NSMutableDictionary *childRecords;
|
||||
BOOL isPersonalSource;
|
||||
}
|
||||
|
||||
+ (id) folderWithName: (NSString *) aName
|
||||
@@ -48,6 +49,9 @@
|
||||
- (NSException *) saveLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry;
|
||||
- (NSException *) deleteLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry;
|
||||
|
||||
- (void) setIsPersonalSource: (BOOL) isPersonal;
|
||||
- (BOOL) isPersonalSource;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -37,12 +37,16 @@
|
||||
#import <EOControl/EOSortOrdering.h>
|
||||
#import <SaxObjC/XMLNamespaces.h>
|
||||
|
||||
#import <SOGo/SOGoPermissions.h>
|
||||
#import <SOGo/SOGoSource.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSDictionary+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/SOGoPermissions.h>
|
||||
#import <SOGo/SOGoSource.h>
|
||||
#import <SOGo/SOGoUserSettings.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
|
||||
#import "SOGoContactFolders.h"
|
||||
#import "SOGoContactGCSFolder.h"
|
||||
#import "SOGoContactLDIFEntry.h"
|
||||
#import "SOGoContactSourceFolder.h"
|
||||
|
||||
@@ -107,6 +111,16 @@
|
||||
return source;
|
||||
}
|
||||
|
||||
- (void) setIsPersonalSource: (BOOL) isPersonal
|
||||
{
|
||||
isPersonalSource = isPersonal;
|
||||
}
|
||||
|
||||
- (BOOL) isPersonalSource
|
||||
{
|
||||
return isPersonalSource;
|
||||
}
|
||||
|
||||
- (NSString *) groupDavResourceType
|
||||
{
|
||||
return @"vcard-collection";
|
||||
@@ -135,6 +149,7 @@
|
||||
SOGoContactLDIFEntry *obj;
|
||||
NSString *url;
|
||||
BOOL isNew = NO;
|
||||
NSArray *baseClasses;
|
||||
|
||||
/* first check attributes directly bound to the application */
|
||||
obj = [super lookupName: objectName inContext: lookupContext acquire: NO];
|
||||
@@ -152,7 +167,11 @@
|
||||
url = [[[lookupContext request] uri] urlWithoutParameters];
|
||||
if ([url hasSuffix: @"AsContact"])
|
||||
{
|
||||
ldifEntry = [NSMutableDictionary dictionary];
|
||||
baseClasses = [NSArray arrayWithObjects: @"inetorgperson",
|
||||
@"mozillaabpersonalpha", nil];
|
||||
ldifEntry = [NSMutableDictionary
|
||||
dictionaryWithObject: baseClasses
|
||||
forKey: @"objectclass"];
|
||||
isNew = YES;
|
||||
}
|
||||
}
|
||||
@@ -294,7 +313,8 @@
|
||||
|
||||
result = nil;
|
||||
|
||||
if ([filter length] > 0 && [criteria isEqualToString: @"name_or_address"])
|
||||
if (([filter length] > 0 && [criteria isEqualToString: @"name_or_address"])
|
||||
|| ![source listRequiresDot])
|
||||
{
|
||||
records = [source fetchContactsMatching: filter];
|
||||
[childRecords setObjects: records
|
||||
@@ -335,22 +355,88 @@
|
||||
- (NSComparisonResult) compare: (id) otherFolder
|
||||
{
|
||||
NSComparisonResult comparison;
|
||||
BOOL otherIsPersonal;
|
||||
|
||||
if ([NSStringFromClass([otherFolder class])
|
||||
isEqualToString: @"SOGoContactGCSFolder"])
|
||||
comparison = NSOrderedDescending;
|
||||
otherIsPersonal = ([otherFolder isKindOfClass: [SOGoContactGCSFolder class]]
|
||||
|| ([otherFolder isKindOfClass: isa] && [otherFolder isPersonalSource]));
|
||||
|
||||
if (isPersonalSource)
|
||||
{
|
||||
if (otherIsPersonal && ![nameInContainer isEqualToString: @"personal"])
|
||||
{
|
||||
if ([[otherFolder nameInContainer] isEqualToString: @"personal"])
|
||||
comparison = NSOrderedDescending;
|
||||
else
|
||||
comparison
|
||||
= [[self displayName]
|
||||
localizedCaseInsensitiveCompare: [otherFolder displayName]];
|
||||
}
|
||||
else
|
||||
comparison = NSOrderedAscending;
|
||||
}
|
||||
else
|
||||
comparison
|
||||
= [[self displayName]
|
||||
localizedCaseInsensitiveCompare: [otherFolder displayName]];
|
||||
{
|
||||
if (otherIsPersonal)
|
||||
comparison = NSOrderedDescending;
|
||||
else
|
||||
comparison
|
||||
= [[self displayName]
|
||||
localizedCaseInsensitiveCompare: [otherFolder displayName]];
|
||||
}
|
||||
|
||||
return comparison;
|
||||
}
|
||||
|
||||
/* common methods */
|
||||
|
||||
- (NSException *) delete
|
||||
{
|
||||
NSException *error;
|
||||
|
||||
if (isPersonalSource)
|
||||
{
|
||||
error = [(SOGoContactFolders *) container
|
||||
removeLDAPAddressBook: nameInContainer];
|
||||
if (!error && [[context request] handledByDefaultHandler])
|
||||
[self sendFolderAdvisoryTemplate: @"Removal"];
|
||||
}
|
||||
else
|
||||
error = [NSException exceptionWithHTTPStatus: 501 /* not implemented */
|
||||
reason: @"delete not available on system sources"];
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
- (void) renameTo: (NSString *) newName
|
||||
{
|
||||
NSException *error;
|
||||
|
||||
if (isPersonalSource)
|
||||
{
|
||||
if (![[source displayName] isEqualToString: newName])
|
||||
{
|
||||
error = [(SOGoContactFolders *) container
|
||||
renameLDAPAddressBook: nameInContainer
|
||||
withDisplayName: newName];
|
||||
if (!error)
|
||||
[self setDisplayName: newName];
|
||||
}
|
||||
}
|
||||
/* If public source then method is ignored, maybe we should return an
|
||||
NSException instead... */
|
||||
}
|
||||
|
||||
/* acls */
|
||||
- (NSString *) ownerInContext: (WOContext *) noContext
|
||||
{
|
||||
return @"nobody";
|
||||
NSString *sourceOwner;
|
||||
|
||||
if (isPersonalSource)
|
||||
sourceOwner = [[source modifiers] objectAtIndex: 0];
|
||||
else
|
||||
sourceOwner = @"nobody";
|
||||
|
||||
return sourceOwner;
|
||||
}
|
||||
|
||||
- (NSArray *) subscriptionRoles
|
||||
|
||||
@@ -31,10 +31,11 @@
|
||||
#include "SOGoConstants.h"
|
||||
|
||||
@class LDAPSourceSchema;
|
||||
@class NSDictionary;
|
||||
@class NSString;
|
||||
@class NGLdapConnection;
|
||||
@class NGLdapEntry;
|
||||
@class NSException;
|
||||
@class NSMutableArray;
|
||||
@class NSMutableDictionary;
|
||||
@class NSString;
|
||||
|
||||
@interface LDAPSource : NSObject <SOGoDNSource>
|
||||
{
|
||||
@@ -42,6 +43,8 @@
|
||||
int queryTimeout;
|
||||
|
||||
NSString *sourceID;
|
||||
NSString *displayName;
|
||||
|
||||
NSString *bindDN; // The bindDN/password could be either the source's one
|
||||
NSString *password; // or the current user if _bindAsCurrentUser is set to YES
|
||||
NSString *sourceBindDN; // while sourceBindDN/sourceBindPassword always belong to the source
|
||||
@@ -50,6 +53,7 @@
|
||||
unsigned int port;
|
||||
NSString *encryption;
|
||||
NSString *_filter;
|
||||
BOOL _bindAsCurrentUser;
|
||||
NSString *_scope;
|
||||
|
||||
NSString *baseDN;
|
||||
@@ -60,7 +64,8 @@
|
||||
NSArray *mailFields, *searchFields;
|
||||
NSString *IMAPHostField, *IMAPLoginField;
|
||||
NSArray *bindFields;
|
||||
BOOL _bindAsCurrentUser;
|
||||
|
||||
BOOL listRequiresDot;
|
||||
|
||||
NSString *domain;
|
||||
NSString *contactInfoAttribute;
|
||||
@@ -80,6 +85,9 @@
|
||||
NSString *kindField;
|
||||
NSString *multipleBookingsField;
|
||||
|
||||
/* user addressbooks */
|
||||
NSString *abOU;
|
||||
|
||||
/* ACL */
|
||||
NSArray *modifiers;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
@@ -42,7 +43,6 @@
|
||||
#import "SOGoSystemDefaults.h"
|
||||
|
||||
#import "LDAPSource.h"
|
||||
|
||||
#import "../../Main/SOGo.h"
|
||||
|
||||
static Class NSStringK;
|
||||
@@ -139,6 +139,9 @@ static Class NSStringK;
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
sourceID = nil;
|
||||
displayName = nil;
|
||||
|
||||
bindDN = nil;
|
||||
password = nil;
|
||||
sourceBindDN = nil;
|
||||
@@ -146,7 +149,6 @@ static Class NSStringK;
|
||||
hostname = nil;
|
||||
port = 389;
|
||||
encryption = nil;
|
||||
sourceID = nil;
|
||||
domain = nil;
|
||||
|
||||
baseDN = nil;
|
||||
@@ -164,6 +166,7 @@ static Class NSStringK;
|
||||
bindFields = nil;
|
||||
_scope = @"sub";
|
||||
_filter = nil;
|
||||
listRequiresDot = YES;
|
||||
|
||||
searchAttributes = nil;
|
||||
passwordPolicy = NO;
|
||||
@@ -220,11 +223,12 @@ static Class NSStringK;
|
||||
inDomain: (NSString *) sourceDomain
|
||||
{
|
||||
SOGoDomainDefaults *dd;
|
||||
NSNumber *udQueryLimit, *udQueryTimeout;
|
||||
NSNumber *udQueryLimit, *udQueryTimeout, *dotValue;
|
||||
|
||||
if ((self = [self init]))
|
||||
{
|
||||
ASSIGN(sourceID, [udSource objectForKey: @"id"]);
|
||||
[self setSourceID: [udSource objectForKey: @"id"]];
|
||||
[self setDisplayName: [udSource objectForKey: @"displayName"]];
|
||||
|
||||
[self setBindDN: [udSource objectForKey: @"bindDN"]
|
||||
password: [udSource objectForKey: @"bindPassword"]
|
||||
@@ -245,9 +249,15 @@ static Class NSStringK;
|
||||
kindField: [udSource objectForKey: @"KindFieldName"]
|
||||
andMultipleBookingsField: [udSource objectForKey: @"MultipleBookingsFieldName"]];
|
||||
|
||||
dotValue = [udSource objectForKey: @"listRequiresDot"];
|
||||
if (dotValue)
|
||||
[self setListRequiresDot: [dotValue boolValue]];
|
||||
[self setContactMapping: [udSource objectForKey: @"mapping"]
|
||||
andObjectClasses: [udSource objectForKey: @"objectClasses"]];
|
||||
|
||||
[self setModifiers: [udSource objectForKey: @"modifiers"]];
|
||||
ASSIGN (abOU, [udSource objectForKey: @"abOU"]);
|
||||
|
||||
if ([sourceDomain length])
|
||||
{
|
||||
dd = [SOGoDomainDefaults defaultsForDomain: sourceDomain];
|
||||
@@ -283,10 +293,8 @@ static Class NSStringK;
|
||||
|
||||
if ([udSource objectForKey: @"passwordPolicy"])
|
||||
passwordPolicy = [[udSource objectForKey: @"passwordPolicy"] boolValue];
|
||||
|
||||
ASSIGN (modifiers, [udSource objectForKey: @"modifiers"]);
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -386,6 +394,16 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||
ASSIGN(multipleBookingsField, [newMultipleBookingsField lowercaseString]);
|
||||
}
|
||||
|
||||
- (void) setListRequiresDot: (BOOL) aBool
|
||||
{
|
||||
listRequiresDot = aBool;
|
||||
}
|
||||
|
||||
- (BOOL) listRequiresDot
|
||||
{
|
||||
return listRequiresDot;
|
||||
}
|
||||
|
||||
- (void) setContactMapping: (NSDictionary *) newMapping
|
||||
andObjectClasses: (NSArray *) newObjectClasses
|
||||
{
|
||||
@@ -438,6 +456,11 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||
[ldapConnection setQuerySizeLimit: queryLimit];
|
||||
if (queryTimeout > 0)
|
||||
[ldapConnection setQueryTimeLimit: queryTimeout];
|
||||
if (!schema)
|
||||
{
|
||||
schema = [LDAPSourceSchema new];
|
||||
[schema readSchemaFromConnection: ldapConnection];
|
||||
}
|
||||
}
|
||||
else
|
||||
ldapConnection = nil;
|
||||
@@ -691,11 +714,18 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||
[qs appendString: searchFormat];
|
||||
}
|
||||
|
||||
if (_filter && [_filter length])
|
||||
if ([_filter length])
|
||||
[qs appendFormat: @" AND %@", _filter];
|
||||
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
|
||||
}
|
||||
else if (!listRequiresDot)
|
||||
{
|
||||
qs = [NSMutableString stringWithFormat: @"(%@='*')", CNField];
|
||||
if ([_filter length])
|
||||
[qs appendFormat: @" AND %@", _filter];
|
||||
qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
|
||||
}
|
||||
else
|
||||
qualifier = nil;
|
||||
|
||||
@@ -1058,7 +1088,7 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||
|
||||
contacts = [NSMutableArray array];
|
||||
|
||||
if ([match length] > 0)
|
||||
if ([match length] > 0 || !listRequiresDot)
|
||||
{
|
||||
ldapConnection = [self _ldapConnection];
|
||||
qualifier = [self _qualifierForFilter: match];
|
||||
@@ -1093,11 +1123,6 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||
|
||||
// attributes = [self _searchAttributes];
|
||||
ldapConnection = [self _ldapConnection];
|
||||
if (!schema)
|
||||
{
|
||||
schema = [LDAPSourceSchema new];
|
||||
[schema readSchemaFromConnection: ldapConnection];
|
||||
}
|
||||
attributes = [NSArray arrayWithObject: @"*"];
|
||||
|
||||
if ([_scope caseInsensitiveCompare: @"BASE"] == NSOrderedSame)
|
||||
@@ -1221,16 +1246,36 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
|
||||
return ldapEntry;
|
||||
}
|
||||
|
||||
- (void) setSourceID: (NSString *) newSourceID
|
||||
{
|
||||
ASSIGN (sourceID, newSourceID);
|
||||
}
|
||||
|
||||
- (NSString *) sourceID
|
||||
{
|
||||
return sourceID;
|
||||
}
|
||||
|
||||
- (void) setDisplayName: (NSString *) newDisplayName
|
||||
{
|
||||
ASSIGN (displayName, newDisplayName);
|
||||
}
|
||||
|
||||
- (NSString *) displayName
|
||||
{
|
||||
return displayName;
|
||||
}
|
||||
|
||||
- (NSString *) baseDN
|
||||
{
|
||||
return baseDN;
|
||||
}
|
||||
|
||||
- (void) setModifiers: (NSArray *) newModifiers
|
||||
{
|
||||
ASSIGN (modifiers, newModifiers);
|
||||
}
|
||||
|
||||
- (NSArray *) modifiers
|
||||
{
|
||||
return modifiers;
|
||||
@@ -1240,33 +1285,50 @@ static NSArray *
|
||||
_convertRecordToLDAPAttributes (LDAPSourceSchema *schema, NSDictionary *ldifRecord)
|
||||
{
|
||||
/* convert resulting record to NGLdapEntry:
|
||||
- strip non-existing object classes
|
||||
- ignore fields with empty values
|
||||
- ignore extra fields
|
||||
- use correct case for LDAP attribute matching classes */
|
||||
NSMutableArray *attributes;
|
||||
NSMutableArray *validClasses, *validFields, *attributes;
|
||||
NGLdapAttribute *attribute;
|
||||
NSArray *classes, *fields, *values;
|
||||
NSString *field, *lowerField, *value;
|
||||
NSString *objectClass, *field, *lowerField, *value;
|
||||
NSUInteger count, max, valueCount, valueMax;
|
||||
|
||||
attributes = [NSMutableArray new];
|
||||
|
||||
classes = [ldifRecord objectForKey: @"objectclass"];
|
||||
if ([classes isKindOfClass: NSStringK])
|
||||
classes = [NSArray arrayWithObject: classes];
|
||||
fields = [schema fieldsForClasses: classes];
|
||||
max = [classes count];
|
||||
validClasses = [NSMutableArray array];
|
||||
validFields = [NSMutableArray array];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
objectClass = [classes objectAtIndex: count];
|
||||
fields = [schema fieldsForClass: objectClass];
|
||||
if ([fields count] > 0)
|
||||
{
|
||||
[validClasses addObject: objectClass];
|
||||
[validFields addObjectsFromArray: fields];
|
||||
}
|
||||
}
|
||||
|
||||
max = [fields count];
|
||||
attributes = [NSMutableArray new];
|
||||
max = [validFields count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
attribute = nil;
|
||||
field = [fields objectAtIndex: count];
|
||||
field = [validFields objectAtIndex: count];
|
||||
lowerField = [field lowercaseString];
|
||||
if (![lowerField isEqualToString: @"dn"])
|
||||
{
|
||||
values = [ldifRecord objectForKey: lowerField];
|
||||
if ([values isKindOfClass: NSStringK])
|
||||
values = [NSArray arrayWithObject: values];
|
||||
if ([lowerField isEqualToString: @"objectclass"])
|
||||
values = validClasses;
|
||||
else
|
||||
{
|
||||
values = [ldifRecord objectForKey: lowerField];
|
||||
if ([values isKindOfClass: NSStringK])
|
||||
values = [NSArray arrayWithObject: values];
|
||||
}
|
||||
valueMax = [values count];
|
||||
for (valueCount = 0; valueCount < valueMax; valueCount++)
|
||||
{
|
||||
@@ -1292,7 +1354,7 @@ _convertRecordToLDAPAttributes (LDAPSourceSchema *schema, NSDictionary *ldifReco
|
||||
- (NSException *) addContactEntry: (NSDictionary *) roLdifRecord
|
||||
withID: (NSString *) aId
|
||||
{
|
||||
NSException *result = nil;
|
||||
NSException *result;
|
||||
NGLdapEntry *newEntry;
|
||||
NSMutableDictionary *ldifRecord;
|
||||
NSArray *attributes;
|
||||
@@ -1302,12 +1364,6 @@ _convertRecordToLDAPAttributes (LDAPSourceSchema *schema, NSDictionary *ldifReco
|
||||
if ([aId length] > 0)
|
||||
{
|
||||
ldapConnection = [self _ldapConnection];
|
||||
if (!schema)
|
||||
{
|
||||
schema = [LDAPSourceSchema new];
|
||||
[schema readSchemaFromConnection: ldapConnection];
|
||||
}
|
||||
|
||||
ldifRecord = [roLdifRecord mutableCopy];
|
||||
[ldifRecord autorelease];
|
||||
[ldifRecord setObject: aId forKey: UIDField];
|
||||
@@ -1336,6 +1392,7 @@ _convertRecordToLDAPAttributes (LDAPSourceSchema *schema, NSDictionary *ldifReco
|
||||
NS_DURING
|
||||
{
|
||||
[ldapConnection addEntry: newEntry];
|
||||
result = nil;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
@@ -1413,7 +1470,7 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
|
||||
- (NSException *) updateContactEntry: (NSDictionary *) roLdifRecord
|
||||
{
|
||||
NSException *result = nil;
|
||||
NSException *result;
|
||||
NSString *dn;
|
||||
NSMutableDictionary *ldifRecord;
|
||||
NSArray *attributes, *changes;
|
||||
@@ -1423,12 +1480,6 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
if ([dn length] > 0)
|
||||
{
|
||||
ldapConnection = [self _ldapConnection];
|
||||
if (!schema)
|
||||
{
|
||||
schema = [LDAPSourceSchema new];
|
||||
[schema readSchemaFromConnection: ldapConnection];
|
||||
}
|
||||
|
||||
ldifRecord = [roLdifRecord mutableCopy];
|
||||
[ldifRecord autorelease];
|
||||
[self _applyContactMappingToOutput: ldifRecord];
|
||||
@@ -1440,6 +1491,7 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
{
|
||||
[ldapConnection modifyEntryWithDN: dn
|
||||
changes: changes];
|
||||
result = nil;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
@@ -1455,7 +1507,7 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
|
||||
- (NSException *) removeContactEntryWithID: (NSString *) aId
|
||||
{
|
||||
NSException *result = nil;
|
||||
NSException *result;
|
||||
NGLdapConnection *ldapConnection;
|
||||
NSString *dn;
|
||||
|
||||
@@ -1464,6 +1516,7 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
NS_DURING
|
||||
{
|
||||
[ldapConnection removeEntryWithDN: dn];
|
||||
result = nil;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
@@ -1474,4 +1527,233 @@ _makeLDAPChanges (NGLdapConnection *ldapConnection,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* user addressbooks */
|
||||
- (BOOL) hasUserAddressBooks
|
||||
{
|
||||
return ([abOU length] > 0);
|
||||
}
|
||||
|
||||
- (NSArray *) addressBookSourcesForUser: (NSString *) user
|
||||
{
|
||||
NSMutableArray *sources;
|
||||
NSString *abBaseDN;
|
||||
NGLdapConnection *ldapConnection;
|
||||
NSArray *attributes, *modifier;
|
||||
NSEnumerator *entries;
|
||||
NGLdapEntry *entry;
|
||||
NSMutableDictionary *entryRecord;
|
||||
NSDictionary *sourceRec;
|
||||
LDAPSource *ab;
|
||||
|
||||
if ([self hasUserAddressBooks])
|
||||
{
|
||||
/* list subentries */
|
||||
sources = [NSMutableArray array];
|
||||
|
||||
ldapConnection = [self _ldapConnection];
|
||||
abBaseDN = [NSString stringWithFormat: @"ou=%@,%@=%@,%@", abOU, IDField, user, baseDN];
|
||||
|
||||
/* test ou=addressbooks entry */
|
||||
attributes = [NSArray arrayWithObject: @"*"];
|
||||
entries = [ldapConnection baseSearchAtBaseDN: abBaseDN
|
||||
qualifier: nil
|
||||
attributes: attributes];
|
||||
entry = [entries nextObject];
|
||||
if (entry)
|
||||
{
|
||||
attributes = [NSArray arrayWithObjects: @"ou", @"description", nil];
|
||||
entries = [ldapConnection flatSearchAtBaseDN: abBaseDN
|
||||
qualifier: nil
|
||||
attributes: attributes];
|
||||
modifier = [NSArray arrayWithObject: user];
|
||||
while ((entry = [entries nextObject]))
|
||||
{
|
||||
sourceRec = [entry _asDictionary];
|
||||
ab = [LDAPSource new];
|
||||
[ab setSourceID: [sourceRec objectForKey: @"ou"]];
|
||||
[ab setDisplayName: [sourceRec objectForKey: @"description"]];
|
||||
[ab setBindDN: bindDN
|
||||
password: password
|
||||
hostname: hostname
|
||||
port: [NSString stringWithFormat: @"%d", port]
|
||||
encryption: encryption
|
||||
bindAsCurrentUser: NO];
|
||||
[ab setBaseDN: [entry dn]
|
||||
IDField: @"cn"
|
||||
CNField: @"displayName"
|
||||
UIDField: @"cn"
|
||||
mailFields: nil
|
||||
searchFields: nil
|
||||
IMAPHostField: nil
|
||||
IMAPLoginField: nil
|
||||
bindFields: nil
|
||||
kindField: nil
|
||||
andMultipleBookingsField: nil];
|
||||
[ab setListRequiresDot: NO];
|
||||
[ab setModifiers: modifier];
|
||||
[sources addObject: ab];
|
||||
[ab release];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
entryRecord = [NSMutableDictionary dictionary];
|
||||
[entryRecord setObject: @"organizationalUnit" forKey: @"objectclass"];
|
||||
[entryRecord setObject: @"addressbooks" forKey: @"ou"];
|
||||
attributes = _convertRecordToLDAPAttributes (schema, entryRecord);
|
||||
entry = [[NGLdapEntry alloc] initWithDN: abBaseDN
|
||||
attributes: attributes];
|
||||
[entry autorelease];
|
||||
[attributes release];
|
||||
NS_DURING
|
||||
{
|
||||
[ldapConnection addEntry: entry];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self errorWithFormat: @"failed to create ou=addressbooks"
|
||||
@" entry for user"];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
}
|
||||
}
|
||||
else
|
||||
sources = nil;
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
- (NSException *) addAddressBookSource: (NSString *) newId
|
||||
withDisplayName: (NSString *) newDisplayName
|
||||
forUser: (NSString *) user
|
||||
{
|
||||
NSException *result;
|
||||
NSString *abDN;
|
||||
NGLdapConnection *ldapConnection;
|
||||
NSArray *attributes;
|
||||
NGLdapEntry *entry;
|
||||
NSMutableDictionary *entryRecord;
|
||||
|
||||
if ([self hasUserAddressBooks])
|
||||
{
|
||||
abDN = [NSString stringWithFormat: @"ou=%@,ou=%@,%@=%@,%@",
|
||||
newId, abOU, IDField, user, baseDN];
|
||||
entryRecord = [NSMutableDictionary dictionary];
|
||||
[entryRecord setObject: @"organizationalUnit" forKey: @"objectclass"];
|
||||
[entryRecord setObject: newId forKey: @"ou"];
|
||||
if ([newDisplayName length] > 0)
|
||||
[entryRecord setObject: newDisplayName forKey: @"description"];
|
||||
ldapConnection = [self _ldapConnection];
|
||||
attributes = _convertRecordToLDAPAttributes (schema, entryRecord);
|
||||
entry = [[NGLdapEntry alloc] initWithDN: abDN
|
||||
attributes: attributes];
|
||||
[entry autorelease];
|
||||
[attributes release];
|
||||
NS_DURING
|
||||
{
|
||||
[ldapConnection addEntry: entry];
|
||||
result = nil;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self errorWithFormat: @"failed to create addressbook entry"];
|
||||
result = localException;
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
}
|
||||
else
|
||||
result = [NSException exceptionWithName: @"LDAPSourceIOException"
|
||||
reason: @"user addressbooks"
|
||||
@" are not supported"
|
||||
userInfo: nil];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSException *) renameAddressBookSource: (NSString *) newId
|
||||
withDisplayName: (NSString *) newDisplayName
|
||||
forUser: (NSString *) user
|
||||
{
|
||||
NSException *result;
|
||||
NSString *abDN;
|
||||
NGLdapConnection *ldapConnection;
|
||||
NSArray *attributes, *changes;
|
||||
NSMutableDictionary *entryRecord;
|
||||
|
||||
if ([self hasUserAddressBooks])
|
||||
{
|
||||
abDN = [NSString stringWithFormat: @"ou=%@,ou=%@,%@=%@,%@",
|
||||
newId, abOU, IDField, user, baseDN];
|
||||
entryRecord = [NSMutableDictionary dictionary];
|
||||
[entryRecord setObject: @"organizationalUnit" forKey: @"objectclass"];
|
||||
[entryRecord setObject: newId forKey: @"ou"];
|
||||
if ([newDisplayName length] > 0)
|
||||
[entryRecord setObject: newDisplayName forKey: @"description"];
|
||||
ldapConnection = [self _ldapConnection];
|
||||
attributes = _convertRecordToLDAPAttributes (schema, entryRecord);
|
||||
changes = _makeLDAPChanges (ldapConnection, abDN, attributes);
|
||||
[attributes release];
|
||||
NS_DURING
|
||||
{
|
||||
[ldapConnection modifyEntryWithDN: abDN
|
||||
changes: changes];
|
||||
result = nil;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self errorWithFormat: @"failed to rename addressbook entry"];
|
||||
result = localException;
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
}
|
||||
else
|
||||
result = [NSException exceptionWithName: @"LDAPSourceIOException"
|
||||
reason: @"user addressbooks"
|
||||
@" are not supported"
|
||||
userInfo: nil];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSException *) removeAddressBookSource: (NSString *) newId
|
||||
forUser: (NSString *) user
|
||||
{
|
||||
NSException *result;
|
||||
NSString *abDN;
|
||||
NGLdapConnection *ldapConnection;
|
||||
NSEnumerator *entries;
|
||||
NGLdapEntry *entry;
|
||||
|
||||
if ([self hasUserAddressBooks])
|
||||
{
|
||||
abDN = [NSString stringWithFormat: @"ou=%@,ou=%@,%@=%@,%@",
|
||||
newId, abOU, IDField, user, baseDN];
|
||||
ldapConnection = [self _ldapConnection];
|
||||
NS_DURING
|
||||
{
|
||||
/* we must remove the ab sub=entries prior to the ab entry */
|
||||
entries = [ldapConnection flatSearchAtBaseDN: abDN
|
||||
qualifier: nil
|
||||
attributes: nil];
|
||||
while ((entry = [entries nextObject]))
|
||||
[ldapConnection removeEntryWithDN: [entry dn]];
|
||||
[ldapConnection removeEntryWithDN: abDN];
|
||||
result = nil;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self errorWithFormat: @"failed to remove addressbook entry"];
|
||||
result = localException;
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
}
|
||||
else
|
||||
result = [NSException exceptionWithName: @"LDAPSourceIOException"
|
||||
reason: @"user addressbooks"
|
||||
@" are not supported"
|
||||
userInfo: nil];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#import "SOGoObject.h"
|
||||
|
||||
@class NSString;
|
||||
|
||||
@interface SOGoFolder : SOGoObject
|
||||
{
|
||||
NSMutableString *displayName;
|
||||
@@ -55,6 +57,9 @@
|
||||
/* outlook */
|
||||
- (NSString *) outlookFolderClass;
|
||||
|
||||
/* email advisories */
|
||||
- (void) sendFolderAdvisoryTemplate: (NSString *) template;
|
||||
|
||||
@end
|
||||
|
||||
@interface SOGoFolder (GroupDAVExtensions)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#import <Foundation/NSURL.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGObjWeb/WOApplication.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/SoWebDAVValue.h>
|
||||
@@ -37,12 +38,16 @@
|
||||
|
||||
#import <SaxObjC/XMLNamespaces.h>
|
||||
|
||||
#import <SOGoUI/SOGoFolderAdvisory.h>
|
||||
|
||||
#import "DOMNode+SOGo.h"
|
||||
#import "NSArray+Utilities.h"
|
||||
#import "NSObject+DAV.h"
|
||||
#import "NSString+DAV.h"
|
||||
#import "NSString+Utilities.h"
|
||||
#import "SOGoPermissions.h"
|
||||
#import "SOGoUser.h"
|
||||
#import "SOGoDomainDefaults.h"
|
||||
#import "SOGoWebDAVAclManager.h"
|
||||
#import "WORequest+SOGo.h"
|
||||
#import "WOResponse+SOGo.h"
|
||||
@@ -248,6 +253,30 @@
|
||||
return comparison;
|
||||
}
|
||||
|
||||
/* email advisories */
|
||||
|
||||
- (void) sendFolderAdvisoryTemplate: (NSString *) template
|
||||
{
|
||||
NSString *pageName;
|
||||
SOGoUser *user;
|
||||
SOGoFolderAdvisory *page;
|
||||
NSString *language;
|
||||
|
||||
user = [SOGoUser userWithLogin: [self ownerInContext: context]];
|
||||
if ([[user domainDefaults] foldersSendEMailNotifications])
|
||||
{
|
||||
language = [[user userDefaults] language];
|
||||
pageName = [NSString stringWithFormat: @"SOGoFolder%@%@Advisory",
|
||||
language, template];
|
||||
|
||||
page = [[WOApplication application] pageWithName: pageName
|
||||
inContext: context];
|
||||
[page setFolderObject: self];
|
||||
[page setRecipientUID: [user login]];
|
||||
[page send];
|
||||
}
|
||||
}
|
||||
|
||||
/* WebDAV */
|
||||
|
||||
- (NSString *) davEntityTag
|
||||
|
||||
@@ -118,9 +118,6 @@
|
||||
- (void) removeAclsForUsers: (NSArray *) users
|
||||
forObjectAtPath: (NSArray *) objectPathArray;
|
||||
|
||||
/* advisories */
|
||||
- (void) sendFolderAdvisoryTemplate: (NSString *) template;
|
||||
|
||||
/* DAV */
|
||||
- (NSURL *) publicDavURL;
|
||||
- (NSURL *) realDavURL;
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
#import <GDLContentStore/GCSFolder.h>
|
||||
#import <GDLContentStore/NSURL+GCS.h>
|
||||
#import <SaxObjC/XMLNamespaces.h>
|
||||
#import <SOGoUI/SOGoFolderAdvisory.h>
|
||||
|
||||
#import "NSDictionary+Utilities.h"
|
||||
#import "NSArray+Utilities.h"
|
||||
@@ -500,28 +499,6 @@ static NSArray *childRecordFields = nil;
|
||||
return folder;
|
||||
}
|
||||
|
||||
- (void) sendFolderAdvisoryTemplate: (NSString *) template
|
||||
{
|
||||
NSString *pageName;
|
||||
SOGoUser *user;
|
||||
SOGoFolderAdvisory *page;
|
||||
NSString *language;
|
||||
|
||||
user = [SOGoUser userWithLogin: [self ownerInContext: context]];
|
||||
if ([[user domainDefaults] foldersSendEMailNotifications])
|
||||
{
|
||||
language = [[user userDefaults] language];
|
||||
pageName = [NSString stringWithFormat: @"SOGoFolder%@%@Advisory",
|
||||
language, template];
|
||||
|
||||
page = [[WOApplication application] pageWithName: pageName
|
||||
inContext: context];
|
||||
[page setFolderObject: self];
|
||||
[page setRecipientUID: [user login]];
|
||||
[page send];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) create
|
||||
{
|
||||
NSException *result;
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
- (NSString *) defaultFolderName;
|
||||
|
||||
- (NSException *) appendPersonalSources;
|
||||
|
||||
- (void) setBaseOCSPath: (NSString *) newOCSPath;
|
||||
|
||||
- (NSArray *) toManyRelationshipKeys;
|
||||
|
||||
@@ -183,7 +183,6 @@ static SoSecurityManager *sm = nil;
|
||||
SOGoGCSFolder *folder;
|
||||
NSString *key;
|
||||
NSException *error;
|
||||
SOGoUser *currentUser;
|
||||
|
||||
if (!subFolderClass)
|
||||
subFolderClass = [[self class] subFolderClass];
|
||||
@@ -191,8 +190,6 @@ static SoSecurityManager *sm = nil;
|
||||
error = [fc evaluateExpressionX: sql];
|
||||
if (!error)
|
||||
{
|
||||
currentUser = [context activeUser];
|
||||
|
||||
attrs = [fc describeResults: NO];
|
||||
while ((row = [fc fetchAttributes: attrs withZone: NULL]))
|
||||
{
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
|
||||
- (NSString *) domain;
|
||||
|
||||
/* requires a "." to obtain the full list of contacts */
|
||||
- (void) setListRequiresDot: (BOOL) aBool;
|
||||
- (BOOL) listRequiresDot;
|
||||
|
||||
- (BOOL) checkLogin: (NSString *) _login
|
||||
password: (NSString *) _pwd
|
||||
perr: (SOGoPasswordPolicyError *) _perr
|
||||
@@ -57,14 +61,36 @@
|
||||
|
||||
- (NSArray *) allEntryIDs;
|
||||
- (NSArray *) fetchContactsMatching: (NSString *) filter;
|
||||
|
||||
- (void) setSourceID: (NSString *) newSourceID;
|
||||
- (NSString *) sourceID;
|
||||
|
||||
- (void) setDisplayName: (NSString *) newDisplayName;
|
||||
- (NSString *) displayName;
|
||||
|
||||
- (void) setModifiers: (NSArray *) newModifiers;
|
||||
- (NSArray *) modifiers;
|
||||
|
||||
- (BOOL) hasUserAddressBooks;
|
||||
- (NSArray *) addressBookSourcesForUser: (NSString *) user;
|
||||
|
||||
- (NSException *) addContactEntry: (NSDictionary *) roLdifRecord
|
||||
withID: (NSString *) aId;
|
||||
- (NSException *) updateContactEntry: (NSDictionary *) ldifRecord;
|
||||
- (NSException *) removeContactEntryWithID: (NSString *) aId;
|
||||
|
||||
/* user address books */
|
||||
- (NSArray *) addressBookSourcesForUser: (NSString *) user;
|
||||
|
||||
- (NSException *) addAddressBookSource: (NSString *) newId
|
||||
withDisplayName: (NSString *) newDisplayName
|
||||
forUser: (NSString *) user;
|
||||
- (NSException *) renameAddressBookSource: (NSString *) newId
|
||||
withDisplayName: (NSString *) newDisplayName
|
||||
forUser: (NSString *) user;
|
||||
- (NSException *) removeAddressBookSource: (NSString *) newId
|
||||
forUser: (NSString *) user;
|
||||
|
||||
@end
|
||||
|
||||
@protocol SOGoDNSource <SOGoSource>
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
@class SOGoUserProfile;
|
||||
@class SOGoUserSettings;
|
||||
|
||||
@protocol SOGoSource;
|
||||
|
||||
@interface SOGoUser : SoUser
|
||||
{
|
||||
SOGoUserDefaults *_defaults;
|
||||
@@ -88,6 +90,7 @@
|
||||
|
||||
/* properties */
|
||||
- (NSString *) domain;
|
||||
- (id <SOGoSource>) authenticationSource;
|
||||
|
||||
- (NSArray *) allEmails;
|
||||
- (BOOL) hasEmail: (NSString *) email;
|
||||
|
||||
@@ -287,6 +287,17 @@
|
||||
return [self _fetchFieldForUser: @"c_domain"];
|
||||
}
|
||||
|
||||
- (id <SOGoSource>) authenticationSource
|
||||
{
|
||||
NSString *sourceID;
|
||||
SOGoUserManager *um;
|
||||
|
||||
sourceID = [self _fetchFieldForUser: @"SOGoSource"];
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
|
||||
return [um sourceWithID: sourceID];
|
||||
}
|
||||
|
||||
- (NSArray *) allEmails
|
||||
{
|
||||
if (!allEmails)
|
||||
|
||||
@@ -573,7 +573,7 @@
|
||||
NSMutableArray *emails;
|
||||
NSDictionary *userEntry;
|
||||
NSEnumerator *sogoSources;
|
||||
NSObject <SOGoDNSource> *currentSource;
|
||||
NSObject <SOGoSource> *currentSource;
|
||||
NSString *sourceID, *cn, *c_domain, *c_uid, *c_imaphostname, *c_imaplogin;
|
||||
NSArray *c_emails;
|
||||
BOOL access;
|
||||
@@ -592,12 +592,14 @@
|
||||
|
||||
sogoSources = [[self authenticationSourceIDsInDomain: domain]
|
||||
objectEnumerator];
|
||||
while ((sourceID = [sogoSources nextObject]))
|
||||
userEntry = nil;
|
||||
while (!userEntry && (sourceID = [sogoSources nextObject]))
|
||||
{
|
||||
currentSource = [_sources objectForKey: sourceID];
|
||||
userEntry = [currentSource lookupContactEntryWithUIDorEmail: uid];
|
||||
if (userEntry)
|
||||
{
|
||||
[currentUser setObject: sourceID forKey: @"SOGoSource"];
|
||||
if (!cn)
|
||||
cn = [userEntry objectForKey: @"c_cn"];
|
||||
if (!c_uid)
|
||||
|
||||
@@ -691,13 +691,46 @@
|
||||
return results;
|
||||
}
|
||||
|
||||
- (void) setSourceID: (NSString *) newSourceID
|
||||
{
|
||||
}
|
||||
|
||||
- (NSString *) sourceID
|
||||
{
|
||||
return _sourceID;
|
||||
}
|
||||
|
||||
- (void) setDisplayName: (NSString *) newDisplayName
|
||||
{
|
||||
}
|
||||
|
||||
- (NSString *) displayName
|
||||
{
|
||||
/* This method is only used when supporting user "source" addressbooks,
|
||||
which is only supported by the LDAP backend for now. */
|
||||
return _sourceID;
|
||||
}
|
||||
|
||||
- (void) setListRequiresDot: (BOOL) newListRequiresDot
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL) listRequiresDot
|
||||
{
|
||||
/* This method is not implemented for SQLSource. It must enable a mechanism
|
||||
where using "." is not required to list the content of addressbooks. */
|
||||
return YES;
|
||||
}
|
||||
|
||||
/* card editing */
|
||||
- (void) setModifiers: (NSArray *) newModifiers
|
||||
{
|
||||
}
|
||||
|
||||
- (NSArray *) modifiers
|
||||
{
|
||||
/* This method is only used when supporting card editing,
|
||||
which is only supported by the LDAP backend for now. */
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -741,4 +774,59 @@
|
||||
userInfo: nil];
|
||||
}
|
||||
|
||||
/* user addressbooks */
|
||||
- (BOOL) hasUserAddressBooks
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSArray *) addressBookSourcesForUser: (NSString *) user
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSException *) addAddressBookSource: (NSString *) newId
|
||||
withDisplayName: (NSString *) newDisplayName
|
||||
forUser: (NSString *) user
|
||||
{
|
||||
NSString *reason;
|
||||
|
||||
reason = [NSString stringWithFormat: @"method '%@' is not available"
|
||||
@" for class '%@'", NSStringFromSelector (_cmd),
|
||||
NSStringFromClass (isa)];
|
||||
|
||||
return [NSException exceptionWithName: @"SQLSourceIOException"
|
||||
reason: reason
|
||||
userInfo: nil];
|
||||
}
|
||||
|
||||
- (NSException *) renameAddressBookSource: (NSString *) newId
|
||||
withDisplayName: (NSString *) newDisplayName
|
||||
forUser: (NSString *) user
|
||||
{
|
||||
NSString *reason;
|
||||
|
||||
reason = [NSString stringWithFormat: @"method '%@' is not available"
|
||||
@" for class '%@'", NSStringFromSelector (_cmd),
|
||||
NSStringFromClass (isa)];
|
||||
|
||||
return [NSException exceptionWithName: @"SQLSourceIOException"
|
||||
reason: reason
|
||||
userInfo: nil];
|
||||
}
|
||||
|
||||
- (NSException *) removeAddressBookSource: (NSString *) newId
|
||||
forUser: (NSString *) user
|
||||
{
|
||||
NSString *reason;
|
||||
|
||||
reason = [NSString stringWithFormat: @"method '%@' is not available"
|
||||
@" for class '%@'", NSStringFromSelector (_cmd),
|
||||
NSStringFromClass (isa)];
|
||||
|
||||
return [NSException exceptionWithName: @"SQLSourceIOException"
|
||||
reason: reason
|
||||
userInfo: nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -52,8 +52,16 @@
|
||||
|
||||
#import "UIxContactFoldersView.h"
|
||||
|
||||
Class SOGoContactSourceFolderK, SOGoGCSFolderK;
|
||||
|
||||
@implementation UIxContactFoldersView
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
SOGoContactSourceFolderK = [SOGoContactSourceFolder class];
|
||||
SOGoGCSFolderK = [SOGoGCSFolder class];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
@@ -110,11 +118,13 @@
|
||||
|
||||
folders = [self clientObject];
|
||||
folder = [folders lookupPersonalFolder: @"personal" ignoringRights: YES];
|
||||
|
||||
contactInfos = [folder lookupContactsWithFilter: nil
|
||||
onCriteria: nil
|
||||
sortBy: @"c_cn"
|
||||
ordering: NSOrderedAscending];
|
||||
if (folder && [folder conformsToProtocol: @protocol (SOGoContactFolder)])
|
||||
contactInfos = [folder lookupContactsWithFilter: nil
|
||||
onCriteria: nil
|
||||
sortBy: @"c_cn"
|
||||
ordering: NSOrderedAscending];
|
||||
else
|
||||
contactInfos = nil;
|
||||
|
||||
return contactInfos;
|
||||
}
|
||||
@@ -183,7 +193,7 @@
|
||||
{
|
||||
folder = [folders objectAtIndex: i];
|
||||
/* We first search in LDAP folders (in case of duplicated entries in GCS folders) */
|
||||
if ([folder isKindOfClass: [SOGoContactSourceFolder class]])
|
||||
if ([folder isKindOfClass: SOGoContactSourceFolderK])
|
||||
[sortedFolders insertObject: folder atIndex: 0];
|
||||
else
|
||||
[sortedFolders addObject: folder];
|
||||
@@ -287,10 +297,23 @@
|
||||
|
||||
- (NSString *) currentContactFolderClass
|
||||
{
|
||||
return ([currentFolder isKindOfClass: [SOGoContactSourceFolder class]]
|
||||
return (([currentFolder isKindOfClass: SOGoContactSourceFolderK]
|
||||
&& ![currentFolder isPersonalSource])
|
||||
? @"remote" : @"local");
|
||||
}
|
||||
|
||||
- (NSString *) currentContactFolderAclEditing
|
||||
{
|
||||
return ([currentFolder isKindOfClass: SOGoGCSFolderK]
|
||||
? @"available": @"unavailable");
|
||||
}
|
||||
|
||||
- (NSString *) currentContactFolderListEditing
|
||||
{
|
||||
return ([currentFolder isKindOfClass: SOGoGCSFolderK]
|
||||
? @"available": @"unavailable");
|
||||
}
|
||||
|
||||
- (NSString *) verticalDragHandleStyle
|
||||
{
|
||||
NSString *vertical;
|
||||
|
||||
@@ -139,6 +139,11 @@
|
||||
pageName = "UIxContactEditor";
|
||||
actionName = "new";
|
||||
};
|
||||
renameFolder = {
|
||||
protectedBy = "Change Permissions";
|
||||
actionClass = "UIxFolderActions";
|
||||
actionName = "renameFolder";
|
||||
};
|
||||
mailer-contacts = {
|
||||
protectedBy = "<public>";
|
||||
pageName = "UIxContactFoldersView";
|
||||
|
||||
@@ -121,6 +121,8 @@
|
||||
><li var:id="currentContactFolderId"
|
||||
var:owner="currentContactFolderOwner"
|
||||
var:class="currentContactFolderClass"
|
||||
var:acl-editing="currentContactFolderAclEditing"
|
||||
var:list-editing="currentContactFolderListEditing"
|
||||
><var:string value="currentContactFolderName"/></li
|
||||
></var:foreach
|
||||
>
|
||||
|
||||
@@ -258,17 +258,6 @@ function onContactContextMenuHide(event) {
|
||||
this.stopObserving("contextmenu:hide", onContactContextMenuHide);
|
||||
}
|
||||
|
||||
function onFolderMenuHide(event) {
|
||||
var topNode = $('d');
|
||||
|
||||
if (topNode.menuSelectedEntry) {
|
||||
topNode.menuSelectedEntry.deselect();
|
||||
topNode.menuSelectedEntry = null;
|
||||
}
|
||||
if (topNode.selectedEntry)
|
||||
topNode.selectedEntry.selectElement();
|
||||
}
|
||||
|
||||
function _onContactMenuAction(folderItem, action, refresh) {
|
||||
var selectedFolders = $("contactFolders").getSelectedNodes();
|
||||
var folderId = $(folderItem).readAttribute("folderId");
|
||||
@@ -308,8 +297,9 @@ function onContactMenuMove(event) {
|
||||
|
||||
function onMenuExportContact (event) {
|
||||
var selectedFolders = $("contactFolders").getSelectedNodes();
|
||||
var selectedFolderId = $(selectedFolders[0]).readAttribute("id");
|
||||
if (selectedFolderId != "/shared") {
|
||||
var canExport = (selectedFolders[0].getAttribute("owner") != "nobody");
|
||||
if (canExport) {
|
||||
var selectedFolderId = $(selectedFolders[0]).readAttribute("id");
|
||||
var contactIds = $(document.menuTarget).collect(function(row) {
|
||||
return row.getAttribute("id");
|
||||
});
|
||||
@@ -599,10 +589,11 @@ function newContact(sender) {
|
||||
|
||||
function newList(sender) {
|
||||
var li = $(Contact.currentAddressBook);
|
||||
if (li.hasClassName("remote"))
|
||||
showAlertDialog(_("You cannot create a list in a shared address book."));
|
||||
else
|
||||
var listEditing = li.getAttribute("list-editing");
|
||||
if (listEditing && listEditing == "available")
|
||||
openContactWindow(URLForFolderID(Contact.currentAddressBook) + "/newlist");
|
||||
else
|
||||
showAlertDialog(_("You cannot create a list in a shared address book."));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1069,15 +1060,15 @@ function onMenuSharing(event) {
|
||||
|
||||
var folders = $("contactFolders");
|
||||
var selected = folders.getSelectedNodes()[0];
|
||||
var owner = selected.getAttribute("owner");
|
||||
if (owner == "nobody")
|
||||
showAlertDialog(_("The user rights cannot be edited for this object!"));
|
||||
else {
|
||||
var aclEditing = selected.getAttribute("acl-editing");
|
||||
if (aclEditing && aclEditing == "available") {
|
||||
var title = this.innerHTML;
|
||||
var url = URLForFolderID(selected.getAttribute("id"));
|
||||
|
||||
openAclWindow(url + "/acls", title);
|
||||
}
|
||||
else
|
||||
showAlertDialog(_("The user rights cannot be edited for this object!"));
|
||||
}
|
||||
|
||||
function onAddressBooksMenuPrepareVisibility() {
|
||||
@@ -1090,30 +1081,55 @@ function onAddressBooksMenuPrepareVisibility() {
|
||||
var menu = $("contactFoldersMenu").down("ul");;
|
||||
var listElements = menu.childNodesWithTag("li");
|
||||
var modifyOption = listElements[0];
|
||||
var newListOption = listElements[3];
|
||||
var removeOption = listElements[5];
|
||||
var exportOption = listElements[7];
|
||||
var importOption = listElements[8];
|
||||
var sharingOption = listElements[listElements.length - 1];
|
||||
|
||||
// Disable the "Sharing" and "Modify" options when address book
|
||||
// is not owned by user
|
||||
if (folderOwner == UserLogin || IsSuperUser) {
|
||||
modifyOption.removeClassName("disabled"); // WARNING: will fail for super users anyway
|
||||
sharingOption.removeClassName("disabled");
|
||||
modifyOption.removeClassName("disabled"); // WARNING: will fail
|
||||
// for super users
|
||||
// anyway
|
||||
var aclEditing = selected[0].getAttribute("acl-editing");
|
||||
if (aclEditing && aclEditing == "available") {
|
||||
sharingOption.removeClassName("disabled");
|
||||
}
|
||||
else {
|
||||
sharingOption.addClassName("disabled");
|
||||
}
|
||||
}
|
||||
else {
|
||||
modifyOption.addClassName("disabled");
|
||||
sharingOption.addClassName("disabled");
|
||||
}
|
||||
|
||||
var listEditing = selected[0].getAttribute("list-editing");
|
||||
if (listEditing && listEditing == "available") {
|
||||
newListOption.removeClassName("disabled");
|
||||
}
|
||||
else {
|
||||
newListOption.addClassName("disabled");
|
||||
}
|
||||
|
||||
/* Disable the "remove" and "export ab" options when address book is
|
||||
public */
|
||||
if (folderOwner == "nobody") {
|
||||
exportOption.addClassName("disabled");
|
||||
importOption.addClassName("disabled");
|
||||
removeOption.addClassName("disabled");
|
||||
}
|
||||
else {
|
||||
exportOption.removeClassName("disabled");
|
||||
removeOption.removeClassName("disabled");
|
||||
importOption.removeClassName("disabled");
|
||||
if (selected[0].getAttribute("id") == "/personal") {
|
||||
removeOption.addClassName("disabled");
|
||||
}
|
||||
else {
|
||||
removeOption.removeClassName("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user