/* SOGoFolder.m - this file is part of SOGo * * Copyright (C) 2007-2009 Inverse inc. * * Author: Wolfgang Sourdeau * * 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 #import #import #import #import #import #import #import #import #import #import #import "DOMNode+SOGo.h" #import "NSArray+Utilities.h" #import "NSObject+DAV.h" #import "NSString+DAV.h" #import "NSString+Utilities.h" #import "SOGoPermissions.h" #import "SOGoWebDAVAclManager.h" #import "WOResponse+SOGo.h" #import "SOGoFolder.h" @interface SOGoObject (SOGoDAVHelpers) - (void) _fillArrayWithPrincipalsOwnedBySelf: (NSMutableArray *) hrefs; @end @interface SOGoFolder (private) - (NSArray *) _interpretWebDAVArrayValue: (id) value; - (NSDictionary *) _expandPropertyResponse: (NGDOMElement *) property forHREF: (NSString *) href; @end @implementation SOGoFolder + (SOGoWebDAVAclManager *) webdavAclManager { static SOGoWebDAVAclManager *webdavAclManager = nil; if (!webdavAclManager) { webdavAclManager = [SOGoWebDAVAclManager new]; [webdavAclManager registerDAVPermission: davElement (@"read", XMLNS_WEBDAV) abstract: YES withEquivalent: SoPerm_WebDAVAccess asChildOf: davElement (@"all", XMLNS_WEBDAV)]; [webdavAclManager registerDAVPermission: davElement (@"read-current-user-privilege-set", XMLNS_WEBDAV) abstract: YES withEquivalent: nil asChildOf: davElement (@"read", XMLNS_WEBDAV)]; } return webdavAclManager; } - (id) init { if ((self = [super init])) { displayName = nil; isSubscription = NO; } return self; } - (void) dealloc { [displayName release]; [super dealloc]; } - (void) setDisplayName: (NSString *) newDisplayName { ASSIGN (displayName, newDisplayName); } - (NSString *) displayName { return ((id)displayName ? (id)displayName : (id)nameInContainer); } - (void) setIsSubscription: (BOOL) newIsSubscription { isSubscription = newIsSubscription; } - (BOOL) isSubscription { return isSubscription; } - (NSString *) realNameInContainer { NSString *realNameInContainer, *ownerName; if (isSubscription) { ownerName = [[self ownerInContext: context] asCSSIdentifier]; realNameInContainer = [nameInContainer substringFromIndex: [ownerName length] + 1]; } else realNameInContainer = nameInContainer; return realNameInContainer; } - (NSString *) folderType { [self subclassResponsibility: _cmd]; return nil; } #warning we should remove this method - (NSArray *) toOneRelationshipKeys { return [self fetchContentObjectNames]; } - (NSArray *) fetchContentObjectNames { return [NSArray array]; } - (NSArray *) toManyRelationshipKeys { return nil; } - (BOOL) isValidContentName: (NSString *) name { return ([name length] > 0); } - (BOOL) isFolderish { return YES; } - (NSString *) davURLAsString { return [[container davURLAsString] stringByAppendingFormat: @"%@/", nameInContainer]; } - (NSString *) httpURLForAdvisoryToUser: (NSString *) uid { return [[self soURL] absoluteString]; } - (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid { return [[self davURL] absoluteString]; } /* sorting */ - (NSComparisonResult) _compareByOrigin: (SOGoFolder *) otherFolder { NSComparisonResult comparison; if (isSubscription == [otherFolder isSubscription]) comparison = NSOrderedSame; else { if (isSubscription) comparison = NSOrderedDescending; else comparison = NSOrderedAscending; } return comparison; } - (NSComparisonResult) _compareByNameInContainer: (SOGoFolder *) otherFolder { NSString *selfName, *otherName; NSComparisonResult comparison; selfName = [self realNameInContainer]; otherName = [otherFolder realNameInContainer]; if ([selfName isEqualToString: @"personal"]) { if ([otherName isEqualToString: @"personal"]) comparison = NSOrderedSame; else comparison = NSOrderedAscending; } else { if ([otherName isEqualToString: @"personal"]) comparison = NSOrderedDescending; else comparison = NSOrderedSame; } return comparison; } - (NSComparisonResult) compare: (id) otherFolder { NSComparisonResult comparison; comparison = [self _compareByOrigin: otherFolder]; if (comparison == NSOrderedSame) { comparison = [self _compareByNameInContainer: otherFolder]; if (comparison == NSOrderedSame) comparison = [[self displayName] localizedCaseInsensitiveCompare: [otherFolder displayName]]; } return comparison; } /* WebDAV */ - (NSString *) davContentType { return @"httpd/unix-directory"; } - (NSArray *) davResourceType { NSArray *rType, *groupDavCollection; if ([self respondsToSelector: @selector (groupDavResourceType)]) { groupDavCollection = [NSArray arrayWithObjects: [self groupDavResourceType], XMLNS_GROUPDAV, nil]; rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil]; } else rType = [NSArray arrayWithObject: @"collection"]; return rType; } - (BOOL) davIsCollection { return YES; } - (NSArray *) _extractHREFSFromPropertyValues: (NSArray *) values { NSMutableArray *hrefs; NSDictionary *value; int count, max; max = [values count]; hrefs = [NSMutableArray arrayWithCapacity: max]; for (count = 0; count < max; count++) { value = [values objectAtIndex: count]; if ([value isKindOfClass: [NSDictionary class]]) { if ([[value objectForKey: @"method"] isEqualToString: @"href"]) [hrefs addObject: [value objectForKey: @"content"]]; else [self errorWithFormat: @"value is not an href"]; } else if ([value isKindOfClass: [NSString class]]) { /* we extract the text between XXX, but in a bad way */ [hrefs addObject: [(NSString *) value removeOutsideTags]]; } else [self errorWithFormat: @"value class is '%@' instead of NSDictionary", NSStringFromClass ([value class])]; } return hrefs; } - (NSArray *) _interpretSoWebDAVValue: (SoWebDAVValue *) value { NSString *valueString; valueString = [value stringForTag: @"" rawName: @"" inContext: context prefixes: nil]; return [NSArray arrayWithObject: [valueString removeOutsideTags]]; } - (NSArray *) _interpretWebDAVValue: (id) value { NSArray *result; if ([value isKindOfClass: [NSString class]]) result = [NSArray arrayWithObject: value]; else if ([value isKindOfClass: [SoWebDAVValue class]]) result = [self _interpretSoWebDAVValue: value]; else if ([value isKindOfClass: [NSArray class]]) result = [self _interpretWebDAVArrayValue: value]; else result = nil; return result; } - (NSArray *) _interpretWebDAVArrayValue: (id) value { int count, max; NSMutableArray *results; id subValue, subResults; max = [value count]; results = [NSMutableArray arrayWithCapacity: max]; if (max > 0) { subValue = [value objectAtIndex: 0]; if ([subValue isKindOfClass: [NSString class]]) [results addObject: davElementWithContent (subValue, [value objectAtIndex: 1], [value objectAtIndex: 3])]; else { for (count = 0; count < max; count++) { subResults = [self _interpretWebDAVValue: [value objectAtIndex: count]]; [results addObjectsFromArray: subResults]; } } } return results; } - (NSArray *) _expandedPropertyValue: (NGDOMElement *) property forObject: (SOGoObject *) currentObject { NSString *propertyTag; SEL propertySel; id value; propertyTag = [property asPropertyPropertyName]; propertySel = [self davPropertySelectorForKey: propertyTag]; if (propertySel) value = [currentObject performSelector: propertySel]; else value = nil; return [self _interpretWebDAVValue: value]; } - (NSArray *) _expandPropertyValue: (NGDOMElement *) property forObject: (SOGoObject *) currentObject { NSArray *values, *hrefs; NSString *href; NSMutableArray *expandedValues; int count, max; BOOL needsExpansion; needsExpansion = ([[property childElementsWithTag: @"property"] length] > 0); values = [self _expandedPropertyValue: property forObject: currentObject]; max = [values count]; expandedValues = [NSMutableArray arrayWithCapacity: max]; if (max) { if (needsExpansion) { hrefs = [self _extractHREFSFromPropertyValues: values]; max = [hrefs count]; for (count = 0; count < max; count++) { href = [hrefs objectAtIndex: count]; [expandedValues addObject: [self _expandPropertyResponse: property forHREF: href]]; } } else [expandedValues setArray: values]; } return expandedValues; } - (NSDictionary *) _expandPropertyResponse: (NGDOMElement *) property forObject: (SOGoObject *) currentObject { id properties; NSArray *childValue; NGDOMElement *childProperty; NSDictionary *response; NSMutableArray *properties200, *properties404; int count, max; NSString *tagName, *tagNS; properties = [property childElementsWithTag: @"property"]; max = [properties length]; properties200 = [NSMutableArray arrayWithCapacity: max]; properties404 = [NSMutableArray arrayWithCapacity: max]; for (count = 0; count < max; count++) { childProperty = [properties objectAtIndex: count]; childValue = [self _expandPropertyValue: childProperty forObject: currentObject]; tagNS = [childProperty attribute: @"namespace"]; if (!tagNS) tagNS = XMLNS_WEBDAV; tagName = [childProperty attribute: @"name"]; if ([childValue count]) [properties200 addObject: davElementWithContent (tagName, tagNS, childValue)]; else [properties404 addObject: davElement (tagName, tagNS)]; } response = [self responseForURL: [currentObject davURLAsString] withProperties200: properties200 andProperties404: properties404]; return response; } - (NSDictionary *) _expandPropertyResponse: (NGDOMElement *) property forHREF: (NSString *) href { SOGoObject *lookupObject; NSDictionary *response; lookupObject = [self lookupObjectAtDAVUrl: href]; if (lookupObject) response = [self _expandPropertyResponse: property forObject: lookupObject]; else response = nil; return response; } - (WOResponse *) davExpandProperty: (WOContext *) localContext { WOResponse *r; id document; NSDictionary *response, *multistatus; NGDOMElement *documentElement; r = [localContext response]; [r prepareDAVResponse]; document = [[context request] contentAsDOMDocument]; documentElement = (NGDOMElement *) [document documentElement]; response = [self _expandPropertyResponse: documentElement forObject: self]; multistatus = davElementWithContent (@"multistatus", XMLNS_WEBDAV, response); [r appendContentString: [multistatus asWebDavStringWithNamespaces: nil]]; return r; } /* web dav acl helper */ - (void) _fillArrayWithPrincipalsOwnedBySelf: (NSMutableArray *) hrefs { NSEnumerator *children; NSString *currentKey; [super _fillArrayWithPrincipalsOwnedBySelf: hrefs]; children = [[self toOneRelationshipKeys] objectEnumerator]; while ((currentKey = [children nextObject])) [[self lookupName: currentKey inContext: context acquire: NO] _fillArrayWithPrincipalsOwnedBySelf: hrefs]; children = [[self toManyRelationshipKeys] objectEnumerator]; while ((currentKey = [children nextObject])) [[self lookupName: currentKey inContext: context acquire: NO] _fillArrayWithPrincipalsOwnedBySelf: hrefs]; } - (NSArray *) davGroupMemberSet { return [NSArray array]; } - (NSArray *) davGroupMembership { return [NSArray array]; } /* folder type */ - (BOOL) isEqual: (id) otherFolder { return ([otherFolder class] == [self class] && [container isEqual: [otherFolder container]] && [nameInContainer isEqualToString: [otherFolder nameInContainer]]); } - (NSString *) outlookFolderClass { [self subclassResponsibility: _cmd]; return nil; } /* acls */ - (NSString *) defaultUserID { return nil; } - (NSArray *) subscriptionRoles { return [NSArray arrayWithObjects: SoRole_Owner, SOGoRole_ObjectViewer, SOGoRole_ObjectEditor, SOGoRole_ObjectCreator, SOGoRole_ObjectEraser, nil]; } - (NSArray *) aclsForUser: (NSString *) uid { return nil; } - (NSArray *) aclUsers { return nil; } @end