]> err.no Git - scalable-opengroupware.org/commitdiff
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1073 d1b88da0-ebda-0310...
authorwolfgang <wolfgang@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Fri, 1 Jun 2007 21:05:56 +0000 (21:05 +0000)
committerwolfgang <wolfgang@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Fri, 1 Jun 2007 21:05:56 +0000 (21:05 +0000)
56 files changed:
ChangeLog
SOPE/NGCards/iCalEntityObject.m
SoObjects/Appointments/GNUmakefile
SoObjects/Appointments/SOGoAppointmentFolder.m
SoObjects/Appointments/SOGoAppointmentObject.m
SoObjects/Appointments/SOGoCalendarComponent.h
SoObjects/Appointments/SOGoCalendarComponent.m
SoObjects/Appointments/SOGoFreeBusyObject.m
SoObjects/Appointments/iCalEntityObject+SOGo.h [new file with mode: 0644]
SoObjects/Appointments/iCalEntityObject+SOGo.m [new file with mode: 0644]
SoObjects/Appointments/product.plist
SoObjects/Contacts/SOGoContactFolder.h
SoObjects/Contacts/SOGoContactFolders.m
SoObjects/Contacts/SOGoContactGCSEntry.m
SoObjects/Contacts/SOGoContactGCSFolder.m
SoObjects/Contacts/SOGoContactLDAPFolder.h
SoObjects/Contacts/SOGoContactLDAPFolder.m
SoObjects/Contacts/product.plist
SoObjects/Mailer/SOGoMailAccount.m
SoObjects/Mailer/SOGoMailAccounts.m
SoObjects/Mailer/SOGoMailFolder.m
SoObjects/Mailer/SOGoMailObject.m
SoObjects/SOGo/NSArray+Utilities.h
SoObjects/SOGo/NSArray+Utilities.m
SoObjects/SOGo/SOGoContentObject.h
SoObjects/SOGo/SOGoContentObject.m
SoObjects/SOGo/SOGoFolder.m
SoObjects/SOGo/SOGoObject.h
SoObjects/SOGo/SOGoObject.m
SoObjects/SOGo/SOGoPermissions.h
SoObjects/SOGo/SOGoPermissions.m
SoObjects/SOGo/SOGoUser.m
UI/Common/UIxFolderActions.m
UI/Contacts/English.lproj/Localizable.strings
UI/Contacts/French.lproj/Localizable.strings
UI/Contacts/UIxContactEditor.m
UI/Contacts/UIxContactsListView.m
UI/Contacts/UIxContactsUserRightsEditor.m
UI/Contacts/product.plist
UI/MailerUI/English.lproj/Localizable.strings
UI/MailerUI/French.lproj/Localizable.strings
UI/MailerUI/UIxMailUserRightsEditor.m
UI/MailerUI/UIxMailView.m
UI/MainUI/product.plist
UI/Scheduler/UIxComponentEditor.m
UI/Templates/ContactsUI/UIxContactsUserRightsEditor.wox
UI/Templates/UIxAclEditor.wox
UI/WebServerResources/ContactsUI.css
UI/WebServerResources/ContactsUI.js
UI/WebServerResources/SchedulerUI.css
UI/WebServerResources/SchedulerUI.js
UI/WebServerResources/UIxCalUserRightsEditor.css
UI/WebServerResources/UIxContactsUserRightsEditor.css
UI/WebServerResources/UIxMailUserRightsEditor.css
UI/WebServerResources/events.js [new file with mode: 0644]
UI/WebServerResources/generic.css

index 681ee4de67d48fcbf84f7205d49d80dc21cea886..0a9ea4df2d7067706b96f3944d8971efdd0f4e62 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,142 @@
+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
index 1239e23393d9278f5a9ddd7898119773a0ec3ae9..fc75f8d45f2eaea94afc55767d0df7ee19984bcd 100644 (file)
   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
index c6effab6d6295ff4dd5fe64920aa42019e291d06..4e3d3255d6d336066b8c904e36d8ea985c697717 100644 (file)
@@ -11,6 +11,7 @@ Appointments_PRINCIPAL_CLASS = SOGoAppointmentsProduct
 Appointments_OBJC_FILES = \
        Product.m                       \
        NSArray+Appointments.m          \
