+2007-06-01 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/SOGo/SOGoObject.m ([SOGoObject
+ -_urlPreferringParticle:expectedoverThisOne:possible]): unescape
+ the result of [self baseURLInContext:] to avoid a double escaping
+ in the resulting string.
+
+ * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder -aclsForUser:uid]): if
+ the user has the "ObjectReader" role on the parent container, then
+ he is granted the "ObjectViewer" role on this object. Same for
+ "ObjectEraser", although this might change later.
+
+ * UI/Scheduler/UIxComponentEditor.m ([UIxComponentEditor
+ -toolbar]): determine the toolbar filename based on the
+ permissions declared by the securitymanager. The role mechanism
+ has been adjusted on a lowerlevel so we can simplify the code.
+
+ * SoObjects/SOGo/SOGoContentObject.m ([SOGoContentObject
+ -initWithName:newNameinContainer:newContainer]): read the content
+ directly from here. That way we can determine whether the object
+ is being created.
+ ([SOGoContentObject -aclsForUser:uid]): if the object is new and
+ the ObjectCreator role is enabled, we also grant the ObjectEditor
+ role to the current user.
+
+ * UI/Common/UIxFolderActions.m ([-canAccessContentAction]):
+ changed the method paradigm to only return HTTP code 204. Not test
+ is done whatsoever since the security manager does it for us.
+
+ * UI/Contacts/UIxContactsListView.m ([-canAccessContentAction]):
+ removed method because the same exists in UIxFolderActions.m
+
+ * UI/Contacts/UIxContactsUserRightsEditor.m
+ ([UIxContactsUserRightsEditor
+ -setUserCanReadObjects:userCanReadObjects]): new method.
+
+ * SoObjects/SOGo/SOGoPermissions.m: added roles "FolderViewer" and
+ "FolderEraser" and special permission "Access Object". Removed
+ role "SOGoMailRole_MessageEraser" since "SOGoRole_ObjectEraser"
+ can be used instead. Removed "FolderReader" since it is useless.
+
+ * SoObjects/Contacts/SOGoContactGCSEntry.m ([SOGoContactGCSEntry
+ -vCard]): directly use the "content" ivar since it is initialized
+ during object creation.
+
+ * SoObjects/Contacts/SOGoContactLDAPFolder.m
+ ([SOGoContactLDAPFolder -init]): no longer handle the
+ nameInContainer no the container ivars. They were removed because
+ this class is a descendant of SOGoObject which already has them.
+ ([SOGoContactLDAPFolder -davDisplayName]): new overriden method
+ returning "displayName".
+ ([SOGoContactLDAPFolder -isFolderish]): new overriden method
+ returning "YES".
+
+ * SoObjects/Appointments/SOGoCalendarComponent.m
+ ([SOGoCalendarComponent -isOrganizerOrOwner:user]): commented out.
+ ([SOGoCalendarComponent -findParticipant:user]): new name for
+ method "participant:".
+ ([SOGoCalendarComponent -findParticipantWithUID:uid]): same as
+ findparticipant but taking a uid string as parameter.
+ ([SOGoCalendarComponent -contentAsString]): don't regenerate the
+ iCalendar automatically. Instead, this is done only when the user
+ is a "date and time viewer".
+ ([SOGoCalendarComponent -aclsForUser:uid]): take delegation roles
+ (modifier and responder) into account by compiling them with the
+ owner's roles.
+
+ * SoObjects/Contacts/SOGoContactFolder.h: removed
+ "nameInContainer" from the list of required methods.
+
+ * SoObjects/Appointments/SOGoFreeBusyObject.m ([SOGoFreeBusyObject
+ -davContentType]): returns "text/calendar".
+
+ * SoObjects/Contacts/SOGoContactLDAPFolder.m
+ ([SOGoContactLDAPFolder -davResourceType]): declare the correct
+ groupdav resource-type.
+
+ * SoObjects/Contacts/SOGoContactFolders.m ([SOGoContactFolders
+ -davContentType]): same as below.
+
+ * SoObjects/Mailer/SOGoMailFolder.m ([SOGoMailFolder
+ -initWithName:newNameinContainer:newContainer]): new overriden
+ method setting the custom owner directly.
+
+ * SoObjects/Mailer/SOGoMailAccounts.m ([SOGoMailAccounts
+ -davContentType]): same as below.
+
+ * SoObjects/Mailer/SOGoMailAccount.m ([SOGoMailAccount
+ -davContentType]): same as below.
+
+ * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder -davContentType]):
+ declare "httpd/unix-directory".
+
+ * SoObjects/SOGo/SOGoUser.m ([SOGoUser +initialize]): declare
+ "UTC" as fallback timezone instead of "Canada/Eastern".
+ ([-hasEmail:email]): make use of the new NSArray's
+ containsCaseInsensitiveString: method.
+
+ * SoObjects/Mailer/SOGoMailObject.m ([SOGoMailObject
+ -davContentType]): declare "message/rfc822" as content type.
+
+ * SoObjects/Appointments/SOGoAppointmentFolder.m
+ ([SOGoAppointmentFolder -_privacySqlString]): "owner" is now an
+ ivar in SOGoObject.
+ ([SOGoAppointmentFolder
+ -fetchFields:_fieldsfromFolder:_folderfrom:_startDateto:_endDatecomponent:_component]): same as above.
+ ([-fetchContentObjectNames]): commented out method since it was
+ usefull only for testing Funambol.
+
+ * SoObjects/SOGo/NSArray+Utilities.m ([NSArray
+ -containsCaseInsensitiveString:match]): an enhanced version of
+ containsObject:.
+
+ * UI/MailerUI/UIxMailView.m ([-isTrashingAllowed]): removed
+ useless method.
+ ([-showMarkDeletedButton]): removed useless method.
+ ([-showTrashButton]): removed useless method.
+
+ * SoObjects/Appointments/iCalEntityObject+SOGo.m
+ ([iCalEntityObject -userIsParticipant:user]): new proxy method
+ that invoked isParticipant on self for each possible email
+ addresses of the user passed as parameter.
+ ([iCalEntityObject -userIsOrganizer:user]): same as above.
+
+ * SoObjects/Appointments/iCalEntityObject+SOGo.[hm]: new class
+ extension module.
+
+ * SoObjects/Appointments/SOGoAppointmentObject.m
+ ([SOGoAppointmentObject
+ -saveContentString:contentStringbaseVersion:baseVersion]): remove
+ method since an event may not have an organizer.
+
+ * SoObjects/SOGo/SOGoObject.m ([SOGoObject
+ -GETAction:localContext]): clarified method. Added support for
+ content-type (thanks to Helge Hess).
+ ([SOGoObject -initWithName:_nameinContainer:_container]):
+ initialize and retain the owner.
+ ([SOGoObject -davContentType]): returns "text/plain".
+
2007-05-30 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/Common/UIxObjectActions.m ([UIxObjectActions
return list;
}
-- (BOOL) isOrganizer: (id)_email
+- (BOOL) isOrganizer: (id) _email
{
- _email = [_email lowercaseString];
+ NSString *organizerMail;
+
+ organizerMail = [[self organizer] rfc822Email];
- return [[[[self organizer] rfc822Email] lowercaseString]
- isEqualToString:_email];
+ return [[organizerMail lowercaseString]
+ isEqualToString: [_email lowercaseString]];
}
- (BOOL) isParticipant: (id) _email
Appointments_OBJC_FILES = \
Product.m \
NSArray+Appointments.m \
+ iCalEntityObject+SOGo.m \
\
SOGoCalendarComponent.m \
SOGoAppointmentObject.m \
- (NSString *) _privacySqlString
{
- NSString *privacySqlString, *owner, *login, *email;
+ NSString *privacySqlString, *login, *email;
SOGoUser *activeUser;
activeUser = [context activeUser];
login = [activeUser login];
- owner = [self ownerInContext: context];
if ([login isEqualToString: owner])
privacySqlString = @"";
EOQualifier *qualifier;
NSMutableArray *fields, *ma = nil;
NSArray *records;
- NSString *sql, *dateSqlString, *componentSqlString, *privacySqlString; /* , *owner; */
+ NSString *sql, *dateSqlString, *componentSqlString, *privacySqlString;
NGCalendarDateRange *r;
if (_folder == nil) {
if (!ma)
ma = [NSMutableArray arrayWithCapacity: [records count]];
-// owner = [self ownerInContext: nil];
[ma addObjectsFromArray: records];
}
else if (!ma)
return nil;
url = [self baseURLInContext:_ctx];
- if (![url hasSuffix:@"/"])
- url = [url stringByAppendingString:@"/"];
+ if (![url hasSuffix: @"/"])
+ url = [url stringByAppendingString: @"/"];
// TODO: this should run a query to determine the uid!
return [url stringByAppendingString:_uid];
if (![_uid isNotNull])
return nil;
-
+
/* create subcontext, so that we don't destroy our environment */
if ((ctx = [context createSubContext]) == nil) {
result = [[ctx application] traversePathArray:path inContext:ctx
error:&error acquire:NO];
if (error != nil) {
- [self errorWithFormat:@"folder lookup failed (uid=%@): %@",
+ [self errorWithFormat: @"folder lookup failed (uid=%@): %@",
_uid, error];
return nil;
}
return calendarFolders;
}
-- (NSArray *) fetchContentObjectNames
-{
- NSMutableArray *objectNames;
- NSArray *records;
- NSCalendarDate *today, *startDate, *endDate;
-
-#warning this should be user-configurable
- objectNames = [NSMutableArray array];
- today = [[NSCalendarDate calendarDate] beginOfDay];
- [today setTimeZone: timeZone];
-
- startDate = [today dateByAddingYears: 0 months: 0 days: -1
- hours: 0 minutes: 0 seconds: 0];
- endDate = [startDate dateByAddingYears: 0 months: 0 days: 2
- hours: 0 minutes: 0 seconds: 0];
- records = [self fetchFields: [NSArray arrayWithObject: @"c_name"]
- from: startDate to: endDate
- component: @"vevent"];
- [objectNames addObjectsFromArray: [records valueForKey: @"c_name"]];
- records = [self fetchFields: [NSArray arrayWithObject: @"c_name"]
- from: startDate to: endDate
- component: @"vtodo"];
- [objectNames addObjectsFromArray: [records valueForKey: @"c_name"]];
-
- return objectNames;
-}
+// - (NSArray *) fetchContentObjectNames
+// {
+// NSMutableArray *objectNames;
+// NSArray *records;
+// NSCalendarDate *today, *startDate, *endDate;
+
+// #warning this should be user-configurable
+// objectNames = [NSMutableArray array];
+// today = [[NSCalendarDate calendarDate] beginOfDay];
+// [today setTimeZone: timeZone];
+
+// startDate = [today dateByAddingYears: 0 months: 0 days: -1
+// hours: 0 minutes: 0 seconds: 0];
+// endDate = [startDate dateByAddingYears: 0 months: 0 days: 2
+// hours: 0 minutes: 0 seconds: 0];
+// records = [self fetchFields: [NSArray arrayWithObject: @"c_name"]
+// from: startDate to: endDate
+// component: @"vevent"];
+// [objectNames addObjectsFromArray: [records valueForKey: @"c_name"]];
+// records = [self fetchFields: [NSArray arrayWithObject: @"c_name"]
+// from: startDate to: endDate
+// component: @"vtodo"];
+// [objectNames addObjectsFromArray: [records valueForKey: @"c_name"]];
+
+// return objectNames;
+// }
/* folder type */
/* perform */
- return [self deleteInUIDs:removedUIDs];
+ return [self deleteInUIDs: removedUIDs];
}
- (NSException *) saveContentString: (NSString *) _iCalString
return @"IPM.Appointment";
}
-- (NSException *) saveContentString: (NSString *) contentString
- baseVersion: (unsigned int) baseVersion
-{
- NSString *newContentString, *oldContentString;
- iCalCalendar *eventCalendar;
- iCalEvent *event;
- iCalPerson *organizer;
- NSArray *organizers;
-
- oldContentString = [self contentAsString];
- if (oldContentString)
- newContentString = contentString;
- else
- {
- eventCalendar = [iCalCalendar parseSingleFromSource: contentString];
- event = (iCalEvent *) [eventCalendar firstChildWithTag: [self componentTag]];
- organizers = [event childrenWithTag: @"organizer"];
- if ([organizers count])
- newContentString = contentString;
- else
- {
- organizer = [self iCalPersonWithUID: [self ownerInContext: context]];
- [event setOrganizer: organizer];
- newContentString = [eventCalendar versitString];
- }
- }
-
- return [super saveContentString: newContentString
- baseVersion: baseVersion];
-}
-
@end /* SOGoAppointmentObject */
andNewObject: (iCalRepeatableEntityObject *) _newObject
toAttendees: (NSArray *) _attendees;
-- (BOOL) isOrganizerOrOwner: (SOGoUser *) user;
-- (iCalPerson *) participant: (SOGoUser *) user;
+// - (BOOL) isOrganizerOrOwner: (SOGoUser *) user;
+
+- (iCalPerson *) findParticipant: (SOGoUser *) user;
+- (iCalPerson *) findParticipantWithUID: (NSString *) uid;
- (iCalPerson *) iCalPersonWithUID: (NSString *) uid;
- (NSString *) getUIDForICalPerson: (iCalPerson *) person;
#import "common.h"
#import "SOGoAptMailNotification.h"
+#import "iCalEntityObject+SOGo.h"
#import "SOGoCalendarComponent.h"
static NSString *mailTemplateDefaultLanguage = nil;
- (NSString *) contentAsString
{
- NSString *tmpContent, *email, *uid, *role;
+ NSString *uid;
iCalCalendar *tmpCalendar;
iCalRepeatableEntityObject *tmpComponent;
+ NSArray *roles;
if (!calContent)
{
- tmpContent = [super contentAsString];
- calContent = tmpContent;
uid = [[context activeUser] login];
- if (![[self ownerInContext: context] isEqualToString: uid]
- && [tmpContent length] > 0)
- {
- tmpCalendar = [iCalCalendar parseSingleFromSource: tmpContent];
- tmpComponent = (iCalRepeatableEntityObject *)
+ roles = [self aclsForUser: uid];
+ if ([roles containsObject: SOGoCalendarRole_Organizer]
+ || [roles containsObject: SOGoCalendarRole_Participant]
+ || [roles containsObject: SOGoCalendarRole_ComponentViewer])
+ {
+ calContent = content;
+ [calContent retain];
+ }
+ else if ([roles containsObject: SOGoCalendarRole_ComponentDAndTViewer])
+ {
+ tmpCalendar = [[self calendar: NO] copy];
+ tmpComponent = (iCalRepeatableEntityObject *)
[tmpCalendar firstChildWithTag: [self componentTag]];
- email = [[context activeUser] primaryEmail];
- if (!([tmpComponent isOrganizer: email]
- || [tmpComponent isParticipant: email]))
- {
- role = [container roleForComponentsWithAccessClass: [tmpComponent symbolicAccessClass]
- forUser: uid];
- if ([role length] > 0)
- {
- if ([role isEqualToString: SOGoCalendarPerm_ViewDAndT])
- {
- // content = tmpContent;
- [self _filterComponent: tmpComponent];
- calContent = [tmpCalendar versitString];
- }
- }
- else
- calContent = nil;
- }
- }
+ [self _filterComponent: tmpComponent];
+ calContent = [tmpCalendar versitString];
+ [tmpCalendar release];
+ }
+ else
+ calContent = nil;
[calContent retain];
}
if (!calendar)
{
- iCalString = [self contentAsString];
+ iCalString = [super contentAsString];
if ([iCalString length] > 0)
calendar = [iCalCalendar parseSingleFromSource: iCalString];
else
- (NSException *) changeParticipationStatus: (NSString *) _status
{
iCalRepeatableEntityObject *component;
- iCalPerson *p;
+ iCalPerson *person;
NSString *newContent;
NSException *ex;
NSString *myEMail;
if (component)
{
myEMail = [[context activeUser] primaryEmail];
- p = [component findParticipantWithEmail: myEMail];
- if (p)
+ person = [self findParticipantWithUID: owner];
+ if (person)
{
// TODO: send iMIP reply mails?
- [p setPartStat: _status];
+ [person setPartStat: _status];
newContent = [[component parent] versitString];
if (newContent)
{
- ex = [self saveContentString:newContent];
+ ex = [self saveContentString: newContent];
if (ex)
// TODO: why is the exception wrapped?
/* Server Error */
}
}
-- (BOOL) isOrganizerOrOwner: (SOGoUser *) user
+// - (BOOL) isOrganizerOrOwner: (SOGoUser *) user
+// {
+// BOOL isOrganizerOrOwner;
+// iCalRepeatableEntityObject *component;
+// NSString *organizerEmail;
+
+// component = [self component: NO];
+// organizerEmail = [[component organizer] rfc822Email];
+// if (component && [organizerEmail length] > 0)
+// isOrganizerOrOwner = [user hasEmail: organizerEmail];
+// else
+// isOrganizerOrOwner
+// = [[container ownerInContext: context] isEqualToString: [user login]];
+
+// return isOrganizerOrOwner;
+// }
+
+- (iCalPerson *) findParticipantWithUID: (NSString *) uid
{
- BOOL isOrganizerOrOwner;
- iCalRepeatableEntityObject *component;
- NSString *organizerEmail;
+ SOGoUser *user;
- component = [self component: NO];
- organizerEmail = [[component organizer] rfc822Email];
- if (component && [organizerEmail length] > 0)
- isOrganizerOrOwner = [user hasEmail: organizerEmail];
- else
- isOrganizerOrOwner
- = [[container ownerInContext: context] isEqualToString: [user login]];
+ user = [SOGoUser userWithLogin: uid roles: nil];
- return isOrganizerOrOwner;
+ return [self findParticipant: user];
}
-- (iCalPerson *) participant: (SOGoUser *) user
+- (iCalPerson *) findParticipant: (SOGoUser *) user
{
iCalPerson *participant, *currentParticipant;
iCalEntityObject *component;
return uids;
}
+- (NSString *) _roleOfOwner: (iCalRepeatableEntityObject *) component
+{
+ NSString *role;
+ iCalPerson *organizer;
+ SOGoUser *ownerUser;
+
+ if (component)
+ {
+ organizer = [component organizer];
+ if ([[organizer rfc822Email] length] > 0)
+ {
+ ownerUser = [SOGoUser userWithLogin: owner roles: nil];
+ if ([component userIsOrganizer: ownerUser])
+ role = SOGoCalendarRole_Organizer;
+ else if ([component userIsParticipant: ownerUser])
+ role = SOGoCalendarRole_Participant;
+ else
+ role = SOGoRole_None;
+ }
+ else
+ role = SOGoCalendarRole_Organizer;
+ }
+ else
+ role = SOGoCalendarRole_Organizer;
+
+ return role;
+}
+
+- (NSString *) _compiledRoleForOwner: (NSString *) ownerRole
+ andUser: (NSString *) userRole
+{
+ NSString *role;
+
+ if ([userRole isEqualToString: SOGoCalendarRole_ComponentModifier]
+ || ([userRole isEqualToString: SOGoCalendarRole_ComponentResponder]
+ && [ownerRole isEqualToString: SOGoCalendarRole_Participant]))
+ role = ownerRole;
+ else
+ role = SOGoRole_None;
+
+ return role;
+}
+
- (NSArray *) aclsForUser: (NSString *) uid
{
NSMutableArray *roles;
NSArray *superAcls;
iCalRepeatableEntityObject *component;
- NSString *email, *accessRole;
+ NSString *accessRole, *ownerRole;
roles = [NSMutableArray array];
+ superAcls = [super aclsForUser: uid];
+ if ([superAcls count] > 0)
+ [roles addObjectsFromArray: superAcls];
+
component = [self component: NO];
- if (component)
+ ownerRole = [self _roleOfOwner: component];
+ if ([owner isEqualToString: uid])
+ [roles addObject: ownerRole];
+ else
{
- email = [[LDAPUserManager sharedUserManager] getEmailForUID: uid];
- if ([component isOrganizer: email])
+ if (component)
+ {
+ accessRole = [container roleForComponentsWithAccessClass:
+ [component symbolicAccessClass]
+ forUser: uid];
+ if ([accessRole length] > 0)
+ {
+ [roles addObject: accessRole];
+ [roles addObject: [self _compiledRoleForOwner: ownerRole
+ andUser: accessRole]];
+ }
+ }
+ else if ([roles containsObject: SOGoRole_ObjectCreator])
[roles addObject: SOGoCalendarRole_Organizer];
- if ([component isParticipant: email])
- [roles addObject: SOGoCalendarRole_Participant];
- accessRole = [container roleForComponentsWithAccessClass:
- [component symbolicAccessClass]
- forUser: uid];
- if ([accessRole length] > 0)
- [roles addObject: accessRole];
}
- superAcls = [super aclsForUser: uid];
- if ([superAcls count] > 0)
- [roles addObjectsFromArray: superAcls];
- if ([roles containsObject: SOGoRole_ObjectCreator])
- [roles addObject: SOGoCalendarRole_ComponentModifier];
+ NSLog (@"all roles: %@" , roles);
+// }
return roles;
}
return r;
}
+- (NSString *) davContentType
+{
+ return @"text/calendar";
+}
+
@end
--- /dev/null
+/* iCalEntityObject+SOGo.h - this file is part of SOGo
+ *
+ * Copyright (C) 2007 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ICALENTITYOBJECT_SOGO_H
+#define ICALENTITYOBJECT_SOGO_H
+
+#import <NGCards/iCalEntityObject.h>
+
+@interface iCalEntityObject (SOGoExtensions)
+
+- (BOOL) userIsParticipant: (SOGoUser *) user;
+- (BOOL) userIsOrganizer: (SOGoUser *) user;
+
+@end
+
+#endif /* ICALENTITYOBJECT_SOGO_H */
--- /dev/null
+/* iCalEntityObject+SOGo.m - this file is part of SOGo
+ *
+ * Copyright (C) 2007 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSEnumerator.h>
+
+#import <SoObjects/SOGo/SOGoUser.h>
+
+#import "iCalEntityObject+SOGo.h"
+
+@implementation iCalEntityObject (SOGoExtensions)
+
+- (BOOL) userIsParticipant: (SOGoUser *) user
+{
+ NSEnumerator *emails;
+ NSString *currentEmail;
+ BOOL response;
+
+ response = NO;
+
+ emails = [[user allEmails] objectEnumerator];
+ currentEmail = [emails nextObject];
+ while (!response && currentEmail)
+ if ([self isParticipant: currentEmail])
+ response = YES;
+ else
+ currentEmail = [emails nextObject];
+
+ return response;
+}
+
+- (BOOL) userIsOrganizer: (SOGoUser *) user
+{
+ NSEnumerator *emails;
+ NSString *currentEmail;
+ BOOL response;
+
+ response = NO;
+
+ emails = [[user allEmails] objectEnumerator];
+ currentEmail = [emails nextObject];
+ while (!response && currentEmail)
+ if ([self isOrganizer: currentEmail])
+ response = YES;
+ else
+ currentEmail = [emails nextObject];
+
+ return response;
+}
+
+@end
"ViewDAndTOfConfidentialRecords" = ( "Owner", "ConfidentialDAndTViewer" );
"ModifyConfidentialRecords" = ( "Owner", "ConfidentialModifier" );
"RespondToConfidentialRecords" = ( "Owner", "ConfidentialModifier", "ConfidentialResponder" );
+ "Access Contents Information" = ( "Owner", "AuthorizedSubscriber" );
};
};
SOGoGroupAppointmentFolder = {
superclass = "SOGoAppointmentFolder";
};
SOGoCalendarComponent = {
- superclass = "SOGoContentObject";
+ superclass = "SOGoContentObject";
defaultRoles = {
- "ViewAllComponent" = ( "Owner", "Organizer", "Participant", "ComponentViewer", "ComponentModifier" );
+ "ViewAllComponent" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer" );
"ViewDAndT" = ( "Organizer", "Participant", "ComponentDAndTViewer" );
- "ModifyComponent" = ( "Owner", "ComponentModifier" );
- "RespondToComponent" = ( "Participant", "ComponentResponder" );
+ "ModifyComponent" = ( "Owner", "Organizer" );
+ "RespondToComponent" = ( "Participant" );
+ "Access Object" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" );
};
};
SOGoAppointmentObject = {
andDisplayName: (NSString *) aDisplayName
inContainer: (SOGoObject *) aContainer;
-- (NSString *) nameInContainer;
- (NSString *) displayName;
- (NSArray *) lookupContactsWithFilter: (NSString *) filter
return YES;
}
+- (NSString *) davContentType
+{
+ return @"httpd/unix-directory";
+}
+
- (void) setBaseOCSPath: (NSString *) newOCSPath
{
if (OCSPath)
- (void) dealloc
{
- if (card)
- [card release];
+ [card release];
[super dealloc];
}
- (NGVCard *) vCard
{
- NSString *contentStr;
-
if (!card)
{
- contentStr = [self contentAsString];
- if ([[contentStr uppercaseString] hasPrefix:@"BEGIN:VCARD"])
- card = [NGVCard parseSingleFromSource: contentStr];
+ if ([[content uppercaseString] hasPrefix: @"BEGIN:VCARD"])
+ card = [NGVCard parseSingleFromSource: content];
else
card = [NGVCard cardWithUid: [self nameInContainer]];
[card retain];
if ((self = [self initWithName: newName
inContainer: newContainer]))
ASSIGN (displayName, newDisplayName);
-
+
return self;
}
EOQualifier *qualifier;
EOSortOrdering *ordering;
- NSLog (@"fetching records matching '%@', sorted by '%@' in order %d",
- filter, sortKey, sortOrdering);
+// NSLog (@"fetching records matching '%@', sorted by '%@' in order %d",
+// filter, sortKey, sortOrdering);
fields = folderListingFields;
qualifier = [self _qualifierForFilter: filter];
return @"Contact";
}
-- (NSString *)outlookFolderClass {
+- (NSString *) outlookFolderClass
+{
return @"IPF.Contact";
}
@interface SOGoContactLDAPFolder : SOGoObject <SOGoContactFolder>
{
- NSString *name;
NSString *displayName;
LDAPSource *ldapSource;
NSMutableDictionary *entries;
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/SoUser.h>
#import <EOControl/EOSortOrdering.h>
+#import <SaxObjC/XMLNamespaces.h>
#import <SoObjects/SOGo/LDAPSource.h>
#import "SOGoContactLDIFEntry.h"
{
if ((self = [super init]))
{
- name = nil;
displayName = nil;
- container = nil;
entries = nil;
ldapSource = nil;
}
andDisplayName: (NSString *) newDisplayName
inContainer: (SOGoObject *) newContainer
{
- self = [self init];
-
- ASSIGN (name, newName);
- ASSIGN (displayName, newDisplayName);
- ASSIGN (container, newContainer);
+ if ((self = [self initWithName: newName
+ inContainer: newContainer]))
+ {
+ ASSIGN (displayName, newDisplayName);
+ }
return self;
}
- (void) dealloc
{
- [name release];
[displayName release];
- [container release];
[entries release];
[ldapSource release];
[super dealloc];
return displayName;
}
-- (NSString *) nameInContainer
-{
- return name;
-}
-
- (id) lookupName: (NSString *) objectName
inContext: (WOContext *) lookupContext
acquire: (BOOL) acquire
{
ldifEntry = [ldapSource lookupContactEntry: objectName];
obj = ((ldifEntry)
- ? [SOGoContactLDIFEntry contactEntryWithName: name
+ ? [SOGoContactLDIFEntry contactEntryWithName: objectName
withLDIFEntry: ldifEntry
inContainer: self]
: [NSException exceptionWithHTTPStatus: 404]);
return result;
}
-- (NSString *) groupDavResourceType
+- (NSArray *) davResourceType
+{
+ NSArray *rType, *groupDavCollection;
+
+ groupDavCollection = [NSArray arrayWithObjects: @"vcard-collection",
+ XMLNS_GROUPDAV, nil];
+ rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil];
+
+ return rType;
+}
+
+- (NSString *) davContentType
+{
+ return @"httpd/unix-directory";
+}
+
+- (BOOL) davIsCollection
+{
+ return YES;
+}
+
+- (NSString *) davDisplayName
+{
+ return displayName;
+}
+
+- (BOOL) isFolderish
{
- return @"vcard-collection";
+ return YES;
}
/* acls */
classes = {
SOGoContactFolders = {
superclass = "SOGoFolder";
- protectedBy = "<public>";
- defaultAccess = "allow";
+ protectedBy = "Access Contents Information";
defaultRoles = {
- "View" = ( "Owner" );
+ "Access Contents Information" = ( "Authenticated" );
+ "WebDAV Access" = ( "Authenticated" );
};
};
-
SOGoContactGCSFolder = {
superclass = "SOGoFolder";
};
-
SOGoContactGCSEntry = {
superclass = "SOGoContentObject";
- defaultRoles = {
- "View" = ( "Owner", "Delegate", "Organizer", "Authenticated" );
- };
};
-
SOGoContactLDAPFolder = {
superclass = "SOGoFolder";
- defaultAccess = "allow";
- protectedBy = "<public>";
+ protectedBy = "Access Contents Information";
+ defaultRoles = {
+ "Access Contents Information" = ( "Authenticated" );
+ "WebDAV Access" = ( "Authenticated" );
+ };
};
-
SOGoContactLDIFEntry = {
- superclass = "SOGoContentObject";
- defaultAccess = "allow";
- protectedBy = "<public>";
+ superclass = "SOGoContentObject";
+ protectedBy = "Access Content Information";
+ defaultRoles = {
+ "Access Content Information" = ( "Authenticated" );
+ "WebDAV Access" = ( "Authenticated" );
+ };
};
};
}
/* WebDAV */
-- (BOOL)davIsCollection {
+- (NSString *) davContentType
+{
+ return @"httpd/unix-directory";
+}
+
+- (BOOL) davIsCollection
+{
return YES;
}
-- (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx {
+- (NSException *) davCreateCollection: (NSString *) _name
+ inContext: (id) _ctx
+{
return [[self imap4Connection] createMailbox:_name atURL:[self imap4URL]];
}
-- (NSString *)shortTitle {
+- (NSString *) shortTitle
+{
NSString *s, *login, *host;
NSRange r;
return [NSString stringWithFormat:@"%@@%@", login, host];
}
-- (NSString *)davDisplayName {
+- (NSString *) davDisplayName
+{
return [self shortTitle];
}
return YES;
}
+- (NSString *) davContentType
+{
+ return @"httpd/unix-directory";
+}
+
/* acls */
- (NSArray *) aclsForUser: (NSString *) uid
useAltNamespace = [ud boolForKey:@"SOGoSpecialFoldersInRoot"];
}
+- (void) _adjustOwner
+{
+ SOGoMailAccount *mailAccount;
+ NSString *path;
+ NSArray *names;
+
+ mailAccount = [self mailAccountFolder];
+ path = [[self imap4Connection] imap4FolderNameForURL: [self imap4URL]];
+
+ if ([path hasPrefix: [mailAccount sharedFolderName]])
+ owner = @"anyone";
+ else if ([path hasPrefix: [mailAccount otherUsersFolderName]])
+ {
+ names = [path componentsSeparatedByString: @"/"];
+ if ([names count] > 1)
+ owner = [names objectAtIndex: 1];
+ else
+ owner = @"anyone";
+ }
+}
+
+- (id) initWithName: (NSString *) newName
+ inContainer: (id) newContainer
+{
+ if ((self = [super initWithName: newName
+ inContainer: newContainer]))
+ {
+ [self _adjustOwner];
+ }
+
+ return self;
+}
+
- (void) dealloc
{
[filenames release];
return subfoldersURL;
}
+- (NSString *) davContentType
+{
+ return @"httpd/unix-directory";
+}
+
- (NSArray *) toOneRelationshipKeys
{
NSArray *uids;
[SOGoAcls addObjectUniquely: SOGoRole_FolderCreator];
break;
case 'x':
- [SOGoAcls addObjectUniquely: SOGoRole_ObjectEraser];
+ [SOGoAcls addObjectUniquely: SOGoRole_FolderEraser];
break;
case 't':
- [SOGoAcls addObjectUniquely: SOGoMailRole_MessageEraser];
+ [SOGoAcls addObjectUniquely: SOGoRole_ObjectEraser];
break;
case 'e':
[SOGoAcls addObjectUniquely: SOGoMailRole_Expunger];
character = 'p';
else if ([currentAcl isEqualToString: SOGoRole_FolderCreator])
character = 'k';
- else if ([currentAcl isEqualToString: SOGoRole_ObjectEraser])
+ else if ([currentAcl isEqualToString: SOGoRole_FolderEraser])
character = 'x';
- else if ([currentAcl isEqualToString: SOGoMailRole_MessageEraser])
+ else if ([currentAcl isEqualToString: SOGoRole_ObjectEraser])
character = 't';
else if ([currentAcl isEqualToString: SOGoMailRole_Expunger])
character = 'e';
return defaultUserID;
}
-- (NSString *) ownerInContext: (WOContext *) localContext
-{
- SOGoMailAccount *mailAccount;
- NSString *path, *owner;
- NSArray *names;
-
- mailAccount = [self mailAccountFolder];
- path = [[self imap4Connection] imap4FolderNameForURL: [self imap4URL]];
-
- if ([path hasPrefix: [mailAccount sharedFolderName]])
- owner = @"anyone";
- else if ([path hasPrefix: [mailAccount otherUsersFolderName]])
- {
- names = [path componentsSeparatedByString: @"/"];
- if ([names count] > 1)
- owner = [names objectAtIndex: 1];
- else
- owner = @"anyone";
- }
- else
- owner = [super ownerInContext: localContext];
-
- return owner;
-}
-
- (NSString *) otherUsersPathToFolder
{
NSString *userPath, *selfPath, *otherUsers, *sharedFolders;
else
userPath = [NSString stringWithFormat: @"/%@/%@%@",
[otherUsers stringByEscapingURL],
- [self ownerInContext: context],
- selfPath];
+ owner, selfPath];
return userPath;
}
return [[content copy] autorelease];
}
+- (NSString *) davContentType
+{
+ return @"message/rfc822";
+}
+
- (NSString *)contentAsString {
NSString *s;
NSData *content;
/* flags */
-- (NSException *)addFlags:(id)_flags {
+- (NSException *) addFlags: (id) _flags
+{
return [[self imap4Connection] addFlags:_flags toURL:[self imap4URL]];
}
-- (NSException *)removeFlags:(id)_flags {
+
+- (NSException *) removeFlags: (id) _flags
+{
return [[self imap4Connection] removeFlags:_flags toURL:[self imap4URL]];
}
login = [[context activeUser] login];
parentAcl = [[self container] aclsForUser: login];
- return [parentAcl containsObject: SOGoMailRole_MessageEraser];
+ return [parentAcl containsObject: SOGoRole_ObjectEraser];
}
/* name lookup */
- (NSArray *) stringsWithFormat: (NSString *) format;
+- (BOOL) containsCaseInsensitiveString: (NSString *) match;
+
#ifdef GNUSTEP_BASE_LIBRARY
- (void) makeObjectsPerform: (SEL) selector
withObject: (id) object1
return representation;
}
+- (BOOL) containsCaseInsensitiveString: (NSString *) match
+{
+ BOOL response;
+ NSString *currentString, *cmpObject;
+ NSEnumerator *objects;
+
+ response = NO;
+
+ cmpObject = [match lowercaseString];
+ objects = [self objectEnumerator];
+ currentString = [objects nextObject];
+ while (currentString && !response)
+ if ([[currentString lowercaseString] isEqualToString: cmpObject])
+ response = YES;
+ else
+ currentString = [objects nextObject];
+
+ return response;
+}
+
@end
@implementation NSMutableArray (SOGoArrayUtilities)
{
NSString *ocsPath;
NSString *content;
+ BOOL isNew;
}
/* accessors */
/* content */
+- (BOOL) isNew;
- (NSString *) contentAsString;
- (NSException *) saveContentString: (NSString *) _str
baseVersion: (unsigned int) _baseVersion;
// TODO: check superclass version
-- (void)dealloc {
+- (id) initWithName: (NSString *) newName
+ inContainer: (id) newContainer
+{
+ if ((self = [super initWithName: newName inContainer: newContainer]))
+ {
+ ocsPath = nil;
+ content = [[self ocsFolder] fetchContentWithName: newName];
+ [content retain];
+ isNew = (!content);
+ }
+
+ return self;
+}
+
+- (void) dealloc
+{
[content release];
[ocsPath release];
[super dealloc];
/* notifications */
-- (void)sleep {
+- (void) sleep
+{
[content release]; content = nil;
[super sleep];
}
/* accessors */
-- (BOOL)isFolderish {
+- (BOOL) isFolderish
+{
return NO;
}
-- (void)setOCSPath:(NSString *)_path {
- if ([ocsPath isEqualToString:_path])
- return;
-
- if (ocsPath)
- [self warnWithFormat:@"GCS path is already set! '%@'", _path];
+- (void) setOCSPath: (NSString *) newOCSPath
+{
+ if (![ocsPath isEqualToString: newOCSPath])
+ {
+ if (ocsPath)
+ [self warnWithFormat:@"GCS path is already set! '%@'", newOCSPath];
- ASSIGNCOPY(ocsPath, _path);
+ ASSIGNCOPY (ocsPath, newOCSPath);
+ }
}
- (NSString *) ocsPath
{
- NSString *p;
-
+ NSMutableString *newOCSPath;
+
if (!ocsPath)
{
- p = [self ocsPathOfContainer];
- if (p)
+ newOCSPath = [NSMutableString new];
+ [newOCSPath appendString: [self ocsPathOfContainer]];
+ if ([newOCSPath length] > 0)
{
- if (![p hasSuffix:@"/"])
- p = [p stringByAppendingString: @"/"];
- ocsPath = [p stringByAppendingString: [self nameInContainer]];
- [ocsPath retain];
+ if (![newOCSPath hasSuffix:@"/"])
+ [newOCSPath appendString: @"/"];
+ [newOCSPath appendString: nameInContainer];
+ ocsPath = newOCSPath;
}
}
return ocsPath;
}
-- (NSString *)ocsPathOfContainer {
- if (![[self container] respondsToSelector:@selector(ocsPath)])
- return nil;
+- (NSString *) ocsPathOfContainer
+{
+ NSString *ocsPathOfContainer;
- return [[self container] ocsPath];
+ if ([container respondsToSelector: @selector (ocsPath)])
+ ocsPathOfContainer = [container ocsPath];
+ else
+ ocsPathOfContainer = nil;
+
+ return ocsPath;
}
- (GCSFolder *) ocsFolder
/* content */
-- (NSString *) contentAsString
+- (BOOL) isNew
{
- if (!content)
- {
- content = [[self ocsFolder] fetchContentWithName: nameInContainer];
- [content retain];
- }
+ return isNew;
+}
+- (NSString *) contentAsString
+{
return content;
}
-- (NSException *) saveContentString: (NSString *) _str
- baseVersion: (unsigned int) _baseVersion
+- (NSException *) saveContentString: (NSString *) newContent
+ baseVersion: (unsigned int) newBaseVersion
{
/* Note: "iCal multifolder saves" are implemented in the apt subclass! */
GCSFolder *folder;
NSException *ex;
-
- if ((folder = [self ocsFolder]) == nil) {
+
+ ex = nil;
+
+ ASSIGN (content, newContent);
+ folder = [container ocsFolder];
+ if (folder)
+ {
+ ex = [folder writeContent: newContent
+ toName: nameInContainer
+ baseVersion: newBaseVersion];
+ if (ex)
+ [self errorWithFormat:@"write failed: %@", ex];
+ }
+ else
[self errorWithFormat:@"Did not find folder of content object."];
- return nil;
- }
- ex = [folder writeContent:_str toName:[self nameInContainer]
- baseVersion:_baseVersion];
- if (ex != nil) {
- [self errorWithFormat:@"write failed: %@", ex];
- return ex;
- }
- return nil;
+ return ex;
}
-- (NSException *)saveContentString:(NSString *)_str {
- return [self saveContentString:_str baseVersion:0 /* don't check */];
+
+- (NSException *) saveContentString: (NSString *) newContent
+{
+ return [self saveContentString: newContent baseVersion: 0];
}
-- (NSException *)delete {
+- (NSException *) delete
+{
/* Note: "iCal multifolder saves" are implemented in the apt subclass! */
GCSFolder *folder;
NSException *ex;
/* actions */
-- (id)PUTAction:(WOContext *)_ctx {
+- (id) PUTAction: (WOContext *) _ctx
+{
WORequest *rq;
NSException *error;
unsigned int baseVersion;
/* setup response */
// TODO: this should be automatic in the SoDispatcher if we return nil?
- [[_ctx response] setStatus:201 /* Created */];
+ [[_ctx response] setStatus: 201 /* Created */];
if ((etag = [self davEntityTag]) != nil)
[[_ctx response] setHeader:etag forKey:@"etag"];
if ([containerAcls count] > 0)
{
if ([containerAcls containsObject: SOGoRole_ObjectCreator])
- [acls addObject: SOGoRole_ObjectCreator];
- if ([containerAcls containsObject: SOGoRole_ObjectEraser])
- [acls addObject: SOGoRole_ObjectEraser];
+ {
+ [acls addObject: SOGoRole_ObjectCreator];
+ if (isNew)
+ [acls addObject: SOGoRole_ObjectEditor];
+ }
+ if ([containerAcls containsObject: SOGoRole_ObjectReader])
+ [acls addObject: SOGoRole_ObjectViewer];
}
return acls;
return rType;
}
+- (NSString *) davContentType
+{
+ return @"httpd/unix-directory";
+}
+
- (NSArray *) toOneRelationshipKeys {
/* toOneRelationshipKeys are the 'files' contained in a folder */
NSMutableArray *ma;
- (NSArray *) aclsForUser: (NSString *) uid
{
- return [self aclsForUser: uid
- forObjectAtPath: [self pathArrayToSoObject]];
+ NSMutableArray *acls;
+ NSArray *ownAcls, *containerAcls;
+
+ acls = [NSMutableArray array];
+ ownAcls = [self aclsForUser: uid
+ forObjectAtPath: [self pathArrayToSoObject]];
+ [acls addObjectsFromArray: ownAcls];
+ if ([container respondsToSelector: @selector (aclsForUser:)])
+ {
+ containerAcls = [container aclsForUser: uid];
+ if ([containerAcls count] > 0)
+ {
+ if ([containerAcls containsObject: SOGoRole_ObjectReader])
+ [acls addObject: SOGoRole_ObjectViewer];
+#warning this should be checked
+ if ([containerAcls containsObject: SOGoRole_ObjectEraser])
+ [acls addObject: SOGoRole_ObjectEraser];
+ }
+ }
+
+ return acls;
}
- (void) setRoles: (NSArray *) roles
{
WOContext *context;
NSString *nameInContainer;
- id container;
- NSString *customOwner;
+ id container;
+ NSString *owner;
}
+ (id) objectWithName: (NSString *)_name inContainer:(id)_container;
#import <NGObjWeb/WORequest+So.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGExtensions/NSObject+Logs.h>
+#import <NGExtensions/NSString+misc.h>
#import <NGCards/NSDictionary+NGCards.h>
#import <UI/SOGoUI/SOGoACLAdvisory.h>
{
return [NSDictionary dictionaryWithObjectsAndKeys:
@"read", SoPerm_AccessContentsInformation,
- @"read", SoPerm_View,
+ @"read", SoPerm_AccessContentsInformation,
@"bind", SoPerm_AddDocumentsImagesAndFiles,
@"unbind", SoPerm_DeleteObjects,
@"write-acl", SoPerm_ChangePermissions,
return YES;
}
-- (id)initWithName:(NSString *)_name inContainer:(id)_container {
- if ((self = [self init]))
+- (id) init
+{
+ if ((self = [super init]))
{
- context = [[WOApplication application] context];
- [context retain];
- nameInContainer = [_name copy];
- container =
- [self doesRetainContainer] ? [_container retain] : _container;
- customOwner = nil;
+ context = nil;
+ nameInContainer = nil;
+ container = nil;
+ owner = nil;
}
return self;
}
-- (id) init
+- (id) initWithName: (NSString *) _name
+ inContainer: (id) _container
{
- if ((self = [super init]))
+ if ((self = [self init]))
{
- nameInContainer = nil;
- container = nil;
+ context = [[WOApplication application] context];
+ [context retain];
+ nameInContainer = [_name copy];
+ container = _container;
+ if ([self doesRetainContainer])
+ [_container retain];
+ ASSIGN (owner, [_container ownerInContext: context]);
}
return self;
}
-- (void)dealloc {
+- (void) dealloc
+{
[context release];
- [customOwner release];
+ [owner release];
if ([self doesRetainContainer])
[container release];
[nameInContainer release];
/* accessors */
-- (NSString *)nameInContainer {
+- (NSString *) nameInContainer
+{
return nameInContainer;
}
-- (id)container {
+
+- (id) container
+{
return container;
}
- (void) setOwner: (NSString *) newOwner
{
- ASSIGN (customOwner, newOwner);
+ ASSIGN (owner, newOwner);
}
-- (NSString *)ownerInContext:(id)_ctx {
- return ((customOwner)
- ? customOwner
- : [[self container] ownerInContext:_ctx]);
+- (NSString *) ownerInContext: (id) localContext
+{
+ return owner;
}
/* hierarchy */
-- (NSArray *)fetchSubfolders {
+- (NSArray *) fetchSubfolders
+{
NSMutableArray *ma;
NSArray *names;
unsigned i, count;
return [container lookupUserFolder];
}
+
- (SOGoGroupsFolder *)lookupGroupsFolder {
return [[self lookupUserFolder] lookupGroupsFolder];
}
-- (void)sleep {
+- (void) sleep
+{
if ([self doesRetainContainer])
[container release];
container = nil;
/* operations */
-- (NSException *)delete {
- return [NSException exceptionWithHTTPStatus:501 /* not implemented */
- reason:@"delete not yet implemented, sorry ..."];
+- (NSException *) delete
+{
+ return [NSException exceptionWithHTTPStatus: 501 /* not implemented */
+ reason: @"delete not yet implemented, sorry ..."];
}
/* KVC hacks */
-- (id)valueForUndefinedKey:(NSString *)_key {
+- (id) valueForUndefinedKey: (NSString *) _key
+{
return nil;
}
/* WebDAV */
-- (NSString *)davDisplayName {
+- (NSString *) davDisplayName
+{
return [self nameInContainer];
}
/* actions */
-- (id)DELETEAction:(id)_ctx {
+- (id) DELETEAction: (id) _ctx
+{
NSException *error;
if ((error = [self delete]) != nil)
return [NSNumber numberWithBool:YES]; /* delete worked out ... */
}
-- (id)GETAction:(id)_ctx {
+- (NSString *) davContentType
+{
+ return @"text/plain";
+}
+
+- (WOResponse *) _webDAVResponse: (WOContext *) localContext
+{
+ WOResponse *response;
+ NSString *contentType;
+ id etag;
+
+ response = [localContext response];
+ contentType = [NSString stringWithFormat: @"%@; charset=utf8",
+ [self davContentType]];
+ [response setHeader: contentType forKey: @"content-type"];
+ [response appendContentString: [self contentAsString]];
+ etag = [self davEntityTag];
+ if (etag)
+ [response setHeader: etag forKey: @"etag"];
+
+ return response;
+}
+
+- (id) GETAction: (id) localContext
+{
// TODO: I guess this should really be done by SOPE (redirect to
// default method)
- WORequest *rq;
- WOResponse *r;
+ WORequest *request;
NSString *uri;
-
- r = [(WOContext *)_ctx response];
- rq = [(WOContext *)_ctx request];
-
- if ([rq isSoWebDAVRequest]) {
- if ([self respondsToSelector:@selector(contentAsString)]) {
- NSException *error;
- id etag;
-
- if ((error = [self matchesRequestConditionInContext:_ctx]) != nil)
- return error;
-
- [r appendContentString:[self contentAsString]];
-
- if ((etag = [self davEntityTag]) != nil)
- [r setHeader:etag forKey:@"etag"];
-
- return r;
+ NSException *error;
+ id value;
+
+ request = [localContext request];
+ if ([request isSoWebDAVRequest])
+ {
+ if ([self respondsToSelector: @selector (contentAsString)])
+ {
+ error = [self matchesRequestConditionInContext: localContext];
+ if (error)
+ value = error;
+ else
+ value = [self _webDAVResponse: localContext];
+ }
+ else
+ value = [NSException exceptionWithHTTPStatus: 501 /* not implemented */
+ reason: @"no WebDAV GET support?!"];
+ }
+ else
+ {
+ value = [localContext response];
+ uri = [[request uri] composeURLWithAction: @"view"
+ parameters: [request formValues]
+ andHash: NO];
+ [value setStatus: 302 /* moved */];
+ [value setHeader: uri forKey: @"location"];
}
-
- return [NSException exceptionWithHTTPStatus:501 /* not implemented */
- reason:@"no WebDAV GET support?!"];
- }
-
- uri = [rq uri];
- [r setStatus:302 /* moved */];
- [r setHeader: [uri composeURLWithAction: @"view"
- parameters: [rq formValues]
- andHash: NO]
- forKey:@"location"];
- return r;
+ return value;
}
/* etag support */
- (NSURL *) _urlPreferringParticle: (NSString *) expected
overThisOne: (NSString *) possible
{
- NSURL *serverURL, *davURL;
+ NSURL *serverURL, *url;
NSMutableArray *path;
NSString *baseURL, *urlMethod;
serverURL = [context serverURL];
- baseURL = [self baseURLInContext: context];
+ baseURL = [[self baseURLInContext: context] stringByUnescapingURL];
path = [NSMutableArray arrayWithArray: [baseURL componentsSeparatedByString:
@"/"]];
urlMethod = [path objectAtIndex: 2];
[path insertObject: expected atIndex: 2];
}
- davURL = [[NSURL alloc] initWithScheme: [serverURL scheme]
- host: [serverURL host]
- path: [path componentsJoinedByString: @"/"]];
- [davURL autorelease];
+ url = [[NSURL alloc] initWithScheme: [serverURL scheme]
+ host: [serverURL host]
+ path: [path componentsJoinedByString: @"/"]];
+ [url autorelease];
- return davURL;
+ return url;
}
- (NSURL *) davURL
#import <NGObjWeb/SoPermissions.h>
extern NSString *SOGoRole_ObjectCreator;
-extern NSString *SOGoRole_ObjectReader;
extern NSString *SOGoRole_ObjectEraser;
+extern NSString *SOGoRole_ObjectReader;
extern NSString *SOGoRole_ObjectViewer;
extern NSString *SOGoRole_ObjectEditor;
extern NSString *SOGoRole_FolderCreator;
-extern NSString *SOGoRole_FolderReader;
+extern NSString *SOGoRole_FolderEraser;
+extern NSString *SOGoRole_FolderViewer;
+
extern NSString *SOGoRole_AuthorizedSubscriber;
extern NSString *SOGoRole_None;
extern NSString *SOGoRole_FreeBusy;
extern NSString *SOGoMailRole_Expunger;
extern NSString *SOGoMailRole_Creator;
extern NSString *SOGoMailRole_Administrator;
-extern NSString *SOGoMailRole_MessageEraser;
extern NSString *SOGoCalendarRole_Organizer;
extern NSString *SOGoCalendarRole_Participant;
extern NSString *SOGoCalendarRole_ComponentModifier;
extern NSString *SOGoCalendarRole_ComponentResponder;
+extern NSString *SOGoPerm_AccessObject;
extern NSString *SOGoPerm_ReadAcls;
extern NSString *SOGoPerm_FreeBusyLookup;
NSString *SOGoRole_ObjectViewer = @"ObjectViewer";
NSString *SOGoRole_ObjectReader = @"ObjectReader";
NSString *SOGoRole_ObjectEditor = @"ObjectEditor";
+
NSString *SOGoRole_FolderCreator = @"FolderCreator";
NSString *SOGoRole_FolderEraser = @"FolderEraser";
-NSString *SOGoRole_FolderViewer = @"FolderViewer";
-NSString *SOGoRole_FolderReader = @"FolderReader";
+
NSString *SOGoRole_AuthorizedSubscriber = @"AuthorizedSubscriber";
NSString *SOGoRole_None = @"None";
NSString *SOGoMailRole_MessageEraser = @"MailMessageEraser";
/* permissions */
+NSString *SOGoPerm_AccessObject= @"Access Object";
NSString *SOGoPerm_ReadAcls = @"ReadAcls"; /* the equivalent of "read-acl" in
the WebDAV acls spec, which is
currently missing from SOPE */
#import "AgenorUserDefaults.h"
#import "LDAPUserManager.h"
#import "SOGoContentObject.h"
-#import "SOGoUser.h"
#import "SOGoPermissions.h"
+#import "NSArray+Utilities.h"
+
+#import "SOGoUser.h"
static NSTimeZone *serverTimeZone = nil;
static NSString *fallbackIMAP4Server = nil;
{
tzName = [ud stringForKey: @"SOGoServerTimeZone"];
if (!tzName)
- tzName = @"Canada/Eastern";
+ tzName = @"UTC";
serverTimeZone = [NSTimeZone timeZoneWithName: tzName];
[serverTimeZone retain];
}
- (BOOL) hasEmail: (NSString *) email
{
- BOOL hasEmail;
- NSString *currentEmail, *cmpEmail;
- NSEnumerator *emails;
-
- hasEmail = NO;
if (!allEmails)
[self _fetchAllEmails];
- cmpEmail = [email lowercaseString];
- emails = [allEmails objectEnumerator];
- currentEmail = [emails nextObject];
- while (currentEmail && !hasEmail)
- if ([[currentEmail lowercaseString] isEqualToString: cmpEmail])
- hasEmail = YES;
- else
- currentEmail = [emails nextObject];
-
- return hasEmail;
+
+ return [allEmails containsCaseInsensitiveString: email];
}
- (NSString *) cn
- (WOResponse *) canAccessContentAction
{
WOResponse *response;
- SoSecurityManager *securityManager;
- BOOL result;
-
- securityManager = [SoSecurityManager sharedSecurityManager];
- result = (![securityManager validatePermission: SoPerm_AccessContentsInformation
- onObject: [self clientObject]
- inContext: context]);
response = [context response];
- [response setStatus: 200];
- [response setHeader: @"text/plain; charset=\"ascii\""
- forKey: @"content-type"];
- [response appendContentString: (result) ? @"1" : @"0"];
+ [response setStatus: 204];
return response;
}
= "This person can add cards to this addressbook.";
"This person can edit the cards of this addressbook."
= "This person can edit the cards of this addressbook.";
-"This person can view the cards of this addressbook."
-= "This person can view the cards of this addressbook.";
+"This person can list the content of this addressbook."
+= "This person can list the content of this addressbook.";
+"This person can read the cards of this addressbook."
+= "This person can read the cards of this addressbook.";
"This person can erase cards from this addressbook."
= "This person can erase cards from this addressbook.";
= "Cette personne peut ajouter des fiches à ce carnet d'adresses.";
"This person can edit the cards of this addressbook."
= "Cette personne peut éditer des fiches de ce carnet d'adresses.";
-"This person can view the cards of this addressbook."
-= "Cette personne peut visionner des fiches de ce carnet d'adresses.";
+"This person can list the content of this addressbook."
+= "Cette personne peut lister le contenu de ce carnet d'adresses.";
+"This person can read the cards of this addressbook."
+= "Cette personne peut visionner les fiches de ce carnet d'adresses.";
"This person can erase cards from this addressbook."
= "Cette personne peut effacer des fiches de ce carnet d'adresses.";
+
objectId = nil;
if ([objectId length] == 0)
- return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
+ return [NSException exceptionWithHTTPStatus: 500 /* Internal Error */
reason: @"could not create a unique ID"];
nextMethod = [NSString stringWithFormat: @"../%@/%@",
objectId, [self editActionName]];
- uri = [self _completeURIForMethod:nextMethod];
- return [self redirectToLocation:uri];
+ uri = [self _completeURIForMethod: nextMethod];
+ return [self redirectToLocation: uri];
}
@end /* UIxContactEditor */
return YES;
}
-- (WOResponse *) canAccessContentAction
-{
- WOResponse *response;
- NSString *clientClass;
-
- clientClass = NSStringFromClass([[self clientObject] class]);
-
- response = [context response];
- [response setStatus: 200];
- [response setHeader: @"text/plain; charset=\"ascii\""
- forKey: @"content-type"];
- [response
- appendContentString:
- ([clientClass isEqualToString: @"SOGoContactLDAPFolder"])
- ? @"1" : @"0"];
-
- return response;
-}
-
@end /* UIxContactsListView */
return [userRights containsObject: SOGoRole_ObjectViewer];
}
+- (void) setUserCanReadObjects: (BOOL) userCanReadObjects
+{
+ if (userCanReadObjects)
+ [self appendRight: SOGoRole_ObjectReader];
+ else
+ [self removeRight: SOGoRole_ObjectReader];
+}
+
+- (BOOL) userCanReadObjects
+{
+ return [userRights containsObject: SOGoRole_ObjectReader];
+}
+
- (void) updateRights
{
WORequest *request;
else
[self removeRight: SOGoRole_ObjectViewer];
+ if ([[request formValueForKey: @"ObjectReader"] length] > 0)
+ [self appendRight: SOGoRole_ObjectReader];
+ else
+ [self removeRight: SOGoRole_ObjectReader];
+
if ([[request formValueForKey: @"ObjectEraser"] length] > 0)
[self appendRight: SOGoRole_ObjectEraser];
else
};
canAccessContent = {
protectedBy = "<public>";
- pageName = "UIxContactsListView";
+ actionClass = "UIxFolderActions";
actionName = "canAccessContent";
};
};
/* acls */
"Default Roles" = "Default Roles";
+"User rights for:" = "User rights for:";
"List and see this folder" = "List and see this folder";
"Read mails from this folder" = "Read mails from this folder";
/* acls */
"Default Roles" = "Rôles par défaut";
+"User rights for:" = "Autorisations pour:";
"List and see this folder" = "Lister et voir ce dossier";
"Read mails from this folder" = "Lire les messages de ce dossier";
- (void) setUserCanRemoveFolder: (BOOL) userCanRemoveFolder
{
if (userCanRemoveFolder)
- [self appendRight: SOGoRole_ObjectEraser];
+ [self appendRight: SOGoRole_FolderEraser];
else
- [self removeRight: SOGoRole_ObjectEraser];
+ [self removeRight: SOGoRole_FolderEraser];
}
- (BOOL) userCanRemoveFolder
{
- return [userRights containsObject: SOGoRole_ObjectEraser];
+ return [userRights containsObject: SOGoRole_FolderEraser];
}
- (void) setUserCanEraseMails: (BOOL) userCanEraseMails
{
if (userCanEraseMails)
- [self appendRight: SOGoMailRole_MessageEraser];
+ [self appendRight: SOGoRole_ObjectEraser];
else
- [self removeRight: SOGoMailRole_MessageEraser];
+ [self removeRight: SOGoRole_ObjectEraser];
}
- (BOOL) userCanEraseMails
{
- return [userRights containsObject: SOGoMailRole_MessageEraser];
+ return [userRights containsObject: SOGoRole_ObjectEraser];
}
- (void) setUserCanExpungeFolder: (BOOL) userCanExpungeFolder
else
[self removeRight: SOGoRole_FolderCreator];
+ if ([[request formValueForKey: SOGoRole_FolderEraser] length] > 0)
+ [self appendRight: SOGoRole_FolderEraser];
+ else
+ [self removeRight: SOGoRole_FolderEraser];
+
if ([[request formValueForKey: SOGoRole_ObjectEraser] length] > 0)
[self appendRight: SOGoRole_ObjectEraser];
else
[self removeRight: SOGoRole_ObjectEraser];
- if ([[request formValueForKey: SOGoMailRole_MessageEraser] length] > 0)
- [self appendRight: SOGoMailRole_MessageEraser];
- else
- [self removeRight: SOGoMailRole_MessageEraser];
-
if ([[request formValueForKey: SOGoMailRole_Expunger] length] > 0)
[self appendRight: SOGoMailRole_Expunger];
else
[self objectTitle]];
}
-/* expunge / delete setup and permissions */
-
-- (BOOL) isTrashingAllowed
-{
- id trash;
-
- trash = [[[self clientObject] mailAccountFolder]
- trashFolderInContext:context];
- if ([trash isKindOfClass:[NSException class]])
- return NO;
-
- return [trash isWriteAllowed];
-}
-
-- (BOOL) showMarkDeletedButton
-{
- // TODO: we might also want to add a default to always show delete
- if (![[self clientObject] isDeletionAllowed])
- return NO;
-
- return [self isTrashingAllowed] ? NO : YES;
-}
-
-- (BOOL) showTrashButton
-{
- if (![[self clientObject] isDeletionAllowed])
- return NO;
-
- return [self isTrashingAllowed];
-}
-
/* links (DUP to UIxMailPartViewer!) */
- (NSString *)linkToEnvelopeAddress:(NGImap4EnvelopeAddress *)_address {
/* actions */
-- (id)defaultAction {
+- (id) defaultAction
+{
/* check etag to see whether we really must rerender */
if (mailETag != nil ) {
/*
"View" = ( "Authenticated", "FreeBusy" );
};
};
- SOGoFolder = {
- superclass = "SOGoObject";
+ SOGoObject = {
protectedBy = "<public>";
defaultAccess = "allow";
defaultRoles = {
- "Add Documents, Images, and Files" = ( "Owner", "ObjectCreator" );
- "View" = ( "Owner", "AuthorizedSubscriber" );
- "Access Contents Information" = ( "Owner", "ObjectViewer", "AuthorizedSubscriber" );
+ "View" = ( "Owner", "ObjectViewer" );
"Change Images And Files" = ( "Owner", "ObjectEditor" );
- "WebDAV Access" = ( "Owner", "AuthorizedSubscriber" );
+ "Access Contents Information" = ( "Owner", "ObjectReader" );
+ "Add Documents, Images, and Files" = ( "Owner", "ObjectCreator" );
+ "Add Folders" = ( "Owner", "FolderCreator" );
"ReadAcls" = ( "Owner", "AuthorizedSubscriber" );
"SaveAcls" = ( "Owner" );
"Delete Objects" = ( "Owner", "ObjectEraser" );
};
};
+ SOGoContentObject = {
+ superclass = "SOGoObject";
+ protectedBy = "Access Object";
+ defaultRoles = {
+ "Access Object" = ( "Owner", "AuthorizedSubscriber" );
+ };
+ };
+ SOGoFolder = {
+ superclass = "SOGoObject";
+ protectedBy = "Access Object";
+ defaultRoles = {
+ "Change Images And Files" = ( "Owner", "ObjectEditor" );
+ "WebDAV Access" = ( "Owner", "AuthorizedSubscriber" );
+ "Access Object" = ( "Owner", "AuthorizedSubscriber" );
+ "Access Contents Information" = ( "Owner", "ObjectViewer" );
+ };
+ };
+ SOGoUserFolder = {
+ superclass = "SOGoFolder";
+ protectedBy = "Access Contents Information";
+ defaultRoles = {
+ "Access Contents Information" = ( "Authenticated" );
+ "WebDAV Access" = ( "Authenticated" );
+ };
+ };
};
categories = {
SOGoRootPage = {
};
SOGoUserFolder = {
- methods = {
- view = {
- protectedBy = "View";
- pageName = "SOGoUserHomePage";
- };
- };
};
SOGoGroupsFolder = {
methods = {
#import <NGCards/iCalRecurrenceRule.h>
#import <NGCards/NSString+NGCards.h>
#import <NGCards/NSCalendarDate+NGCards.h>
+#import <NGObjWeb/SoSecurityManager.h>
+#import <NGObjWeb/NSException+HTTP.h>
+#import <NGObjWeb/WORequest.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
-#import <NGObjWeb/NSException+HTTP.h>
-#import <NGObjWeb/WORequest.h>
-#import <SOGo/SOGoUser.h>
-#import <SOGoUI/SOGoDateFormatter.h>
+#import <UI/SOGoUI/SOGoDateFormatter.h>
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
#import <SoObjects/Appointments/SOGoAppointmentObject.h>
#import <SoObjects/Appointments/SOGoTaskObject.h>
#import <SoObjects/SOGo/NSString+Utilities.h>
+#import <SoObjects/SOGo/SOGoUser.h>
+#import <SoObjects/SOGo/SOGoPermissions.h>
#import "UIxComponent+Scheduler.h"
- (NSString *) toolbar
{
- SOGoUser *currentUser;
SOGoCalendarComponent *clientObject;
NSString *toolbarFilename;
- iCalPerson *person;
iCalPersonPartStat participationStatus;
+ SoSecurityManager *sm;
+ NSString *owner;
+ sm = [SoSecurityManager sharedSecurityManager];
clientObject = [self clientObject];
- currentUser = [[self context] activeUser];
- if ([clientObject isOrganizerOrOwner: currentUser])
+
+ if (![sm validatePermission: SOGoCalendarPerm_ModifyComponent
+ onObject: clientObject
+ inContext: context])
{
if ([[clientObject componentTag] isEqualToString: @"vevent"])
toolbarFilename = @"SOGoAppointmentObject.toolbar";
else
toolbarFilename = @"SOGoTaskObject.toolbar";
}
- else
+ else if (![sm validatePermission: SOGoCalendarPerm_RespondToComponent
+ onObject: clientObject
+ inContext: context])
{
/* Lightning does not manage participation status within tasks */
- person = [clientObject participant: currentUser];
- if (person)
- {
- participationStatus = [person participationStatus];
- if (participationStatus == iCalPersonPartStatAccepted)
- toolbarFilename = @"SOGoAppointmentObjectDecline.toolbar";
- else if (participationStatus == iCalPersonPartStatDeclined)
- toolbarFilename = @"SOGoAppointmentObjectAccept.toolbar";
- else
- toolbarFilename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar";
- }
+ owner = [clientObject ownerInContext: context];
+ participationStatus
+ = [[clientObject findParticipantWithUID: owner] participationStatus];
+ if (participationStatus == iCalPersonPartStatAccepted)
+ toolbarFilename = @"SOGoAppointmentObjectDecline.toolbar";
+ else if (participationStatus == iCalPersonPartStatDeclined)
+ toolbarFilename = @"SOGoAppointmentObjectAccept.toolbar";
else
- toolbarFilename = @"SOGoComponentClose.toolbar";
+ toolbarFilename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar";
}
+ else
+ toolbarFilename = @"SOGoComponentClose.toolbar";
return toolbarFilename;
}
<label><input type="checkbox" class="checkBox"
const:name="ObjectViewer"
var:checked="userCanViewObjects"/><var:string
- label:value="This person can view the cards of this addressbook."/></label>
+ label:value="This person can list the content of this addressbook."/></label>
+ <br/>
+ <label><input type="checkbox" class="checkBox"
+ const:name="ObjectReader"
+ var:checked="userCanReadObjects"/><var:string
+ label:value="This person can read the cards of this addressbook."/></label>
<br/>
<label><input type="checkbox" class="checkBox"
const:name="ObjectEraser"
<label><var:string label:value="Owner:"/><br/>
<span class="value"><strong><var:string value="ownerName"/></strong></span></label><br/>
</div>
- <var:if condition="clientObject.hasSupportForDefaultRoles"
- ><input id="defaultRolesBtn" type="button"
- class="button" label:value="Default Roles"/></var:if>
+ <input id="defaultRolesBtn" type="button"
+ class="button" label:value="Default Roles"/>
<div class="userSelector" id="userRoles">
<var:if condition="currentUserIsOwner">
<span id="userSelectorButtons">
-moz-border-left-colors: #9c9a94 #000;
overflow: auto; }
-UL#contactFolders LI.denied
-{ background: #fefefe;
- font-style: italic;
- color: #f33; }
-
DIV#contactFoldersList LI
{
padding: .2em 1em;
white-space: nowrap;
}
-DIV#contactFoldersList LI._selected
-{
- background: #4b6983;
- color: #fff;
-}
-
.treecell
{
color: black;
margin-right: .2em;
}
-TABLE#contactsList TR._selected TD
-{
- background: #4b6983;
- color: #fff;
-}
-
TABLE#contactsList TR._deleted TD
{
text-decoration: line-through;
var cachedContacts = new Array();
var currentContactFolder = '/personal';
-var usersRightsWindowHeight = 180;
+var usersRightsWindowHeight = 200;
var usersRightsWindowWidth = 450;
function openContactWindow(sender, url) {
function deniedFoldersLookupCallback(http) {
if (http.readyState == 4) {
- var denied = true;
-
- if (http.status == 200)
- denied = (http.responseText == "0");
+ var denied = (http.status != 204)
var entry = $(http.callbackData);
if (denied)
entry.addClassName("denied");
UL#calendarList LI
{ white-space: nowrap; }
-UL#calendarList LI.denied
-{ background-color: #fefefe;
- font-style: italic;
- color: #f33; }
-
UL#tasksList
{ position: absolute;
width: 100%;
TABLE#appointmentsList td.headerLocation
{ width: 35%; }
-#dateSelector TD._selected,
-UL > LI._selected,
-TABLE#appointmentsList TR._selected TD
-{
- background: #4b6983 !important;
- color: #fff !important;
-}
-
._unfocused#dateSelector TD._selected,
UL._unfocused > LI._selected,
TABLE._unfocused#appointmentsList TR._selected TD
}
function calendarEntryCallback(http) {
- var disabled = true;
-
- if (http.readyState == 4) {
- if (http.status == 200)
- disabled = (http.responseText == "0");
+ if (http.readyState == 4) {
+ var denied = (http.status != 204)
var entry = $(http.callbackData);
- var input = entry.childNodesWithTag("input")[0];
- input.disabled = disabled;
- if (disabled) {
- input.checked = false;
- $(entry).addClassName("denied");
- }
+ if (denied)
+ entry.addClassName("denied");
else
- $(entry).removeClassName("denied");
+ entry.removeClassName("denied");
}
}
DIV.title
{ color: #000;
vertical-align: bottom;
- padding-top: 15px;
+ padding-top: 8px;
padding-left: 1em;
height: 33px;
background-color: #fff;
DIV.title SPAN.value
{ margin-left: 1em;
- font-size: 18px;
+ font-size: 14px;
font-weight: bold; }
DIV.calendarUserRights
DIV.title
{ color: #000;
vertical-align: bottom;
- padding-top: 15px;
+ padding-top: 8px;
padding-left: 1em;
height: 33px;
background-color: #fff;
DIV.title SPAN.value
{ margin-left: 1em;
- font-size: 18px;
+ font-size: 14px;
font-weight: bold; }
DIV.calendarUserRights
DIV.title
{ color: #000;
vertical-align: bottom;
- padding-top: 15px;
+ padding-top: 8px;
padding-left: 1em;
height: 33px;
background-color: #fff;
DIV.title SPAN.value
{ margin-left: 1em;
- font-size: 18px;
+ font-size: 14px;
font-weight: bold; }
DIV.calendarUserRights
--- /dev/null
+// written by Dean Edwards, 2005\r
+// with input from Tino Zijdel, Matthias Miller, Diego Perini\r
+// http://dean.edwards.name/weblog/2005/10/add-event/\r
+function addEvent(element, type, handler) {\r
+ // Modification by Tanny O'Haley, http://tanny.ica.com to add the\r
+ // DOMContentLoaded for all browsers.\r
+ if (type == "DOMContentLoaded" || type == "domload") {\r
+ addDOMLoadEvent(handler);\r
+ return;\r
+ }\r
+ \r
+ if (element.addEventListener) {\r
+ element.addEventListener(type, handler, false);\r
+ } else {\r
+ // assign each event handler a unique ID\r
+ if (!handler.$$guid) handler.$$guid = addEvent.guid++;\r
+ // create a hash table of event types for the element\r
+ if (!element.events) element.events = {};\r
+ // create a hash table of event handlers for each element/event pair\r
+ var handlers = element.events[type];\r
+ if (!handlers) {\r
+ handlers = element.events[type] = {};\r
+ // store the existing event handler (if there is one)\r
+ if (element["on" + type]) {\r
+ handlers[0] = element["on" + type];\r
+ }\r
+ }\r
+ // store the event handler in the hash table\r
+ handlers[handler.$$guid] = handler;\r
+ // assign a global event handler to do all the work\r
+ element["on" + type] = handleEvent;\r
+ }\r
+};\r
+// a counter used to create unique IDs\r
+addEvent.guid = 1;\r
+\r
+function removeEvent(element, type, handler) {\r
+ if (element.removeEventListener) {\r
+ element.removeEventListener(type, handler, false);\r
+ } else {\r
+ // delete the event handler from the hash table\r
+ if (element.events && element.events[type]) {\r
+ delete element.events[type][handler.$$guid];\r
+ }\r
+ }\r
+};\r
+\r
+function handleEvent(event) {\r
+ var returnValue = true;\r
+ // grab the event object (IE uses a global event object)\r
+ event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);\r
+ // get a reference to the hash table of event handlers\r
+ var handlers = this.events[event.type];\r
+ // execute each event handler\r
+ for (var i in handlers) {\r
+ this.$$handleEvent = handlers[i];\r
+ if (this.$$handleEvent(event) === false) {\r
+ returnValue = false;\r
+ }\r
+ }\r
+ return returnValue;\r
+};\r
+\r
+function fixEvent(event) {\r
+ // add W3C standard event methods\r
+ event.preventDefault = fixEvent.preventDefault;\r
+ event.stopPropagation = fixEvent.stopPropagation;\r
+ return event;\r
+};\r
+fixEvent.preventDefault = function() {\r
+ this.returnValue = false;\r
+};\r
+fixEvent.stopPropagation = function() {\r
+ this.cancelBubble = true;\r
+};\r
+\r
+// End Dean Edwards addEvent.\r
+\r
+// Tino Zijdel - crisp@xs4all.nl This little snippet fixes the problem that the onload attribute on \r
+// the body-element will overwrite previous attached events on the window object for the onload event.\r
+if (!window.addEventListener) {\r
+ document.onreadystatechange = function(){\r
+ if (window.onload && window.onload != handleEvent) {\r
+ addEvent(window, 'load', window.onload);\r
+ window.onload = handleEvent;\r
+ }\r
+ }\r
+}\r
+\r
+// Here are my functions for adding the DOMContentLoaded event to browsers other\r
+// than Mozilla.\r
+\r
+// Array of DOMContentLoaded event handlers.\r
+window.onDOMLoadEvents = new Array();\r
+window.DOMContentLoadedInitDone = false;\r
+\r
+// Function that adds DOMContentLoaded listeners to the array.\r
+function addDOMLoadEvent(listener) {\r
+ window.onDOMLoadEvents[window.onDOMLoadEvents.length]=listener;\r
+}\r
+\r
+// Function to process the DOMContentLoaded events array.\r
+function DOMContentLoadedInit() {\r
+ // quit if this function has already been called\r
+ if (window.DOMContentLoadedInitDone) return;\r
+\r
+ // flag this function so we don't do the same thing twice\r
+ window.DOMContentLoadedInitDone = true;\r
+\r
+ // iterates through array of registered functions \r
+ for (var i=0; i<window.onDOMLoadEvents.length; i++) {\r
+ var func = window.onDOMLoadEvents[i];\r
+ func();\r
+ }\r
+}\r
+\r
+function DOMContentLoadedScheduler() {\r
+ // quit if the init function has already been called\r
+ if (window.DOMContentLoadedInitDone) return true;\r
+ \r
+ // First, check for Safari or KHTML.\r
+ // Second, check for IE.\r
+ //if DOM methods are supported, and the body element exists\r
+ //(using a double-check including document.body, for the benefit of older moz builds [eg ns7.1] \r
+ //in which getElementsByTagName('body')[0] is undefined, unless this script is in the body section)\r
+ if(/KHTML|WebKit/i.test(navigator.userAgent)) {\r
+ if(/loaded|complete/.test(document.readyState)) {\r
+ DOMContentLoadedInit();\r
+ } else {\r
+ // Not ready yet, wait a little more.\r
+ setTimeout("DOMContentLoadedScheduler()", 250);\r
+ }\r
+ } else if(document.getElementById("__ie_onload")) {\r
+ return true;\r
+ } else if(typeof document.getElementsByTagName != 'undefined' && (document.getElementsByTagName('body')[0] != null || document.body != null)) {\r
+ DOMContentLoadedInit();\r
+ } else {\r
+ // Not ready yet, wait a little more.\r
+ setTimeout("DOMContentLoadedScheduler()", 250);\r
+ }\r
+ \r
+ return true;\r
+}\r
+\r
+// Schedule to run the init function.\r
+setTimeout("DOMContentLoadedScheduler()", 250);\r
+\r
+// Just in case window.onload happens first, add it there too.\r
+addEvent(window, "load", DOMContentLoadedInit);\r
+\r
+// If addEventListener supports the DOMContentLoaded event.\r
+if(document.addEventListener)\r
+ document.addEventListener("DOMContentLoaded", DOMContentLoadedInit, false);\r
+\r
+/* for Internet Explorer */\r
+/*@cc_on @*/\r
+/*@if (@_win32)\r
+ document.write("<script id=__ie_onload defer src=\"//:\"><\/script>");\r
+ var script = document.getElementById("__ie_onload");\r
+ script.onreadystatechange = function() {\r
+ if (this.readyState == "complete") {\r
+ DOMContentLoadedInit(); // call the onload handler\r
+ }\r
+ };\r
+/*@end @*/\r
{ color: #999;
background: inherit; }
+LI.denied
+{ background-color: #fefefe;
+ font-style: italic;
+ color: #f33; }
+
+LI._selected,
+TR._selected > TD,
+TD._selected
+{
+ background-color: #4b6983;
+ color: #fff;
+}
+
+LI[class~="_selected"].denied
+{
+ background-color: #f33;
+}
+
/* folder tree (js) )*/
DIV.dTreeNode A SPAN.nodeName
{