[CalendarServer-changes] [5942] CalendarServer/branches/new-store-no-caldavfile-2/twistedcaldav/ static.py

source_changes at macosforge.org source_changes at macosforge.org
Mon Jul 26 12:45:32 PDT 2010


Revision: 5942
          http://trac.macosforge.org/projects/calendarserver/changeset/5942
Author:   glyph at apple.com
Date:     2010-07-26 12:45:31 -0700 (Mon, 26 Jul 2010)
Log Message:
-----------
re-remove (not sure why this didn't get picked up in the merge)

Removed Paths:
-------------
    CalendarServer/branches/new-store-no-caldavfile-2/twistedcaldav/static.py

Deleted: CalendarServer/branches/new-store-no-caldavfile-2/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile-2/twistedcaldav/static.py	2010-07-26 19:44:40 UTC (rev 5941)
+++ CalendarServer/branches/new-store-no-caldavfile-2/twistedcaldav/static.py	2010-07-26 19:45:31 UTC (rev 5942)
@@ -1,2129 +0,0 @@
-# -*- test-case-name: twistedcaldav.test -*-
-##
-# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-
-"""
-CalDAV-aware static resources.
-"""
-
-__all__ = [
-    "CalDAVFile",
-    "AutoProvisioningFileMixIn",
-    "CalendarHomeProvisioningFile",
-    "CalendarHomeUIDProvisioningFile",
-    "CalendarHomeFile",
-    "ScheduleFile",
-    "ScheduleInboxFile",
-    "ScheduleOutboxFile",
-    "IScheduleInboxFile",
-    "DropBoxHomeFile",
-    "DropBoxCollectionFile",
-    "DropBoxChildFile",
-    "TimezoneServiceFile",
-    "NotificationCollectionFile",
-    "NotificationFile",
-    "AddressBookHomeProvisioningFile",
-    "AddressBookHomeUIDProvisioningFile",
-    "AddressBookHomeFile",
-    "DirectoryBackedAddressBookFile",
-    "GlobalAddressBookFile",
-]
-
-import datetime
-import os
-import errno
-from urlparse import urlsplit
-from uuid import uuid4
-
-from twext.python.log import Logger
-
-from twisted.internet.defer import fail, succeed, inlineCallbacks, returnValue, maybeDeferred
-from twisted.python.failure import Failure
-from twext.python.filepath import CachingFilePath as FilePath
-from twext.web2 import responsecode, http, http_headers
-from twext.web2.http import HTTPError, StatusResponse
-from twext.web2.dav import davxml
-from twext.web2.dav.element.base import dav_namespace
-from twext.web2.dav.fileop import mkcollection, rmdir
-from twext.web2.dav.http import ErrorResponse, MultiStatusResponse
-from twext.web2.dav.idav import IDAVResource
-from twext.web2.dav.method import put_common, delete_common
-from twext.web2.dav.noneprops import NonePropertyStore
-from twext.web2.dav.resource import AccessDeniedError
-from twext.web2.dav.resource import davPrivilegeSet
-from twext.web2.dav.util import parentForURL, bindMethods, joinURL
-from twext.web2.http_headers import generateContentType, MimeType
-from txdav.idav import AlreadyFinishedError
-
-from twistedcaldav import caldavxml
-from twistedcaldav import carddavxml
-from twistedcaldav import customxml
-from twistedcaldav.caldavxml import caldav_namespace
-from twistedcaldav.client.reverseproxy import ReverseProxyResource
-from twistedcaldav.config import config
-from twistedcaldav.customxml import TwistedCalendarAccessProperty, TwistedScheduleMatchETags
-from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
-from twistedcaldav.directory.internal import InternalDirectoryRecord
-from twistedcaldav.directory.util import NotFilePath
-from twistedcaldav.extensions import DAVFile, CachingPropertyStore
-from twistedcaldav.linkresource import LinkResource, LinkFollowerMixIn
-from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
-
-from twistedcaldav.freebusyurl import FreeBusyURLResource
-from twistedcaldav.ical import Component as iComponent
-from twistedcaldav.ical import Property as iProperty
-from twistedcaldav.index import Index, IndexSchedule, SyncTokenValidException
-from twistedcaldav.resource import CalDAVResource, isCalendarCollectionResource, isPseudoCalendarCollectionResource
-from twistedcaldav.resource import isAddressBookCollectionResource
-from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource, IScheduleInboxResource
-from twistedcaldav.datafilters.privateevents import PrivateEventFilter
-from twistedcaldav.dropbox import DropBoxHomeResource, DropBoxCollectionResource
-from twistedcaldav.directorybackedaddressbook import DirectoryBackedAddressBookResource
-from twistedcaldav.directory.addressbook import uidsResourceName as uidsResourceNameAddressBook,\
-    GlobalAddressBookResource
-from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeProvisioningResource
-from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeTypeProvisioningResource
-from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeUIDProvisioningResource
-from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeResource
-from twistedcaldav.directory.calendar import uidsResourceName
-from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
-from twistedcaldav.directory.calendar import DirectoryCalendarHomeTypeProvisioningResource
-from twistedcaldav.directory.calendar import DirectoryCalendarHomeUIDProvisioningResource
-from twistedcaldav.directory.calendar import DirectoryCalendarHomeResource
-from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn
-from twistedcaldav.sharing import SharedHomeMixin
-from twistedcaldav.timezoneservice import TimezoneServiceResource
-from twistedcaldav.vcardindex import AddressBookIndex
-from twistedcaldav.notify import getPubSubConfiguration, getPubSubXMPPURI
-from twistedcaldav.notify import getPubSubHeartbeatURI, getPubSubPath
-from twistedcaldav.notify import ClientNotifier, getNodeCacher
-from twistedcaldav.notifications import NotificationCollectionResource,\
-    NotificationResource
-
-log = Logger()
-
-class ReadOnlyResourceMixIn(object):
-
-    def http_PUT        (self, request): return responsecode.FORBIDDEN
-    def http_COPY       (self, request): return responsecode.FORBIDDEN
-    def http_MOVE       (self, request): return responsecode.FORBIDDEN
-    def http_DELETE     (self, request): return responsecode.FORBIDDEN
-    def http_MKCOL      (self, request): return responsecode.FORBIDDEN
-
-    def http_MKCALENDAR(self, request):
-        return ErrorResponse(
-            responsecode.FORBIDDEN,
-            (caldav_namespace, "calendar-collection-location-ok")
-        )
-
-
-
-class CalDAVFile (LinkFollowerMixIn, CalDAVResource, DAVFile):
-    """
-    CalDAV-accessible L{DAVFile} resource.
-    """
-#    def __repr__(self):
-#        if self.isCalendarCollection():
-#            return "<%s (calendar collection): %s>" % (self.__class__.__name__, self.fp.path)
-#        else:
-#            return super(CalDAVFile, self).__repr__()
-
-    def __eq__(self, other):
-        if not isinstance(other, CalDAVFile):
-            return False
-        return self.fp.path == other.fp.path
-
-    def checkPreconditions(self, request):
-        """
-        We override the base class to handle the special implicit scheduling weak ETag behavior
-        for compatibility with old clients using If-Match.
-        """
-        
-        if config.Scheduling.CalDAV.ScheduleTagCompatibility:
-            
-            if self.exists() and self.hasDeadProperty(TwistedScheduleMatchETags):
-                etags = self.readDeadProperty(TwistedScheduleMatchETags).children
-                if len(etags) > 1:
-                    # This is almost verbatim from twext.web2.static.checkPreconditions
-                    if request.method not in ("GET", "HEAD"):
-                        
-                        # Loop over each tag and succeed if any one matches, else re-raise last exception
-                        exists = self.exists()
-                        last_modified = self.lastModified()
-                        last_exception = None
-                        for etag in etags:
-                            try:
-                                http.checkPreconditions(
-                                    request,
-                                    entityExists = exists,
-                                    etag = http_headers.ETag(etag),
-                                    lastModified = last_modified,
-                                )
-                            except HTTPError, e:
-                                last_exception = e
-                            else:
-                                break
-                        else:
-                            if last_exception:
-                                raise last_exception
-            
-                    # Check per-method preconditions
-                    method = getattr(self, "preconditions_" + request.method, None)
-                    if method:
-                        response = maybeDeferred(method, request)
-                        response.addCallback(lambda _: request)
-                        return response
-                    else:
-                        return None
-
-        return super(CalDAVFile, self).checkPreconditions(request)
-
-    def deadProperties(self, caching=True):
-        if not hasattr(self, "_dead_properties"):
-            # FIXME: this code should actually be dead, as the property store
-            # should be initialized as part of the traversal process.
- 
-            # Get the property store from super
-            deadProperties = super(CalDAVFile, self).deadProperties()
-
-            if caching:
-                # Wrap the property store in a memory store
-                deadProperties = CachingPropertyStore(deadProperties)
-
-            self._dead_properties = deadProperties
-
-        return self._dead_properties
-
-    ##
-    # CalDAV
-    ##
-
-    def createCalendar(self, request):
-        """
-        External API for creating a calendar.  Verify that the parent is a
-        collection, exists, is I{not} a calendar collection; that this resource
-        does not yet exist, then create it.
-
-        @param request: the request used to look up parent resources to
-            validate.
-
-        @type request: L{twext.web2.iweb.IRequest}
-
-        @return: a deferred that fires when a calendar collection has been
-            created in this resource.
-        """
-        if self.fp.exists():
-            log.err("Attempt to create collection where file exists: %s" % (self.fp.path,))
-            raise HTTPError(StatusResponse(responsecode.NOT_ALLOWED, "File exists"))
-
-        # newStore guarantees that we always have a parent calendar home
-        #if not self.fp.parent().isdir():
-        #    log.err("Attempt to create collection with no parent: %s" % (self.fp.path,))
-        #    raise HTTPError(StatusResponse(responsecode.CONFLICT, "No parent collection"))
-
-        #
-        # Verify that no parent collection is a calendar also
-        #
-        log.msg("Creating calendar collection %s" % (self,))
-
-        def _defer(parent):
-            if parent is not None:
-                log.err("Cannot create a calendar collection within a calendar collection %s" % (parent,))
-                raise HTTPError(ErrorResponse(
-                    responsecode.FORBIDDEN,
-                    (caldavxml.caldav_namespace, "calendar-collection-location-ok")
-                ))
-
-            return self.createCalendarCollection()
-
-        parent = self._checkParents(request, isPseudoCalendarCollectionResource)
-        parent.addCallback(_defer)
-        return parent
-
-
-    def createCalendarCollection(self):
-        """
-        Internal API for creating a calendar collection.
-
-        This will immediately create the collection without performing any
-        verification.  For the normal API, see L{CalDAVFile.createCalendar}.
-
-        The default behavior is to return a failing Deferred; for a working
-        implementation, see L{twistedcaldav.legacy}.
-
-        @return: a L{Deferred} which fires when the underlying collection has
-            actually been created.
-        """
-        return fail(NotImplementedError())
-
-
-    def createSpecialCollection(self, resourceType=None):
-        #
-        # Create the collection once we know it is safe to do so
-        #
-        def onCollection(status):
-            if status != responsecode.CREATED:
-                raise HTTPError(status)
-
-            self.writeDeadProperty(resourceType)
-            return status
-
-        def onError(f):
-            try:
-                rmdir(self.fp)
-            except Exception, e:
-                log.err("Unable to clean up after failed MKCOL (special resource type: %s): %s" % (e, resourceType,))
-            return f
-
-        d = mkcollection(self.fp)
-        if resourceType is not None:
-            d.addCallback(onCollection)
-        d.addErrback(onError)
-        return d
-
-    @inlineCallbacks
-    def iCalendarRolledup(self, request):
-        if self.isPseudoCalendarCollection():
-
-
-# FIXME: move cache implementation!
-            # Determine the cache key
-#            isvirt = (yield self.isVirtualShare(request))
-#            if isvirt:
-#                principal = (yield self.resourceOwnerPrincipal(request))
-#                if principal:
-#                    cacheKey = principal.principalUID()
-#                else:
-#                    cacheKey = "unknown"
-#            else:
-#                isowner = (yield self.isOwner(request, adminprincipals=True, readprincipals=True))
-#                cacheKey = "owner" if isowner else "notowner"
-                
-            # Now check for a cached .ics
-#            rolled = self.fp.child(".subscriptions")
-#            if not rolled.exists():
-#                try:
-#                    rolled.makedirs()
-#                except IOError, e:
-#                    log.err("Unable to create internet calendar subscription cache directory: %s because of: %s" % (rolled.path, e,))
-#                    raise HTTPError(ErrorResponse(responsecode.INTERNAL_SERVER_ERROR))
-#            cached = rolled.child(cacheKey)
-#            if cached.exists():
-#                try:
-#                    cachedData = cached.open().read()
-#                except IOError, e:
-#                    log.err("Unable to open or read internet calendar subscription cache file: %s because of: %s" % (cached.path, e,))
-#                else:
-#                    # Check the cache token
-#                    token, data = cachedData.split("\r\n", 1)
-#                    if token == self.getSyncToken():
-#                        returnValue(data)
-
-            # Generate a monolithic calendar
-            calendar = iComponent("VCALENDAR")
-            calendar.addProperty(iProperty("VERSION", "2.0"))
-
-            # Do some optimisation of access control calculation by determining any inherited ACLs outside of
-            # the child resource loop and supply those to the checkPrivileges on each child.
-            filteredaces = (yield self.inheritedACEsforChildren(request))
-
-            tzids = set()
-            isowner = (yield self.isOwner(request, adminprincipals=True, readprincipals=True))
-            accessPrincipal = (yield self.resourceOwnerPrincipal(request))
-
-            for name, uid, type in self.index().bruteForceSearch(): #@UnusedVariable
-                try:
-                    child = yield request.locateChildResource(self, name)
-                    child = IDAVResource(child)
-                except TypeError:
-                    child = None
-
-                if child is not None:
-                    # Check privileges of child - skip if access denied
-                    try:
-                        yield child.checkPrivileges(request, (davxml.Read(),), inherited_aces=filteredaces)
-                    except AccessDeniedError:
-                        continue
-
-                    # Get the access filtered view of the data
-                    caldata = child.iCalendarTextFiltered(isowner, accessPrincipal.principalUID() if accessPrincipal else "")
-                    try:
-                        subcalendar = iComponent.fromString(caldata)
-                    except ValueError:
-                        continue
-                    assert subcalendar.name() == "VCALENDAR"
-
-                    for component in subcalendar.subcomponents():
-                        
-                        # Only insert VTIMEZONEs once
-                        if component.name() == "VTIMEZONE":
-                            tzid = component.propertyValue("TZID")
-                            if tzid in tzids:
-                                continue
-                            tzids.add(tzid)
-
-                        calendar.addComponent(component)
-
-            # Cache the data
-            data = str(calendar)
-            data = self.getSyncToken() + "\r\n" + data
-#            try:
-#                cached.open(mode='w').write(data)
-#            except IOError, e:
-#                log.err("Unable to open or write internet calendar subscription cache file: %s because of: %s" % (cached.path, e,))
-                
-            returnValue(calendar)
-
-        raise HTTPError(ErrorResponse(responsecode.BAD_REQUEST))
-
-    def iCalendarTextFiltered(self, isowner, accessUID=None):
-        try:
-            access = self.readDeadProperty(TwistedCalendarAccessProperty)
-        except HTTPError:
-            access = None
-
-        # Now "filter" the resource calendar data
-        caldata = PrivateEventFilter(access, isowner).filter(self.iCalendarText())
-        if accessUID:
-            caldata = PerUserDataFilter(accessUID).filter(caldata)
-        return str(caldata)
-
-    def iCalendarText(self, name=None):
-        if self.isPseudoCalendarCollection():
-            if name is None:
-                return str(self.iCalendar())
-
-            try:
-                calendar_file = self.fp.child(name).open()
-            except IOError, e:
-                if e[0] == errno.ENOENT: return None
-                raise
-
-        elif self.isCollection():
-            return None
-
-        else:
-            if name is not None:
-                raise AssertionError("name must be None for non-collection calendar resource")
-
-            calendar_file = self.fp.open()
-
-        # FIXME: This is blocking I/O
-        try:
-            calendar_data = calendar_file.read()
-        finally:
-            calendar_file.close()
-
-        return calendar_data
-
-    def createAddressBook(self, request):
-        """
-        External API for creating an addressbook.  Verify that the parent is a
-        collection, exists, is I{not} an addressbook collection; that this resource
-        does not yet exist, then create it.
-
-        @param request: the request used to look up parent resources to
-            validate.
-
-        @type request: L{twext.web2.iweb.IRequest}
-
-        @return: a deferred that fires when an addressbook collection has been
-            created in this resource.
-        """
-        #
-        # request object is required because we need to validate against parent
-        # resources, and we need the request in order to locate the parents.
-        #
-
-        if self.fp.exists():
-            log.err("Attempt to create collection where file exists: %s" % (self.fp.path,))
-            raise HTTPError(StatusResponse(responsecode.NOT_ALLOWED, "File exists"))
-
-        # newStore guarantees that we always have a parent calendar home
-        #if not os.path.isdir(os.path.dirname(self.fp.path)):
-        #    log.err("Attempt to create collection with no parent: %s" % (self.fp.path,))
-        #    raise HTTPError(StatusResponse(responsecode.CONFLICT, "No parent collection"))
-
-        #
-        # Verify that no parent collection is a calendar also
-        #
-        log.msg("Creating address book collection %s" % (self,))
-
-        def _defer(parent):
-            if parent is not None:
-                log.err("Cannot create an address book collection within an address book collection %s" % (parent,))
-                raise HTTPError(ErrorResponse(
-                    responsecode.FORBIDDEN,
-                    (carddavxml.carddav_namespace, "addressbook-collection-location-ok")
-                ))
-
-            return self.createAddressBookCollection()
-
-        parent = self._checkParents(request, isAddressBookCollectionResource)
-        parent.addCallback(_defer)
-        return parent
-
-    def createAddressBookCollection(self):
-        """
-        Internal API for creating an addressbook collection.
-
-        This will immediately create the collection without performing any
-        verification.  For the normal API, see L{CalDAVFile.createAddressBook}.
-
-        The default behavior is to return a failing Deferred; for a working
-        implementation, see L{twistedcaldav.legacy}.
-
-        @return: a L{Deferred} which fires when the underlying collection has
-            actually been created.
-        """
-        return fail(NotImplementedError())
-
-    @inlineCallbacks
-    def vCardRolledup(self, request):
-        # TODO: just catenate all the vCards together 
-        yield fail(HTTPError((ErrorResponse(responsecode.BAD_REQUEST))))
-
-    def vCardText(self, name=None):
-        if self.isAddressBookCollection():
-            if name is None:
-                return str(self.vCard())
-
-            try:
-                vcard_file = self.fp.child(name).open()
-            except IOError, e:
-                if e[0] == errno.ENOENT: return None
-                raise
-
-        elif self.isCollection():
-            return None
-
-        else:
-            if name is not None:
-                raise AssertionError("name must be None for non-collection vcard resource")
-
-            vcard_file = self.fp.open()
-
-        # FIXME: This is blocking I/O
-        try:
-            vcard_data = vcard_file.read()
-        finally:
-            vcard_file.close()
-
-        return vcard_data
-
-    def vCardXML(self, name=None):
-        return carddavxml.AddressData.fromAddressData(self.vCardText(name))
-
-    def supportedPrivileges(self, request):
-        # read-free-busy support on calendar collection and calendar object resources
-        if self.isCollection():
-            return succeed(calendarPrivilegeSet)
-        else:
-            def gotParent(parent):
-                if parent and isCalendarCollectionResource(parent):
-                    return succeed(calendarPrivilegeSet)
-                else:
-                    return super(CalDAVFile, self).supportedPrivileges(request)
-
-            d = self.locateParent(request, request.urlForResource(self))
-            d.addCallback(gotParent)
-            return d
-
-        return super(CalDAVFile, self).supportedPrivileges(request)
-
-    ##
-    # Public additions
-    ##
-
-    def index(self):
-        """
-        Obtains the index for a calendar collection resource.
-        @return: the index object for this resource.
-        @raise AssertionError: if this resource is not a calendar collection
-            resource.
-        """
-        if self.isAddressBookCollection():
-            return AddressBookIndex(self)
-        else:
-            return Index(self)
-
-    def whatchanged(self, client_token):
-        
-        current_token = str(self.readDeadProperty(customxml.GETCTag))
-        current_uuid, current_revision = current_token.split("#", 1)
-        current_revision = int(current_revision)
-
-        if client_token:
-            try:
-                caluuid, revision = client_token.split("#", 1)
-                revision = int(revision)
-                
-                # Check client token validity
-                if caluuid != current_uuid:
-                    raise ValueError
-                if revision > current_revision:
-                    raise ValueError
-            except ValueError:
-                raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (dav_namespace, "valid-sync-token")))
-        else:
-            revision = 0
-
-        try:
-            changed, removed = self.index().whatchanged(revision)
-        except SyncTokenValidException:
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (dav_namespace, "valid-sync-token")))
-
-        return changed, removed, current_token
-
-    @inlineCallbacks
-    def bumpSyncToken(self):
-        """
-        Increment the sync-token which is also the ctag.
-        
-        return: a deferred that returns the new revision number
-        """
-        assert self.isCollection()
-        
-        # Need to lock
-        lock = MemcacheLock("ResourceLock", self.fp.path, timeout=60.0)
-        try:
-            try:
-                yield lock.acquire()
-            except MemcacheLockTimeoutError:
-                raise HTTPError(StatusResponse(responsecode.CONFLICT, "Resource: %s currently in use on the server." % (self.uri,)))
-
-            try:
-                token = str(self.readDeadProperty(customxml.GETCTag))
-                caluuid, revision = token.split("#", 1)
-                revision = int(revision) + 1
-                token = "%s#%d" % (caluuid, revision,)
-    
-            except (HTTPError, ValueError):
-                # Initialise it
-                caluuid = uuid4()
-                revision = 1
-                token = "%s#%d" % (caluuid, revision,)
-    
-            yield self.updateCTag(token)
-            returnValue(revision)
-        finally:
-            yield lock.clean()
-
-    def initSyncToken(self):
-        """
-        Create a new sync-token which is also the ctag.
-        """
-        # FIXME: new implementation is in txcaldav.file, this should be
-        # deleted.
-        assert self.isCollection()
-        # Initialise it
-        caluuid = uuid4()
-        revision = 1
-        token = "%s#%d" % (caluuid, revision,)
-        try:
-            self.writeDeadProperty(customxml.GETCTag(token))
-        except:
-            return fail(Failure())
-
-    def getSyncToken(self):
-        """
-        Return current sync-token value.
-        """
-        assert self.isCollection()
-        
-        return str(self.readDeadProperty(customxml.GETCTag))
-
-    def updateCTag(self, token=None):
-        assert self.isCollection()
-        
-        if not token:
-            token = str(datetime.datetime.now())
-        try:
-            self.writeDeadProperty(customxml.GETCTag(token))
-        except:
-            return fail(Failure())
-
-        if hasattr(self, 'clientNotifier'):
-            self.clientNotifier.notify(op="update")
-
-        return succeed(True)
-
-    ##
-    # File
-    ##
-
-    def listChildren(self):
-        return [
-            child for child in super(CalDAVFile, self).listChildren()
-            if not child.startswith(".")
-        ]
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-
-        similar = super(CalDAVFile, self).createSimilarFile(path)
-
-        if isCalendarCollectionResource(self):
-            raise RuntimeError("Calendar collection resources should really "
-                               "be represented by a different class.")
-
-        return similar
-
-    ##
-    # Quota
-    ##
-
-    def quotaSize(self, request):
-        """
-        Get the size of this resource.
-        TODO: Take into account size of dead-properties. Does stat include xattrs size?
-
-        @return: an L{Deferred} with a C{int} result containing the size of the resource.
-        """
-        if self.isCollection():
-            @inlineCallbacks
-            def walktree(top):
-                """
-                Recursively descend the directory tree rooted at top,
-                calling the callback function for each regular file
-
-                @param top: L{FilePath} for the directory to walk.
-                """
-
-                total = 0
-                for f in top.listdir():
-
-                    # Ignore the database
-                    if f.startswith("."):
-                        continue
-
-                    child = top.child(f)
-                    if child.isdir():
-                        # It's a directory, recurse into it
-                        total += yield walktree(child)
-                    elif child.isfile():
-                        # It's a file, call the callback function
-                        total += child.getsize()
-                    else:
-                        # Unknown file type, print a message
-                        pass
-
-                returnValue(total)
-
-            return walktree(self.fp)
-        else:
-            return succeed(self.fp.getsize())
-
-    ##
-    # Utilities
-    ##
-
-    @staticmethod
-    def _isChildURI(request, uri, immediateChild=True):
-        """
-        Verify that the supplied URI represents a resource that is a child
-        of the request resource.
-        @param request: the request currently in progress
-        @param uri: the URI to test
-        @return: True if the supplied URI is a child resource
-                 False if not
-        """
-        if uri is None: return False
-
-        #
-        # Parse the URI
-        #
-
-        (scheme, host, path, query, fragment) = urlsplit(uri) #@UnusedVariable
-
-        # Request hostname and child uri hostname have to be the same.
-        if host and host != request.headers.getHeader("host"):
-            return False
-
-        # Child URI must start with request uri text.
-        parent = request.uri
-        if not parent.endswith("/"):
-            parent += "/"
-
-        return path.startswith(parent) and (len(path) > len(parent)) and (not immediateChild or (path.find("/", len(parent)) == -1))
-
-    @inlineCallbacks
-    def _checkParents(self, request, test):
-        """
-        @param request: the request being processed.
-        @param test: a callable
-        @return: the closest parent for this resource using the request URI from
-            the given request for which C{test(parent)} evaluates to a true
-            value, or C{None} if no parent matches.
-        """
-        parent = self
-        parent_uri = request.uri
-
-        while True:
-            parent_uri = parentForURL(parent_uri)
-            if not parent_uri: break
-
-            parent = yield request.locateResource(parent_uri)
-
-            if test(parent):
-                returnValue(parent)
-
-class AutoProvisioningFileMixIn (LinkFollowerMixIn, AutoProvisioningResourceMixIn):
-    def provision(self):
-        self.provisionFile()
-        return super(AutoProvisioningFileMixIn, self).provision()
-
-
-    def provisionFile(self):
-        if hasattr(self, "_provisioned_file"):
-            return False
-        else:
-            self._provisioned_file = True
-
-        # If the file already exists we can just exit here - there is no need to go further
-        if self.fp.exists():
-            return False
-
-        # At this point the original FilePath did not indicate an existing file, but we should
-        # recheck it to see if some other request sneaked in and already created/provisioned it
-
-        fp = self.fp
-
-        fp.restat(False)
-        if fp.exists():
-            return False
-
-        log.msg("Provisioning file: %s" % (self,))
-
-        if hasattr(self, "parent"):
-            parent = self.parent
-            if not parent.exists() and isinstance(parent, AutoProvisioningFileMixIn):
-                parent.provision()
-
-            assert parent.exists(), "Parent %s of %s does not exist" % (parent, self)
-            assert parent.isCollection(), "Parent %s of %s is not a collection" % (parent, self)
-
-        if self.isCollection():
-            try:
-                fp.makedirs()
-            except OSError:
-                # It's possible someone else created the directory in the meantime...
-                # Check our status again, and re-raise if we're not a collection.
-                if not self.isCollection():
-                    raise
-            fp.changed()
-        else:
-            fp.open("w").close()
-            fp.changed()
-
-        return True
-
-    def _initTypeAndEncoding(self):
-
-        # Handle cases not covered by getTypeAndEncoding()
-        if self.isCollection():
-            self._type = "httpd/unix-directory"
-        else:
-            super(AutoProvisioningFileMixIn, self)._initTypeAndEncoding()
-
-
-class CalendarHomeProvisioningFile(AutoProvisioningFileMixIn, 
-                                   DirectoryCalendarHomeProvisioningResource,
-                                   DAVFile):
-    """
-    Resource which provisions calendar home collections as needed.
-    """
-
-    def __init__(self, path, directory, url, store):
-        """
-        Initialize this L{CalendarHomeProvisioningFile}.
-
-        @param path: the path to the filesystem directory which will back the
-            resource.
-
-        @type path: L{FilePath}
-
-        @param directory: an L{IDirectoryService} to provision calendars from.
-
-        @param url: the canonical URL for this L{CalendarHomeProvisioningFile} 
-            resource.
-        """
-        DAVFile.__init__(self, path)
-        DirectoryCalendarHomeProvisioningResource.__init__(self, directory, url)
-        self._newStore = store
-
-
-    def provisionChild(self, name):
-        if name == uidsResourceName:
-            return CalendarHomeUIDProvisioningFile(self.fp.child(name).path, self)
-
-        return CalendarHomeTypeProvisioningFile(self.fp.child(name).path, self, name)
-
-
-    def createSimilarFile(self, path):
-        raise HTTPError(responsecode.NOT_FOUND)
-
-
-
-class CalendarHomeTypeProvisioningFile (AutoProvisioningFileMixIn, DirectoryCalendarHomeTypeProvisioningResource, DAVFile):
-    def __init__(self, path, parent, recordType):
-        """
-        @param path: the path to the file which will back the resource.
-        @param parent: the parent of this resource
-        @param recordType: the directory record type to provision.
-        """
-        DAVFile.__init__(self, path)
-        DirectoryCalendarHomeTypeProvisioningResource.__init__(self, parent, recordType)
-
-
-
-def _transactionFromRequest(request, newStore):
-    """
-    Return the associated transaction from the given HTTP request, creating a
-    new one from the given data store if none has yet been associated.
-
-    Also, if the request was not previously associated with a transaction, add
-    a failsafe transaction-abort response filter to abort any transaction which
-    has not been committed or aborted by the resource which responds to the
-    request.
-
-    @param request: The request to inspect.
-    @type request: L{IRequest}
-
-    @param newStore: The store to create a transaction from.
-    @type newStore: L{IDataStore}
-
-    @return: a transaction that should be used to read and write data
-        associated with the request.
-    @rtype: L{ITransaction} (and possibly L{ICalendarTransaction} and
-        L{IAddressBookTransaction} as well.
-    """
-    TRANSACTION_KEY = '_newStoreTransaction'
-    transaction = getattr(request, TRANSACTION_KEY, None)
-    if transaction is None:
-        transaction = newStore.newTransaction(repr(request))
-        def abortIfUncommitted(request, response):
-            try:
-                transaction.abort()
-            except AlreadyFinishedError:
-                pass
-            return response
-        abortIfUncommitted.handleErrors = True
-        request.addResponseFilter(abortIfUncommitted)
-        setattr(request, TRANSACTION_KEY, transaction)
-    return transaction
-
-
-
-class CalendarHomeUIDProvisioningFile (AutoProvisioningFileMixIn, DirectoryCalendarHomeUIDProvisioningResource, DAVFile):
-    def __init__(self, path, parent, homeResourceClass=None):
-        """
-        @param path: the path to the file which will back the resource.
-        """
-        DAVFile.__init__(self, path)
-        DirectoryCalendarHomeUIDProvisioningResource.__init__(self, parent)
-        if homeResourceClass is None:
-            self.homeResourceClass = CalendarHomeFile
-        else:
-            self.homeResourceClass = homeResourceClass
-
-
-    def locateChild(self, request, segments):
-
-        name = segments[0]
-        if name == "":
-            return (self, ())
-
-        record = self.directory.recordWithUID(name)
-        if record:
-            return (self.homeResourceForRecord(record, request), segments[1:])
-        else:
-            return (None, ())
-
-    def homeResourceForRecord(self, record, request):
-        self.provision()
-        transaction = _transactionFromRequest(request, self.parent._newStore)
-
-        name = record.uid
-
-        if record is None:
-            log.msg("No directory record with GUID %r" % (name,))
-            return None
-
-        if not record.enabledForCalendaring:
-            log.msg("Directory record %r is not enabled for calendaring" % (record,))
-            return None
-
-        assert len(name) > 4, "Directory record has an invalid GUID: %r" % (name,)
-        
-        if record.locallyHosted():
-            childPath = self.fp.child(name[0:2]).child(name[2:4]).child(name)
-            child = self.homeResourceClass(childPath.path, self, record, transaction)
-    
-            if not child.exists():
-                self.provision()
-    
-                if not childPath.parent().isdir():
-                    childPath.parent().makedirs()
-    
-                for oldPath in (
-                    # Pre 2.0: All in one directory
-                    self.fp.child(name),
-                    # Pre 1.2: In types hierarchy instead of the GUID hierarchy
-                    self.parent.getChild(record.recordType).fp.child(record.shortNames[0]),
-                ):
-                    if oldPath.exists():
-                        # The child exists at an old location.  Move to new location.
-                        log.msg("Moving calendar home from old location %r to new location %r." % (oldPath, childPath))
-                        try:
-                            oldPath.moveTo(childPath)
-                        except (OSError, IOError), e:
-                            log.err("Error moving calendar home %r: %s" % (oldPath, e))
-                            raise HTTPError(StatusResponse(
-                                responsecode.INTERNAL_SERVER_ERROR,
-                                "Unable to move calendar home."
-                            ))
-                        child.fp.changed()
-                        break
-
-                assert child.exists()
-        
-        else:
-            childPath = self.fp.child(name[0:2]).child(name[2:4]).child(name)
-            child = CalendarHomeReverseProxyFile(childPath.path, self, record)
-
-        return child
-
-    def createSimilarFile(self, path):
-        raise HTTPError(responsecode.NOT_FOUND)
-
-class CalendarHomeReverseProxyFile(ReverseProxyResource):
-    
-    def __init__(self, path, parent, record):
-        self.path = path
-        self.parent = parent
-        self.record = record
-        
-        super(CalendarHomeReverseProxyFile, self).__init__(self.record.hostedAt)
-    
-    def url(self):
-        return joinURL(self.parent.url(), self.record.uid)
-
-class CalendarHomeFile(AutoProvisioningFileMixIn, SharedHomeMixin, 
-                       DirectoryCalendarHomeResource, CalDAVFile):
-    """
-    Calendar home collection resource.
-    """
-    def liveProperties(self):
-        
-        return super(CalendarHomeFile, self).liveProperties() + (
-            (customxml.calendarserver_namespace, "push-transports"),
-            (customxml.calendarserver_namespace, "pushkey"),
-            (customxml.calendarserver_namespace, "xmpp-uri"),
-            (customxml.calendarserver_namespace, "xmpp-heartbeat-uri"),
-            (customxml.calendarserver_namespace, "xmpp-server"),
-        )
-
-    def __init__(self, path, parent, record, transaction):
-        """
-        @param path: the path to the file which will back the resource.
-        """
-
-        self.associateWithTransaction(transaction)
-
-        # TODO: when calendar home gets a resourceID( ) method, remove
-        # the "id=record.uid" keyword from this call:
-        self.clientNotifier = ClientNotifier(self, id=record.uid)
-        storeHome = transaction.calendarHomeWithUID(record.uid)
-        if storeHome is not None:
-            created = False
-        else:
-            storeHome = transaction.calendarHomeWithUID(
-                record.uid, create=True
-            )
-            created = True
-        self._newStoreCalendarHome = storeHome
-        CalDAVFile.__init__(self, path)
-        DirectoryCalendarHomeResource.__init__(self, parent, record)
-        from twistedcaldav.storebridge import _NewStorePropertiesWrapper
-        self._dead_properties = _NewStorePropertiesWrapper(
-            self._newStoreCalendarHome.properties()
-        )
-        if created:
-            # This is a bit of a hack.  Really we ought to be always generating
-            # this URL live from a back-end method that tells us what the
-            # default calendar is.
-            inbox = self.getChild("inbox")
-            childURL = joinURL(self.url(), "calendar")
-            inbox.processFreeBusyCalendar(childURL, True)
-
-
-    def sharesDB(self):
-        """
-        Retrieve the new-style shares DB wrapper.
-        """
-        if not hasattr(self, "_sharesDB"):
-            self._sharesDB = self._newStoreCalendarHome.retrieveOldShares()
-        return self._sharesDB
-
-
-    def exists(self):
-        # FIXME: tests
-        return True
-    
-    
-    def quotaSize(self, request):
-        # FIXME: tests, workingness
-        return succeed(0)
-
-
-    def provision(self):
-        if config.Sharing.Enabled and config.Sharing.Calendars.Enabled and self.fp.exists():
-            self.provisionShares()
-        return
-
-    def provisionChild(self, name):
-        from twistedcaldav.storebridge import StoreScheduleInboxFile
-        from twistedcaldav.storebridge import DropboxCollection
-        if config.EnableDropBox:
-            DropBoxHomeFileClass = DropboxCollection
-        else:
-            DropBoxHomeFileClass = None
-
-        if config.FreeBusyURL.Enabled:
-            FreeBusyURLFileClass = FreeBusyURLFile
-        else:
-            FreeBusyURLFileClass = None
-            
-        if config.Sharing.Enabled and config.Sharing.Calendars.Enabled:
-            NotificationCollectionFileClass = NotificationCollectionFile
-        else:
-            NotificationCollectionFileClass = None
-
-
-        # For storebridge stuff we special case this
-        if name == "notification":
-            return self.createNotificationsFile(self.fp.child(name).path)
-
-        cls = {
-            "inbox"        : StoreScheduleInboxFile,
-            "outbox"       : ScheduleOutboxFile,
-            "dropbox"      : DropBoxHomeFileClass,
-            "freebusy"     : FreeBusyURLFileClass,
-            "notification" : NotificationCollectionFileClass,
-        }.get(name, None)
-
-        if cls is not None:
-            child = cls(self.fp.child(name).path, self)
-            child.clientNotifier = self.clientNotifier.clone(child,
-                label="collection")
-            return child
-        return self.createSimilarFile(self.fp.child(name).path)
-
-    def createNotificationsFile(self, path):
-        
-        txn = self._newStoreCalendarHome._transaction
-        notifications = txn.notificationsWithUID(self._newStoreCalendarHome.uid())
-
-        from twistedcaldav.storebridge import StoreNotificationCollectionFile
-        similar = StoreNotificationCollectionFile(
-            notifications, self._newStoreCalendarHome,
-            path, self,
-        )
-        self.propagateTransaction(similar)
-        similar.clientNotifier = self.clientNotifier.clone(similar,
-            label="collection")
-        return similar
-
-    def createSimilarFile(self, path):
-
-        if self.comparePath(path):
-            return self
-        else:
-            if not isinstance(path, FilePath):
-                path = FilePath(path)
-            newCalendar = self._newStoreCalendarHome.calendarWithName(
-                path.basename()
-            )
-            if newCalendar is None:
-                # Local imports.due to circular dependency between modules.
-                from twistedcaldav.storebridge import (
-                     ProtoCalendarCollectionFile)
-                similar = ProtoCalendarCollectionFile(
-                    self._newStoreCalendarHome,
-                    path, principalCollections=self.principalCollections()
-                )
-            else:
-                from twistedcaldav.storebridge import CalendarCollectionFile
-                similar = CalendarCollectionFile(
-                    newCalendar, self._newStoreCalendarHome,
-                    path, principalCollections=self.principalCollections()
-                )
-            self.propagateTransaction(similar)
-            similar.clientNotifier = self.clientNotifier.clone(similar,
-                label="collection")
-            return similar
-
-    def getChild(self, name):
-        # This avoids finding case variants of put children on case-insensitive filesystems.
-        if name not in self.putChildren and name.lower() in (x.lower() for x in self.putChildren):
-            return None
-
-        return super(CalendarHomeFile, self).getChild(name)
-
-
-    def readProperty(self, property, request):
-        if type(property) is tuple:
-            qname = property
-        else:
-            qname = property.qname()
-
-        if qname == (customxml.calendarserver_namespace, "push-transports"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if (pubSubConfiguration['enabled'] and
-                getattr(self, "clientNotifier", None) is not None):
-                    id = self.clientNotifier.getID()
-                    nodeName = getPubSubPath(id, pubSubConfiguration)
-                    children = []
-                    if pubSubConfiguration['aps-bundle-id']:
-                        children.append(
-                            customxml.PubSubTransportProperty(
-                                customxml.PubSubSubscriptionProperty(
-                                    davxml.HRef(
-                                        pubSubConfiguration['subscription-url']
-                                    ),
-                                ),
-                                customxml.PubSubAPSBundleIDProperty(
-                                    pubSubConfiguration['aps-bundle-id']
-                                ),
-                                type="APSD",
-                            )
-                        )
-                    if pubSubConfiguration['xmpp-server']:
-                        children.append(
-                            customxml.PubSubTransportProperty(
-                                customxml.PubSubXMPPServerProperty(
-                                    pubSubConfiguration['xmpp-server']
-                                ),
-                                customxml.PubSubXMPPURIProperty(
-                                    getPubSubXMPPURI(id, pubSubConfiguration)
-                                ),
-                                type="XMPP",
-                            )
-                        )
-
-                    propVal = customxml.PubSubPushTransportsProperty(*children)
-                    nodeCacher = getNodeCacher()
-                    d = nodeCacher.waitForNode(self.clientNotifier, nodeName)
-                    # In either case we're going to return the value
-                    d.addBoth(lambda ignored: propVal)
-                    return d
-
-
-            else:
-                return succeed(customxml.PubSubPushTransportsProperty())
-
-        if qname == (customxml.calendarserver_namespace, "pushkey"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if pubSubConfiguration['enabled']:
-                if getattr(self, "clientNotifier", None) is not None:
-                    id = self.clientNotifier.getID()
-                    nodeName = getPubSubPath(id, pubSubConfiguration)
-                    propVal = customxml.PubSubXMPPPushKeyProperty(nodeName)
-                    nodeCacher = getNodeCacher()
-                    d = nodeCacher.waitForNode(self.clientNotifier, nodeName)
-                    # In either case we're going to return the xmpp-uri value
-                    d.addBoth(lambda ignored: propVal)
-                    return d
-            else:
-                return succeed(customxml.PubSubXMPPPushKeyProperty())
-
-
-        if qname == (customxml.calendarserver_namespace, "xmpp-uri"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if pubSubConfiguration['enabled']:
-                if getattr(self, "clientNotifier", None) is not None:
-                    id = self.clientNotifier.getID()
-                    nodeName = getPubSubPath(id, pubSubConfiguration)
-                    propVal = customxml.PubSubXMPPURIProperty(
-                        getPubSubXMPPURI(id, pubSubConfiguration))
-                    nodeCacher = getNodeCacher()
-                    d = nodeCacher.waitForNode(self.clientNotifier, nodeName)
-                    # In either case we're going to return the xmpp-uri value
-                    d.addBoth(lambda ignored: propVal)
-                    return d
-            else:
-                return succeed(customxml.PubSubXMPPURIProperty())
-
-        elif qname == (customxml.calendarserver_namespace, "xmpp-heartbeat-uri"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if pubSubConfiguration['enabled']:
-                return succeed(
-                    customxml.PubSubHeartbeatProperty(
-                        customxml.PubSubHeartbeatURIProperty(
-                            getPubSubHeartbeatURI(pubSubConfiguration)
-                        ),
-                        customxml.PubSubHeartbeatMinutesProperty(
-                            str(pubSubConfiguration['heartrate'])
-                        )
-                    )
-                )
-            else:
-                return succeed(customxml.PubSubHeartbeatURIProperty())
-
-        elif qname == (customxml.calendarserver_namespace, "xmpp-server"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if pubSubConfiguration['enabled']:
-                return succeed(customxml.PubSubXMPPServerProperty(
-                    pubSubConfiguration['xmpp-server']))
-            else:
-                return succeed(customxml.PubSubXMPPServerProperty())
-
-        return super(CalendarHomeFile, self).readProperty(property, request)
-
-
-class ScheduleFile (ReadOnlyResourceMixIn, AutoProvisioningFileMixIn, CalDAVFile):
-    def __init__(self, path, parent):
-        super(ScheduleFile, self).__init__(path, principalCollections=parent.principalCollections())
-
-    def isCollection(self):
-        return True
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            return CalDAVFile(path, principalCollections=self.principalCollections())
-
-    def index(self):
-        """
-        Obtains the index for an schedule collection resource.
-        @return: the index object for this resource.
-        @raise AssertionError: if this resource is not a calendar collection
-            resource.
-        """
-        return IndexSchedule(self)
-
-class ScheduleInboxFile (ScheduleInboxResource, ScheduleFile):
-    """
-    Calendar scheduling inbox collection resource.
-    """
-    def __init__(self, path, parent):
-        ScheduleFile.__init__(self, path, parent)
-        ScheduleInboxResource.__init__(self, parent)
-
-    def __repr__(self):
-        return "<%s (calendar inbox collection): %s>" % (self.__class__.__name__, self.fp.path)
-
-
-    ##
-    # ACL
-    ##
-
-    def supportedPrivileges(self, request):
-        return succeed(deliverSchedulePrivilegeSet)
-
-class ScheduleOutboxFile (ScheduleOutboxResource, ScheduleFile):
-    """
-    Calendar scheduling outbox collection resource.
-    """
-    def __init__(self, path, parent):
-        ScheduleFile.__init__(self, NotFilePath(isdir=True), parent)
-        ScheduleOutboxResource.__init__(self, parent)
-
-    def deadProperties(self):
-        if not hasattr(self, "_dead_properties"):
-            self._dead_properties = NonePropertyStore(self)
-        return self._dead_properties
-
-    def etag(self):
-        return None
-
-    def provision(self):
-        """
-        Schedule outboxes do not need to be provisioned; they shouldn't store
-        anything.
-        """
-
-    def __repr__(self):
-        return "<%s (calendar outbox collection): %s>" % (self.__class__.__name__, self.fp.path)
-
-
-    ##
-    # ACL
-    ##
-
-    def supportedPrivileges(self, request):
-        return succeed(sendSchedulePrivilegeSet)
-
-    def report_urn_ietf_params_xml_ns_caldav_calendar_query(self, request, calendar_query):
-        return succeed(MultiStatusResponse(()))
-        
-    def report_urn_ietf_params_xml_ns_caldav_calendar_multiget(self, request, multiget):
-        responses = [davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.NOT_FOUND)) for href in multiget.resources]
-        return succeed(MultiStatusResponse((responses)))
-
-class IScheduleInboxFile (ReadOnlyResourceMixIn, IScheduleInboxResource, CalDAVFile):
-    """
-    Server-to-server scheduling inbox resource.
-    """
-    def __init__(self, path, parent):
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-        IScheduleInboxResource.__init__(self, parent)
-
-    def __repr__(self):
-        return "<%s (server-to-server inbox resource): %s>" % (self.__class__.__name__, self.fp.path)
-
-    def isCollection(self):
-        return False
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            return responsecode.NOT_FOUND
-
-    def deadProperties(self):
-        if not hasattr(self, "_dead_properties"):
-            self._dead_properties = NonePropertyStore(self)
-        return self._dead_properties
-
-    def etag(self):
-        return None
-
-    def checkPreconditions(self, request):
-        return None
-
-    ##
-    # ACL
-    ##
-
-    def supportedPrivileges(self, request):
-        return succeed(deliverSchedulePrivilegeSet)
-
-
-
-class FreeBusyURLFile (ReadOnlyResourceMixIn, AutoProvisioningFileMixIn, FreeBusyURLResource, CalDAVFile):
-    """
-    Free-busy URL resource.
-    """
-    def __init__(self, path, parent):
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-        FreeBusyURLResource.__init__(self, parent)
-
-    def __repr__(self):
-        return "<%s (free-busy URL resource): %s>" % (self.__class__.__name__, self.fp.path)
-
-    def isCollection(self):
-        return False
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            return responsecode.NOT_FOUND
-
-    ##
-    # ACL
-    ##
-
-    def supportedPrivileges(self, request):
-        return succeed(deliverSchedulePrivilegeSet)
-
-class DropBoxHomeFile (AutoProvisioningFileMixIn, DropBoxHomeResource, CalDAVFile):
-    def __init__(self, path, parent):
-        DropBoxHomeResource.__init__(self)
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-        self.parent = parent
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            return DropBoxCollectionFile(path, self)
-
-    def __repr__(self):
-        return "<%s (dropbox home collection): %s>" % (self.__class__.__name__, self.fp.path)
-
-class DropBoxCollectionFile (DropBoxCollectionResource, CalDAVFile):
-    def __init__(self, path, parent):
-        DropBoxCollectionResource.__init__(self)
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            return DropBoxChildFile(path, self)
-
-    def __repr__(self):
-        return "<%s (dropbox collection): %s>" % (self.__class__.__name__, self.fp.path)
-
-class DropBoxChildFile (CalDAVFile):
-    def __init__(self, path, parent):
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-
-        assert self.fp.isfile() or not self.fp.exists()
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            return responsecode.NOT_FOUND
-
-class TimezoneServiceFile (ReadOnlyResourceMixIn, TimezoneServiceResource, CalDAVFile):
-    def __init__(self, path, parent):
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-        TimezoneServiceResource.__init__(self, parent)
-
-        assert self.fp.isfile() or not self.fp.exists()
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            return responsecode.NOT_FOUND
-
-    def deadProperties(self):
-        if not hasattr(self, "_dead_properties"):
-            self._dead_properties = NonePropertyStore(self)
-        return self._dead_properties
-
-    def etag(self):
-        return None
-
-    def checkPreconditions(self, request):
-        return None
-
-    def checkPrivileges(self, request, privileges, recurse=False, principal=None, inherited_aces=None):
-        return succeed(None)
-
-class NotificationCollectionFile(ReadOnlyResourceMixIn, NotificationCollectionResource, CalDAVFile):
-    """
-    Notification collection resource.
-    """
-    def __init__(self, path, parent):
-        NotificationCollectionResource.__init__(self)
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-        self.parent = parent
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            return NotificationFile(path, self)
-
-    def __repr__(self):
-        return "<%s (notification collection): %s>" % (self.__class__.__name__, self.fp.path)
-
-    def _writeNotification(self, request, uid, rname, xmltype, xmldata):
-        
-        # TODO: use the generic StoreObject api so that quota, sync-token etc all get changed properly
-        child = self.createSimilarFile(self.fp.child(rname).path)
-        def _defer(_):
-            child.writeDeadProperty(davxml.GETContentType.fromString(generateContentType(MimeType("text", "xml", params={"charset":"utf-8"}))))
-            child.writeDeadProperty(customxml.NotificationType(xmltype))
-            return True
-
-        url = request.urlForResource(self)
-        url = joinURL(url, rname)
-        request._rememberResource(child, url)
-        d = put_common.storeResource(request, data=xmldata, destination=child, destination_uri=url)
-        d.addCallback(_defer)
-        return d
-
-
-    def _deleteNotification(self, request, rname):
-        child = self.createSimilarFile(self.fp.child(rname).path)
-        url = request.urlForResource(self)
-        url = joinURL(url, rname)
-        request._rememberResource(child, url)
-        return delete_common.deleteResource(request, child, url)
-
-class NotificationFile(NotificationResource, CalDAVFile):
-
-    def __init__(self, path, parent):
-        NotificationResource.__init__(self, parent)
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-
-        assert self.fp.isfile() or not self.fp.exists()
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            return responsecode.NOT_FOUND
-
-    def __repr__(self):
-        return "<%s (notification file): %s>" % (self.__class__.__name__, self.fp.path)
-        
-    def resourceName(self):
-        return self.fp.basename()
-
-class AddressBookHomeProvisioningFile (AutoProvisioningFileMixIn, DirectoryAddressBookHomeProvisioningResource, DAVFile):
-    """
-    Resource which provisions address book home collections as needed.
-    """
-    def __init__(self, path, directory, url, store):
-        """
-        @param path: the path to the file which will back the resource.
-        @param directory: an L{IDirectoryService} to provision address books from.
-        @param url: the canonical URL for the resource.
-        """
-        DAVFile.__init__(self, path)
-        DirectoryAddressBookHomeProvisioningResource.__init__(self, directory, url)
-        self._newStore = store
-
-
-    def provisionChild(self, name):
-        if name == uidsResourceNameAddressBook:
-            return AddressBookHomeUIDProvisioningFile(self.fp.child(name).path, self)
-
-        return AddressBookHomeTypeProvisioningFile(self.fp.child(name).path, self, name)
-
-    def createSimilarFile(self, path):
-        raise HTTPError(responsecode.NOT_FOUND)
-
-class AddressBookHomeTypeProvisioningFile (AutoProvisioningFileMixIn, DirectoryAddressBookHomeTypeProvisioningResource, DAVFile):
-    def __init__(self, path, parent, recordType):
-        """
-        @param path: the path to the file which will back the resource.
-        @param parent: the parent of this resource
-        @param recordType: the directory record type to provision.
-        """
-        DAVFile.__init__(self, path)
-        DirectoryAddressBookHomeTypeProvisioningResource.__init__(self, parent, recordType)
-
-class AddressBookHomeUIDProvisioningFile (AutoProvisioningFileMixIn, DirectoryAddressBookHomeUIDProvisioningResource, DAVFile):
-    def __init__(self, path, parent, homeResourceClass=None):
-        """
-        @param path: the path to the file which will back the resource.
-        """
-        DAVFile.__init__(self, path)
-        DirectoryAddressBookHomeUIDProvisioningResource.__init__(self, parent)
-        if homeResourceClass is None:
-            self.homeResourceClass = AddressBookHomeFile
-        else:
-            self.homeResourceClass = homeResourceClass
-
-    def locateChild(self, request, segments):
-
-        name = segments[0]
-        if name == "":
-            return (self, ())
-
-        record = self.directory.recordWithUID(name)
-        if record:
-            return (self.homeResourceForRecord(record, request), segments[1:])
-        else:
-            return (None, ())
-
-    def homeResourceForRecord(self, record, request):
-        self.provision()
-        transaction = _transactionFromRequest(request, self.parent._newStore)
-
-        name = record.uid
-
-        if record is None:
-            log.msg("No directory record with GUID %r" % (name,))
-            return None
-
-        if not record.enabledForAddressBooks:
-            log.msg("Directory record %r is not enabled for address books" % (record,))
-            return None
-
-        assert len(name) > 4
-        
-        childPath = self.fp.child(name[0:2]).child(name[2:4]).child(name)
-        child = self.homeResourceClass(childPath.path, self, record, transaction)
-
-        if not child.exists():
-            self.provision()
-
-            if not childPath.parent().isdir():
-                childPath.parent().makedirs()
-
-            for oldPath in (
-                # Pre 2.0: All in one directory
-                self.fp.child(name),
-                # Pre 1.2: In types hierarchy instead of the GUID hierarchy
-                self.parent.getChild(record.recordType).fp.child(record.shortNames[0]),
-            ):
-                if oldPath.exists():
-                    # The child exists at an old location.  Move to new location.
-                    log.msg("Moving address book home from old location %r to new location %r." % (oldPath, childPath))
-                    try:
-                        oldPath.moveTo(childPath)
-                    except (OSError, IOError), e:
-                        log.err("Error moving address book home %r: %s" % (oldPath, e))
-                        raise HTTPError(StatusResponse(
-                            responsecode.INTERNAL_SERVER_ERROR,
-                            "Unable to move address book home."
-                        ))
-                    child.fp.restat(False)
-                    break
-            else:
-                #
-                # NOTE: provisionDefaultAddressBooks() returns a deferred, which we are ignoring.
-                # The result being that the default calendars will be present at some point
-                # in the future, not necessarily right now, and we don't have a way to wait
-                # on that to finish.
-                #
-                child.provisionDefaultAddressBooks()
-
-                #
-                # Try to work around the above a little by telling the client that something
-                # when wrong temporarily if the child isn't provisioned right away.
-                #
-                if not child.exists():
-                    raise HTTPError(StatusResponse(
-                        responsecode.SERVICE_UNAVAILABLE,
-                        "Provisioning address book home."
-                    ))
-
-            assert child.exists()
-
-        return child
-
-    def createSimilarFile(self, path):
-        raise HTTPError(responsecode.NOT_FOUND)
-
-class AddressBookHomeFile (AutoProvisioningFileMixIn, SharedHomeMixin, DirectoryAddressBookHomeResource, CalDAVFile):
-    """
-    Address book home collection resource.
-    """
-    
-    def liveProperties(self):
-        return super(AddressBookHomeFile, self).liveProperties() + (
-            (customxml.calendarserver_namespace, "push-transports"),
-            (customxml.calendarserver_namespace, "pushkey"),
-            (customxml.calendarserver_namespace, "xmpp-uri"),
-            (customxml.calendarserver_namespace, "xmpp-heartbeat-uri"),
-            (customxml.calendarserver_namespace, "xmpp-server"),
-        )
-
-    def __init__(self, path, parent, record, transaction):
-        """
-        @param path: the path to the file which will back the resource.
-        """
-
-        self.associateWithTransaction(transaction)
-
-        # TODO: when addressbook home gets a resourceID( ) method, remove
-        # the "id=record.uid" keyword from this call:
-        self.clientNotifier = ClientNotifier(self, id=record.uid)
-        self._newStoreAddressBookHome = (
-            transaction.addressbookHomeWithUID(record.uid, create=True)
-        )
-        CalDAVFile.__init__(self, path)
-        DirectoryAddressBookHomeResource.__init__(self, parent, record)
-
-        from twistedcaldav.storebridge import _NewStorePropertiesWrapper
-        self._dead_properties = _NewStorePropertiesWrapper(
-            self._newStoreAddressBookHome.properties()
-        )
-
-
-    def sharesDB(self):
-        """
-        Retrieve the new-style shares DB wrapper.
-        """
-        if not hasattr(self, "_sharesDB"):
-            self._sharesDB = self._newStoreAddressBookHome.retrieveOldShares()
-        return self._sharesDB
-
-
-    def exists(self):
-        # FIXME: tests
-        return True
-    
-    
-    def quotaSize(self, request):
-        # FIXME: tests, workingness
-        return succeed(0)
-
-
-    def provision(self):
-        if config.Sharing.Enabled and config.Sharing.AddressBooks.Enabled:
-            self.provisionShares()
-        self.provisionLinks()
-
-    def provisionLinks(self):
-        
-        if not hasattr(self, "_provisionedLinks"):
-            if config.GlobalAddressBook.Enabled:
-                self.putChild(
-                    config.GlobalAddressBook.Name,
-                    LinkResource(self, "/addressbooks/public/global/addressbook/"),
-                )
-            self._provisionedLinks = True
-
-    def provisionChild(self, name):
- 
-        if config.Sharing.Enabled and config.Sharing.AddressBooks.Enabled and not config.Sharing.Calendars.Enabled:
-            NotificationCollectionFileClass = NotificationCollectionFile
-        else:
-            NotificationCollectionFileClass = None
-
-        cls = {
-            "notification" : NotificationCollectionFileClass,
-        }.get(name, None)
-
-        if cls is not None:
-            child = cls(self.fp.child(name).path, self)
-            child.clientNotifier = self.clientNotifier.clone(child,
-                label="collection")
-            return child
-        return self.createSimilarFile(self.fp.child(name).path)
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            if not isinstance(path, FilePath):
-                path = FilePath(path)
-
-            # Check for public/global path
-            from twistedcaldav.storebridge import (
-                AddressBookCollectionFile,
-                ProtoAddressBookCollectionFile,
-                GlobalAddressBookCollectionFile,
-                ProtoGlobalAddressBookCollectionFile,
-            )
-            mainCls = AddressBookCollectionFile
-            protoCls = ProtoAddressBookCollectionFile
-            if isinstance(self.record, InternalDirectoryRecord):
-                if "global" in self.record.shortNames:
-                    mainCls = GlobalAddressBookCollectionFile
-                    protoCls = ProtoGlobalAddressBookCollectionFile
-
-            newAddressBook = self._newStoreAddressBookHome.addressbookWithName(
-                path.basename()
-            )
-            if newAddressBook is None:
-                # Local imports.due to circular dependency between modules.
-                similar = protoCls(
-                    self._newStoreAddressBookHome,
-                    path, principalCollections=self.principalCollections()
-                )
-            else:
-                similar = mainCls(
-                    newAddressBook, self._newStoreAddressBookHome,
-                    path, principalCollections=self.principalCollections()
-                )
-            self.propagateTransaction(similar)
-            similar.clientNotifier = self.clientNotifier.clone(similar,
-                label="collection")
-            return similar
-
-    def getChild(self, name):
-        # This avoids finding case variants of put children on case-insensitive filesystems.
-        if name not in self.putChildren and name.lower() in (x.lower() for x in self.putChildren):
-            return None
-
-        return super(AddressBookHomeFile, self).getChild(name)
-
-
-    def readProperty(self, property, request):
-        if type(property) is tuple:
-            qname = property
-        else:
-            qname = property.qname()
-
-        if qname == (customxml.calendarserver_namespace, "push-transports"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if (pubSubConfiguration['enabled'] and
-                getattr(self, "clientNotifier", None) is not None):
-                    id = self.clientNotifier.getID()
-                    nodeName = getPubSubPath(id, pubSubConfiguration)
-                    children = []
-                    if pubSubConfiguration['aps-bundle-id']:
-                        children.append(
-                            customxml.PubSubTransportProperty(
-                                customxml.PubSubSubscriptionProperty(
-                                    davxml.HRef(
-                                        pubSubConfiguration['subscription-url']
-                                    ),
-                                ),
-                                customxml.PubSubAPSBundleIDProperty(
-                                    pubSubConfiguration['aps-bundle-id']
-                                ),
-                                type="APSD",
-                            )
-                        )
-                    if pubSubConfiguration['xmpp-server']:
-                        children.append(
-                            customxml.PubSubTransportProperty(
-                                customxml.PubSubXMPPServerProperty(
-                                    pubSubConfiguration['xmpp-server']
-                                ),
-                                customxml.PubSubXMPPURIProperty(
-                                    getPubSubXMPPURI(id, pubSubConfiguration)
-                                ),
-                                type="XMPP",
-                            )
-                        )
-
-                    propVal = customxml.PubSubPushTransportsProperty(*children)
-                    nodeCacher = getNodeCacher()
-                    d = nodeCacher.waitForNode(self.clientNotifier, nodeName)
-                    # In either case we're going to return the value
-                    d.addBoth(lambda ignored: propVal)
-                    return d
-
-
-            else:
-                return succeed(customxml.PubSubPushTransportsProperty())
-
-        if qname == (customxml.calendarserver_namespace, "pushkey"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if pubSubConfiguration['enabled']:
-                if getattr(self, "clientNotifier", None) is not None:
-                    id = self.clientNotifier.getID()
-                    nodeName = getPubSubPath(id, pubSubConfiguration)
-                    propVal = customxml.PubSubXMPPPushKeyProperty(nodeName)
-                    nodeCacher = getNodeCacher()
-                    d = nodeCacher.waitForNode(self.clientNotifier, nodeName)
-                    # In either case we're going to return the xmpp-uri value
-                    d.addBoth(lambda ignored: propVal)
-                    return d
-            else:
-                return succeed(customxml.PubSubXMPPPushKeyProperty())
-
-
-        if qname == (customxml.calendarserver_namespace, "xmpp-uri"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if pubSubConfiguration['enabled']:
-                if getattr(self, "clientNotifier", None) is not None:
-                    id = self.clientNotifier.getID()
-                    nodeName = getPubSubPath(id, pubSubConfiguration)
-                    propVal = customxml.PubSubXMPPURIProperty(
-                        getPubSubXMPPURI(id, pubSubConfiguration))
-                    nodeCacher = getNodeCacher()
-                    d = nodeCacher.waitForNode(self.clientNotifier, nodeName)
-                    # In either case we're going to return the xmpp-uri value
-                    d.addBoth(lambda ignored: propVal)
-                    return d
-            else:
-                return succeed(customxml.PubSubXMPPURIProperty())
-
-        elif qname == (customxml.calendarserver_namespace, "xmpp-heartbeat-uri"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if pubSubConfiguration['enabled']:
-                return succeed(
-                    customxml.PubSubHeartbeatProperty(
-                        customxml.PubSubHeartbeatURIProperty(
-                            getPubSubHeartbeatURI(pubSubConfiguration)
-                        ),
-                        customxml.PubSubHeartbeatMinutesProperty(
-                            str(pubSubConfiguration['heartrate'])
-                        )
-                    )
-                )
-            else:
-                return succeed(customxml.PubSubHeartbeatURIProperty())
-
-        elif qname == (customxml.calendarserver_namespace, "xmpp-server"):
-            pubSubConfiguration = getPubSubConfiguration(config)
-            if pubSubConfiguration['enabled']:
-                return succeed(customxml.PubSubXMPPServerProperty(
-                    pubSubConfiguration['xmpp-server']))
-            else:
-                return succeed(customxml.PubSubXMPPServerProperty())
-
-        return super(AddressBookHomeFile, self).readProperty(property, request)
-
-
-class DirectoryBackedAddressBookFile (ReadOnlyResourceMixIn, DirectoryBackedAddressBookResource, CalDAVFile):
-    """
-    Directory-backed address book, supporting directory vcard search.
-    """
-    def __init__(self, path, principalCollections):
-        CalDAVFile.__init__(self, path, principalCollections=principalCollections)
-        DirectoryBackedAddressBookResource.__init__(self)
-
-        # create with permissions, similar to CardDAVOptions in tap.py
-        # FIXME:  /Directory does not need to be in file system unless debug-only caching options are used
-        try:
-            os.mkdir(path)
-            os.chmod(path, 0750)
-            if config.UserName and config.GroupName:
-                import pwd
-                import grp
-                uid = pwd.getpwnam(config.UserName)[2]
-                gid = grp.getgrnam(config.GroupName)[2]
-                os.chown(path, uid, gid)
- 
-            log.msg("Created %s" % (path,))
-            
-        except (OSError,), e:
-            # this is caused by multiprocessor race and is harmless
-            if e.errno != errno.EEXIST:
-                raise
-
-    
-    def getChild(self, name):
-        
-        if name is "":
-            return self
-        else:
-            from twistedcaldav.simpleresource import SimpleCalDAVResource
-            return SimpleCalDAVResource(principalCollections=self.principalCollections())
-       
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            from twistedcaldav.simpleresource import SimpleCalDAVResource
-            return SimpleCalDAVResource(principalCollections=self.principalCollections())
- 
-class GlobalAddressBookFile (ReadOnlyResourceMixIn, GlobalAddressBookResource, CalDAVFile):
-    """
-    Directory-backed address book, supporting directory vcard search.
-    """
-    def __init__(self, path, principalCollections):
-        CalDAVFile.__init__(self, path, principalCollections=principalCollections)
-        self.clientNotifier = ClientNotifier(self)
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            similar = CalDAVFile(path, principalCollections=self.principalCollections())
-            similar.clientNotifier = self.clientNotifier.clone(similar,
-                label="collection")
-            return similar
-
-##
-# Utilities
-##
-
-def locateExistingChild(resource, request, segments):
-    """
-    This C{locateChild()} implementation fails to find children if C{getChild()}
-    doesn't return one.
-    """
-    # If getChild() finds a child resource, return it
-    child = resource.getChild(segments[0])
-    if child is not None:
-        return (child, segments[1:])
-
-    # Otherwise, there is no child
-    return (None, ())
-
-def _schedulePrivilegeSet(deliver):
-    edited = False
-
-    top_supported_privileges = []
-
-    for supported_privilege in davPrivilegeSet.childrenOfType(davxml.SupportedPrivilege):
-        all_privilege = supported_privilege.childOfType(davxml.Privilege)
-        if isinstance(all_privilege.children[0], davxml.All):
-            all_description = supported_privilege.childOfType(davxml.Description)
-            all_supported_privileges = list(supported_privilege.childrenOfType(davxml.SupportedPrivilege))
-            all_supported_privileges.append(
-                davxml.SupportedPrivilege(
-                    davxml.Privilege(caldavxml.ScheduleDeliver() if deliver else caldavxml.ScheduleSend()),
-                    davxml.Description("schedule privileges for current principal", **{"xml:lang": "en"}),
-                ),
-            )
-            if config.Scheduling.CalDAV.OldDraftCompatibility:
-                all_supported_privileges.append(
-                    davxml.SupportedPrivilege(
-                        davxml.Privilege(caldavxml.Schedule()),
-                        davxml.Description("old-style schedule privileges for current principal", **{"xml:lang": "en"}),
-                    ),
-                )
-            top_supported_privileges.append(
-                davxml.SupportedPrivilege(all_privilege, all_description, *all_supported_privileges)
-            )
-            edited = True
-        else:
-            top_supported_privileges.append(supported_privilege)
-
-    assert edited, "Structure of davPrivilegeSet changed in a way that I don't know how to extend for schedulePrivilegeSet"
-
-    return davxml.SupportedPrivilegeSet(*top_supported_privileges)
-
-deliverSchedulePrivilegeSet = _schedulePrivilegeSet(True)
-sendSchedulePrivilegeSet = _schedulePrivilegeSet(False)
-
-def _calendarPrivilegeSet ():
-    edited = False
-
-    top_supported_privileges = []
-
-    for supported_privilege in davPrivilegeSet.childrenOfType(davxml.SupportedPrivilege):
-        all_privilege = supported_privilege.childOfType(davxml.Privilege)
-        if isinstance(all_privilege.children[0], davxml.All):
-            all_description = supported_privilege.childOfType(davxml.Description)
-            all_supported_privileges = []
-            for all_supported_privilege in supported_privilege.childrenOfType(davxml.SupportedPrivilege):
-                read_privilege = all_supported_privilege.childOfType(davxml.Privilege)
-                if isinstance(read_privilege.children[0], davxml.Read):
-                    read_description = all_supported_privilege.childOfType(davxml.Description)
-                    read_supported_privileges = list(all_supported_privilege.childrenOfType(davxml.SupportedPrivilege))
-                    read_supported_privileges.append(
-                        davxml.SupportedPrivilege(
-                            davxml.Privilege(caldavxml.ReadFreeBusy()),
-                            davxml.Description("allow free busy report query", **{"xml:lang": "en"}),
-                        )
-                    )
-                    all_supported_privileges.append(
-                        davxml.SupportedPrivilege(read_privilege, read_description, *read_supported_privileges)
-                    )
-                    edited = True
-                else:
-                    all_supported_privileges.append(all_supported_privilege)
-            top_supported_privileges.append(
-                davxml.SupportedPrivilege(all_privilege, all_description, *all_supported_privileges)
-            )
-        else:
-            top_supported_privileges.append(supported_privilege)
-
-    assert edited, "Structure of davPrivilegeSet changed in a way that I don't know how to extend for calendarPrivilegeSet"
-
-    return davxml.SupportedPrivilegeSet(*top_supported_privileges)
-
-calendarPrivilegeSet = _calendarPrivilegeSet()
-
-##
-# Attach methods
-##
-
-import twistedcaldav.method
-
-bindMethods(twistedcaldav.method, CalDAVFile)
-
-# Some resources do not support some methods
-setattr(CalendarHomeFile, "http_ACL", None)
-setattr(AddressBookHomeFile, "http_ACL", None)
-
-setattr(DropBoxCollectionFile, "http_MKCALENDAR", None)
-setattr(DropBoxChildFile, "http_MKCOL", None)
-setattr(DropBoxChildFile, "http_MKCALENDAR", None)
-
-# FIXME: Little bit of a circular dependency here...
-twistedcaldav.method.acl.CalDAVFile      = CalDAVFile
-twistedcaldav.method.copymove.CalDAVFile = CalDAVFile
-twistedcaldav.method.delete.CalDAVFile   = CalDAVFile
-twistedcaldav.method.get.CalDAVFile      = CalDAVFile
-twistedcaldav.method.mkcol.CalDAVFile    = CalDAVFile
-twistedcaldav.method.propfind.CalDAVFile = CalDAVFile
-twistedcaldav.method.put.CalDAVFile      = CalDAVFile
-
-
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100726/4ffc7c44/attachment-0001.html>


More information about the calendarserver-changes mailing list