+       iCalEntityObject+SOGo.m         \
        \
        SOGoCalendarComponent.m         \
        SOGoAppointmentObject.m         \
index a2cea22aca7e2da6959ddbb38b6303d4f5dc6ba7..afeee3057775407ef8d892a6bb8859f081ad91de 100644 (file)
@@ -728,12 +728,11 @@ static NSNumber   *sharedYes = nil;
 
 - (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 = @"";
@@ -793,7 +792,7 @@ static NSNumber   *sharedYes = nil;
   EOQualifier *qualifier;
   NSMutableArray *fields, *ma = nil;
   NSArray *records;
-  NSString *sql, *dateSqlString, *componentSqlString, *privacySqlString; /* , *owner; */
+  NSString *sql, *dateSqlString, *componentSqlString, *privacySqlString;
   NGCalendarDateRange *r;
 
   if (_folder == nil) {
@@ -862,7 +861,6 @@ static NSNumber   *sharedYes = nil;
       if (!ma)
         ma = [NSMutableArray arrayWithCapacity: [records count]];
 
-//       owner = [self ownerInContext: nil];
       [ma addObjectsFromArray: records];
     }
   else if (!ma)
@@ -971,8 +969,8 @@ static NSNumber   *sharedYes = nil;
     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];
@@ -990,7 +988,7 @@ static NSNumber   *sharedYes = nil;
 
   if (![_uid isNotNull])
     return nil;
-  
+
   /* create subcontext, so that we don't destroy our environment */
   
   if ((ctx = [context createSubContext]) == nil) {
@@ -1007,7 +1005,7 @@ static NSNumber   *sharedYes = 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;
   }
@@ -1257,32 +1255,32 @@ static NSNumber   *sharedYes = 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 */
 
index 691ed36edf2c743cde04d99540b2970e17856252..37a7301afcb9e6f9c58eb6f603f7f55d9ce505cc 100644 (file)
 
   /* 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 */
index 50a1cfa2a3c2d7b82d061bf11fd31b866e2197c8..5675724bf49de65546cfc50741c0dfd0d8e172cc 100644 (file)
                         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;
index e6a6a65c3f8026173c920a7e2c8763ccaf80f4dc..15242ccf9771446fbad40c24af9c976d30e461e0 100644 (file)
@@ -37,6 +37,7 @@
 #import "common.h"
 
 #import "SOGoAptMailNotification.h"
+#import "iCalEntityObject+SOGo.h"
 #import "SOGoCalendarComponent.h"
 
 static NSString *mailTemplateDefaultLanguage = nil;
@@ -111,40 +112,33 @@ static BOOL sendEMailNotifications = NO;
 
 - (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];
     }
@@ -175,7 +169,7 @@ static BOOL sendEMailNotifications = NO;
 
   if (!calendar)
     {
-      iCalString = [self contentAsString];
+      iCalString = [super contentAsString];
       if ([iCalString length] > 0)
         calendar = [iCalCalendar parseSingleFromSource: iCalString];
       else
@@ -262,7 +256,7 @@ static BOOL sendEMailNotifications = NO;
 - (NSException *) changeParticipationStatus: (NSString *) _status
 {
   iCalRepeatableEntityObject *component;
-  iCalPerson *p;
+  iCalPerson *person;
   NSString *newContent;
   NSException *ex;
   NSString *myEMail;
@@ -273,15 +267,15 @@ static BOOL sendEMailNotifications = NO;
   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 */
@@ -445,24 +439,33 @@ static BOOL sendEMailNotifications = NO;
     }
 }
 
-- (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;
@@ -534,34 +537,85 @@ static BOOL sendEMailNotifications = NO;
   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;
 }
index ae378a123822c5af27c8d58eb08bafb31b649d49..b892914c345a3a05e9e4bf156229dc03d9f984c3 100644 (file)
   return r;
 }
 
+- (NSString *) davContentType
+{
+  return @"text/calendar";
+}
+
 @end
diff --git a/SoObjects/Appointments/iCalEntityObject+SOGo.h b/SoObjects/Appointments/iCalEntityObject+SOGo.h
new file mode 100644 (file)
index 0000000..7f8702b
--- /dev/null
@@ -0,0 +1,35 @@
+/* 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 */
diff --git a/SoObjects/Appointments/iCalEntityObject+SOGo.m b/SoObjects/Appointments/iCalEntityObject+SOGo.m
new file mode 100644 (file)
index 0000000..5b100f9
--- /dev/null
@@ -0,0 +1,70 @@
+/* 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
index ff9831d06e94cb49db17dcf5c06c30290d84796d..0d2bab48b28029472c5285fd32d30a06c95de34b 100644 (file)
        "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 = {
index 904009d3aa5ac78c5b407e9fb83c1d9d519532ef..6ced261a51e212bd4755c0a191abf183da99d5fb 100644 (file)
@@ -51,7 +51,6 @@
                          andDisplayName: (NSString *) aDisplayName
                             inContainer: (SOGoObject *) aContainer;
 
-- (NSString *) nameInContainer;
 - (NSString *) displayName;
 
 - (NSArray *) lookupContactsWithFilter: (NSString *) filter
index bbe0c5f5988e3e93d7f800706911a6a42d78a068..0aeeab8fc7a834448a203c330e0500fe71714685 100644 (file)
   return YES;
 }
 
+- (NSString *) davContentType
+{
+  return @"httpd/unix-directory";
+}
+
 - (void) setBaseOCSPath: (NSString *) newOCSPath
 {
   if (OCSPath)
index 39aca0a4b2fb8396d71e63cb73dbec4dc7d99908..b56e5a92868368105e0535c6bf4f58c088610631 100644 (file)
@@ -40,8 +40,7 @@
 
 - (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];
index 42d966dc7665054e4f1988f314dcdb6fe800134a..6762c2438661af6a3ac2831cad511f86d3566ec1 100644 (file)
@@ -60,7 +60,7 @@
   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";
 }
 
index dd2f9bfc76ae447b169d510c49324f8db5cd54e9..da09d3821571de652c566d80b50057e7a401c0c6 100644 (file)
@@ -31,7 +31,6 @@
 
 @interface SOGoContactLDAPFolder : SOGoObject <SOGoContactFolder>
 {
-  NSString *name;
   NSString *displayName;
   LDAPSource *ldapSource;
   NSMutableDictionary *entries;
index 75c198947765ad87e30cab1968d2dbbf013c0179..391336392366a2eb4b39c0c79fd72852f53ad330 100644 (file)
@@ -31,6 +31,7 @@
 #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"
@@ -69,9 +70,7 @@
 {
   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 */
index 843eda8b9fa7e1e376f1c03b86fb66c93030df0c..cb6b5124dc868ad1ba6629adbc2b5d950c4b8d9e 100644 (file)
   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" );
+      };
     };
   };
 }
index 184274881e6b060313312859d309a479354f0f89..be0cea9f47a9ec1d8c9b7707cdd5492de9eb0e2a 100644 (file)
@@ -387,15 +387,24 @@ static BOOL     useAltNamespace       = NO;
 
 /* 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;
 
@@ -425,7 +434,8 @@ static BOOL     useAltNamespace       = NO;
   return [NSString stringWithFormat:@"%@@%@", login, host];
 }
 
-- (NSString *)davDisplayName {
+- (NSString *) davDisplayName
+{
   return [self shortTitle];
 }
 
index d215e8e104ef6231a73737199f1230e8612ac490..8e7c8a582e516516fd5c185222d0cedf13976d7a 100644 (file)
@@ -185,6 +185,11 @@ static NSString *AgenorShareLoginMarker  = @".-.";
   return YES;
 }
 
+- (NSString *) davContentType
+{
+  return @"httpd/unix-directory";
+}
+
 /* acls */
 
 - (NSArray *) aclsForUser: (NSString *) uid
index f3b86ab151b49c010ea2a004a244adec58500ae6..d79cb68d6e17fcf9706cadcb59376e71cf772635 100644 (file)
@@ -62,6 +62,39 @@ static BOOL useAltNamespace = NO;
   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];
@@ -115,6 +148,11 @@ static BOOL useAltNamespace = NO;
   return subfoldersURL;
 }
 
+- (NSString *) davContentType
+{
+  return @"httpd/unix-directory";
+}
+
 - (NSArray *) toOneRelationshipKeys
 {
   NSArray  *uids;
@@ -406,10 +444,10 @@ static BOOL useAltNamespace = NO;
          [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];
@@ -449,9 +487,9 @@ static BOOL useAltNamespace = NO;
        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';
@@ -562,31 +600,6 @@ static BOOL useAltNamespace = NO;
   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;
@@ -604,8 +617,7 @@ static BOOL useAltNamespace = NO;
   else
     userPath = [NSString stringWithFormat: @"/%@/%@%@",
                         [otherUsers stringByEscapingURL],
-                        [self ownerInContext: context],
-                        selfPath];
+                        owner, selfPath];
 
   return userPath;
 }
index 68ec6326ad6925dc6f9e9cddffbb6bf55424ff7f..8f91f247f3ee83385063804acb81e5981086e38a 100644 (file)
@@ -407,6 +407,11 @@ static BOOL debugSoParts       = NO;
   return [[content copy] autorelease];
 }
 
+- (NSString *) davContentType
+{
+  return @"message/rfc822";
+}
+
 - (NSString *)contentAsString {
   NSString *s;
   NSData *content;
@@ -650,10 +655,13 @@ static BOOL debugSoParts       = NO;
 
 /* 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]];
 }
 
@@ -667,7 +675,7 @@ static BOOL debugSoParts       = NO;
   login = [[context activeUser] login];
   parentAcl = [[self container] aclsForUser: login];
 
-  return [parentAcl containsObject: SOGoMailRole_MessageEraser];
+  return [parentAcl containsObject: SOGoRole_ObjectEraser];
 }
 
 /* name lookup */
index 025b2bceae8fb9bd9b144f5f333215486a124927..b330cf85435401e7623d217f6bc3c1dbb107b019 100644 (file)
@@ -33,6 +33,8 @@
 
 - (NSArray *) stringsWithFormat: (NSString *) format;
 
+- (BOOL) containsCaseInsensitiveString: (NSString *) match;
+
 #ifdef GNUSTEP_BASE_LIBRARY
 - (void) makeObjectsPerform: (SEL) selector
                  withObject: (id) object1
index 66054efb8f62a86e66284bcf861809ec9c1d7b80..77dabdcbd2c2758cfdeb9631c2f777377807e264 100644 (file)
   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)
index 9d3545b401a5722d008ec91e237bb19e433fd63e..f23f5cce076b0fc7a0c56190649912be52eded98 100644 (file)
@@ -33,6 +33,7 @@
 {
   NSString *ocsPath;
   NSString *content;
+  BOOL isNew;
 }
 
 /* accessors */
@@ -47,6 +48,7 @@
 
 /* content */
 
+- (BOOL) isNew;
 - (NSString *) contentAsString;
 - (NSException *) saveContentString: (NSString *) _str
                         baseVersion: (unsigned int) _baseVersion;
index d5153f325f52db42da0fe55e37d52b5c5b42cc8c..e771cefbd82d5efabb471a647e89b5eb52cfe168 100644 (file)
 
 // 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;
index cf5b25c2e3a2546df31f61595d003816e4ab2aa2..6dc6f4f076db83d90a379cff62b852e12cd5c533 100644 (file)
@@ -237,6 +237,11 @@ static NSString *defaultUserID = @"<default>";
   return rType;
 }
 
+- (NSString *) davContentType
+{
+  return @"httpd/unix-directory";
+}
+
 - (NSArray *) toOneRelationshipKeys {
   /* toOneRelationshipKeys are the 'files' contained in a folder */
   NSMutableArray *ma;
@@ -429,8 +434,27 @@ static NSString *defaultUserID = @"<default>";
 
 - (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
index 8d83c8d798836c05ae6b2aa18bd1a1bcb9c0b50a..8370acf9c08cfb97bb2312569cd045ed82cf22f3 100644 (file)
@@ -57,8 +57,8 @@
 {
   WOContext *context;
   NSString *nameInContainer;
-  id       container;
-  NSString *customOwner;
+  id container;
+  NSString *owner;
 }
 
 + (id) objectWithName: (NSString *)_name inContainer:(id)_container;
index cd60e58578c4ee4e46a6a9e4f66e5610bbb13827..1707caf35e8b6714e00aaea2622782883d91213c 100644 (file)
@@ -40,6 +40,7 @@
 #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>
 
@@ -76,7 +77,7 @@
 {
   return [NSDictionary dictionaryWithObjectsAndKeys:
                          @"read", SoPerm_AccessContentsInformation,
-                       @"read", SoPerm_View, 
+                         @"read", SoPerm_AccessContentsInformation,
                        @"bind", SoPerm_AddDocumentsImagesAndFiles,
                        @"unbind", SoPerm_DeleteObjects,
                        @"write-acl", SoPerm_ChangePermissions,
@@ -393,34 +394,40 @@ static BOOL kontactGroupDAV = YES;
   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];
@@ -429,10 +436,13 @@ static BOOL kontactGroupDAV = YES;
 
 /* accessors */
 
-- (NSString *)nameInContainer {
+- (NSString *) nameInContainer
+{
   return nameInContainer;
 }
-- (id)container {
+
+- (id) container
+{
   return container;
 }
 
@@ -440,18 +450,18 @@ static BOOL kontactGroupDAV = YES;
 
 - (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;
@@ -485,11 +495,13 @@ static BOOL kontactGroupDAV = YES;
   
   return [container lookupUserFolder];
 }
+
 - (SOGoGroupsFolder *)lookupGroupsFolder {
   return [[self lookupUserFolder] lookupGroupsFolder];
 }
 
-- (void)sleep {
+- (void) sleep
+{
   if ([self doesRetainContainer])
     [container release];
   container = nil;
@@ -497,26 +509,30 @@ static BOOL kontactGroupDAV = YES;
 
 /* 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)
@@ -526,44 +542,64 @@ static BOOL kontactGroupDAV = YES;
   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 */
@@ -780,12 +816,12 @@ static BOOL kontactGroupDAV = YES;
 - (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];
@@ -797,12 +833,12 @@ static BOOL kontactGroupDAV = YES;
        [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
index 2b4e60cf55c12ce113ef315e59961b0cb77ae7dd..53ed0e96552e9f6020592e858e83f60ef9d60536 100644 (file)
 #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;
@@ -46,7 +48,6 @@ extern NSString *SOGoMailRole_Poster;
 extern NSString *SOGoMailRole_Expunger;
 extern NSString *SOGoMailRole_Creator;
 extern NSString *SOGoMailRole_Administrator;
-extern NSString *SOGoMailRole_MessageEraser;
 
 extern NSString *SOGoCalendarRole_Organizer;
 extern NSString *SOGoCalendarRole_Participant;
@@ -69,6 +70,7 @@ extern NSString *SOGoCalendarRole_ComponentDAndTViewer;
 extern NSString *SOGoCalendarRole_ComponentModifier;
 extern NSString *SOGoCalendarRole_ComponentResponder;
 
+extern NSString *SOGoPerm_AccessObject;
 extern NSString *SOGoPerm_ReadAcls;
 extern NSString *SOGoPerm_FreeBusyLookup;
 
index f5cb1f172b20e22a9fe9a12b30dd3b2d58b46cd4..0e9769151561461f8472a443cc82c8f665d243c6 100644 (file)
@@ -28,10 +28,10 @@ NSString *SOGoRole_ObjectEraser = @"ObjectEraser";
 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";
 
@@ -73,6 +73,7 @@ NSString *SOGoMailRole_Administrator = @"MailAdministrator";
 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 */
index e345602a72990c458be2ac37ad2c52f231eb8dbb..d60b5dc2c2ab0a77f1e7fac101795e5929938c41 100644 (file)
 #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;
@@ -57,7 +59,7 @@ static NSURL *AgenorProfileURL = nil;
     {
       tzName = [ud stringForKey: @"SOGoServerTimeZone"];
       if (!tzName)
-        tzName = @"Canada/Eastern";
+        tzName = @"UTC";
       serverTimeZone = [NSTimeZone timeZoneWithName: tzName];
       [serverTimeZone retain];
     }
@@ -186,23 +188,10 @@ static NSURL *AgenorProfileURL = nil;
 
 - (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
index 94edaea4ad989496236b3e546ea43c5408ded4d1..ca14b9d5e55972e2b3b3e1c48159a393e9754005 100644 (file)
 - (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;
 }
index 16704ace63416d7043c24c7ffe19bdd4ce8f1f70..9f8a0ac234cf85ae8980d40dc679dfd4aac2c9bb 100644 (file)
 = "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.";
index 0d73332edea04ac72b8b3d1d86faf727958a9ed3..f0ee23b30ce7460ebe977c71aa6701a0f7535cec 100644 (file)
 = "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.";
+
index 4341f4edee387a75a62b1bd79f871a257cd30f5f..578c65ce39feffabc2249ee2624bb648d080bc30 100644 (file)
     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 */
index fc56f202dbbfaa66241e7f422b61f89cced24b38..64c8fd906dcc968642920598295a2effd4cb1792 100644 (file)
   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 */
index a6d43ee01d7ee1c4c4033d43cf0e7bc5210b813f..65cb1d11824d3e0f48fce758f31e0501aa3f5f41 100644 (file)
   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
index 48d2d3c27e52544e365d47c73497cb0ca955dc1c..cff8e800d881a19ef3c988549015a51b87a02e2f 100644 (file)
            };
           canAccessContent = {
              protectedBy = "<public>";
-              pageName    = "UIxContactsListView";
+             actionClass = "UIxFolderActions";
              actionName = "canAccessContent";
           };
         };
index 9fbaf7c286df523b0d8043aca92222fd2ec316b3..16c3021c23cc2da3d67c5c443869d5f42d8caa4e 100644 (file)
@@ -37,6 +37,7 @@
 
 /* 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";
index 7f0153861084dba52d69b585b39e9533daa5c6c5..252b1eb2413d62965f10e787f98d3b65f3d10260 100644 (file)
@@ -36,6 +36,7 @@
 
 /* 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";
index 2478b5c5ad1f94c9dedd6bf595de24ae16b5d13c..08942a3efb0139a8ba00af9dfb507775db628c2f 100644 (file)
 - (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
index 7a9027ab2f507a12ec462ac53c05c7e36e1180bf..de312aa8d6e818a9027052f77f439f3493569bd4 100644 (file)
@@ -97,37 +97,6 @@ static NSString *mailETag = nil;
                    [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 {
@@ -162,7 +131,8 @@ static NSString *mailETag = nil;
 
 /* actions */
 
-- (id)defaultAction {
+- (id) defaultAction
+{
   /* check etag to see whether we really must rerender */
   if (mailETag != nil ) {
     /*
index 2ce04921d92900785dca79529103e217f7cb8ca8..dd5f0245b5c2f7a20f5aeed07b7957790a8cb654 100644 (file)
         "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 = {
index 910fc8dc60c1e9cd33798d7f74738c8aa40aeb6d..7f7397c91d44efc0c40a9554f881b61b21b5e520 100644 (file)
 #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;
 }
index 39b25787d2e4a3c996849ffb32c94f473aed66ac..620cfd20a83b2e2f9df0c4d684f6e551c2e25d96 100644 (file)
       <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"
index 301ef5dcb4f035adbab7db6fc12aff4958f8f350..58ba94c90077a8bac3a85ade4e051d2e13380f5d 100644 (file)
@@ -22,9 +22,8 @@
        <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">
index 89eefdd8b417819bc14453fc8cc630058101655a..e11714e9aed9e452a8059f2fe0fa5857b2d68620 100644 (file)
@@ -145,11 +145,6 @@ UL#contactFolders
   -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;
@@ -158,12 +153,6 @@ DIV#contactFoldersList LI
   white-space: nowrap;
 }
 
-DIV#contactFoldersList LI._selected
-{ 
-  background: #4b6983;
-  color: #fff;
-}
-
 .treecell
 {
   color: black;
@@ -204,12 +193,6 @@ TABLE#contactsList TD IMG
   margin-right: .2em;
 }
 
-TABLE#contactsList TR._selected TD
-{ 
-  background: #4b6983;
-  color: #fff;
-}
-
 TABLE#contactsList TR._deleted TD
 { 
   text-decoration: line-through;
index 264ccac5a48f8bfc3329c76a07b5a6ca867c4887..0bfa6a7dcd3dd5f5ea2cd3c627bd13f6b460ee8e 100644 (file)
@@ -3,7 +3,7 @@
 var cachedContacts = new Array();
 var currentContactFolder = '/personal';
 
-var usersRightsWindowHeight = 180;
+var usersRightsWindowHeight = 200;
 var usersRightsWindowWidth = 450;
 
 function openContactWindow(sender, url) {
@@ -561,10 +561,7 @@ function lookupDeniedFolders() {
 
 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");
index 92f4c6e57dd2ac875abf4179373f1851fbd4209a..f127a277c0539c69c99946850e7320438652d21f 100644 (file)
@@ -81,11 +81,6 @@ UL#calendarList
 UL#calendarList LI
 { white-space: nowrap; }
 
-UL#calendarList LI.denied
-{ background-color: #fefefe;
-  font-style: italic;
-  color: #f33; }
-
 UL#tasksList
 { position: absolute;
   width: 100%;
@@ -303,14 +298,6 @@ TABLE#appointmentsList td.tbtv_subject_headercell,
 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
index 3070c492316b0137b30bc5560fca6ef9e4866548..42738a712df5ccf8ab76c8ca4dc03f6316ab109f 100644 (file)
@@ -911,20 +911,13 @@ function calendarStatusCallback(http) {
 }
 
 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");
    }
 }
 
index eaea5734bcfe88badbed627b021b8ec84a20a158..3e7b6991bc56e2530abd68afa4c19bd055a0ecd9 100644 (file)
@@ -1,7 +1,7 @@
 DIV.title
 { color: #000;
   vertical-align: bottom;
-  padding-top: 15px;
+  padding-top: 8px;
   padding-left: 1em;
   height: 33px;
   background-color: #fff;
@@ -9,7 +9,7 @@ DIV.title
 
 DIV.title SPAN.value
 { margin-left: 1em;
-  font-size: 18px;
+  font-size: 14px;
   font-weight: bold; }
 
 DIV.calendarUserRights
index eaea5734bcfe88badbed627b021b8ec84a20a158..3e7b6991bc56e2530abd68afa4c19bd055a0ecd9 100644 (file)
@@ -1,7 +1,7 @@
 DIV.title
 { color: #000;
   vertical-align: bottom;
-  padding-top: 15px;
+  padding-top: 8px;
   padding-left: 1em;
   height: 33px;
   background-color: #fff;
@@ -9,7 +9,7 @@ DIV.title
 
 DIV.title SPAN.value
 { margin-left: 1em;
-  font-size: 18px;
+  font-size: 14px;
   font-weight: bold; }
 
 DIV.calendarUserRights
index eaea5734bcfe88badbed627b021b8ec84a20a158..3e7b6991bc56e2530abd68afa4c19bd055a0ecd9 100644 (file)
@@ -1,7 +1,7 @@
 DIV.title
 { color: #000;
   vertical-align: bottom;
-  padding-top: 15px;
+  padding-top: 8px;
   padding-left: 1em;
   height: 33px;
   background-color: #fff;
@@ -9,7 +9,7 @@ DIV.title
 
 DIV.title SPAN.value
 { margin-left: 1em;
-  font-size: 18px;
+  font-size: 14px;
   font-weight: bold; }
 
 DIV.calendarUserRights
diff --git a/UI/WebServerResources/events.js b/UI/WebServerResources/events.js
new file mode 100644 (file)
index 0000000..fdf0490
--- /dev/null
@@ -0,0 +1,165 @@
+// 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
index ca630042b2c7409c9edd8e9e82848fa02a5b2a81..6c1ff9194a4bcc936baaf3ad3a6c2ecc903b7290 100644 (file)
@@ -556,6 +556,24 @@ A[class~="_disabled"].button:active
 { 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
 {