[CalendarServer-changes] [5923] CalendarServer/branches/new-store-no-caldavfile

source_changes at macosforge.org source_changes at macosforge.org
Wed Jul 21 13:29:33 PDT 2010


Revision: 5923
          http://trac.macosforge.org/projects/calendarserver/changeset/5923
Author:   cdaboo at apple.com
Date:     2010-07-21 13:29:32 -0700 (Wed, 21 Jul 2010)
Log Message:
-----------
Big dump of current state. A lot more removal of CalDAVFile dependencies.

Modified Paths:
--------------
    CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/test/test_caldav.py
    CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/util.py
    CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/export.py
    CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/util.py
    CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/warmup.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/customxml.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/addressbook.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/aggregate.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendar.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendaruserproxy.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/principal.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/resource.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/test/test_principal.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directorybackedaddressbook.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/dropbox.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/extensions.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/freebusyurl.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/linkresource.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/mail.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/acl.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_common.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notifications.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notify.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/resource.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/schedule.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/utils.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharing.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/static.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/storebridge.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_schedule.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_sharing.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_wrapping.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/util.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/timezoneservice.py
    CalendarServer/branches/new-store-no-caldavfile/txcaldav/calendarstore/file.py
    CalendarServer/branches/new-store-no-caldavfile/txcarddav/addressbookstore/file.py
    CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/__init__.py
    CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/file.py

Added Paths:
-----------
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/bind.py

Modified: CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/test/test_caldav.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/test/test_caldav.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/test/test_caldav.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -47,8 +47,10 @@
 from twistedcaldav.stdconfig import DEFAULT_CONFIG
 
 from twistedcaldav.directory.aggregate import AggregateDirectoryService
+from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
+from twistedcaldav.directory.directory import UnknownRecordTypeError
+from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
 from twistedcaldav.directory.sudo import SudoDirectoryService
-from twistedcaldav.directory.directory import UnknownRecordTypeError
 from twistedcaldav.test.util import TestCase
 
 from calendarserver.tap.caldav import (
@@ -56,8 +58,6 @@
     DelayedStartupProcessMonitor, DelayedStartupLineLogger, TwistdSlaveProcess
 )
 from calendarserver.provision.root import RootResource
-from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
-from twistedcaldav.static import CalendarHomeProvisioningFile
 
 
 # Points to top of source tree.
@@ -724,7 +724,7 @@
 
         self.failUnless(isinstance(
             root.getChild("calendars"),
-            CalendarHomeProvisioningFile
+            DirectoryCalendarHomeProvisioningResource
         ))
 
 

Modified: CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/util.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/util.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/util.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -36,8 +36,11 @@
 from twext.python.log import Logger
 
 from twistedcaldav import memcachepool
+from twistedcaldav.bind import doBind
 from twistedcaldav.directory import augment, calendaruserproxy
+from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeProvisioningResource
 from twistedcaldav.directory.aggregate import AggregateDirectoryService
+from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
 from twistedcaldav.directory.digest import QopDigestCredentialFactory
 from twistedcaldav.directory.internal import InternalDirectoryService
 from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
@@ -48,8 +51,7 @@
 from twistedcaldav.resource import CalDAVResource, AuthenticationWrapper
 from twistedcaldav.schedule import IScheduleInboxResource
 from twistedcaldav.simpleresource import SimpleResource
-from twistedcaldav.static import CalendarHomeProvisioningFile
-from twistedcaldav.static import AddressBookHomeProvisioningFile, DirectoryBackedAddressBookFile
+from twistedcaldav.static import DirectoryBackedAddressBookFile
 from twistedcaldav.timezones import TimezoneCache
 from twistedcaldav.timezoneservice import TimezoneServiceResource
 from twistedcaldav.util import getMemorySize, getNCPU
@@ -81,18 +83,21 @@
     tuples containing: path, resource class, __init__ args list, and optional
     authentication scheme ("basic" or "digest").
     """
+    
+    # FIXME: this is only here to workaround circular imports
+    doBind()
 
     #
     # Default resource classes
     #
     rootResourceClass            = RootResource
     principalResourceClass       = DirectoryPrincipalProvisioningResource
-    calendarResourceClass        = CalendarHomeProvisioningFile
+    calendarResourceClass        = DirectoryCalendarHomeProvisioningResource
     iScheduleResourceClass       = IScheduleInboxResource
     timezoneServiceResourceClass = TimezoneServiceResource
     webCalendarResourceClass     = WebCalendarResource
     webAdminResourceClass        = WebAdminResource
-    addressBookResourceClass     = AddressBookHomeProvisioningFile
+    addressBookResourceClass     = DirectoryAddressBookHomeProvisioningResource
     directoryBackedAddressBookResourceClass = DirectoryBackedAddressBookFile
 
     #
@@ -286,16 +291,16 @@
     if config.EnableCalDAV:
         log.info("Setting up calendar collection: %r" % (calendarResourceClass,))
         calendarCollection = calendarResourceClass(
-            os.path.join(config.DocumentRoot, "calendars"),
-            directory, "/calendars/",
+            directory,
+            "/calendars/",
             _newStore,
         )
 
     if config.EnableCardDAV:
         log.info("Setting up address book collection: %r" % (addressBookResourceClass,))
         addressBookCollection = addressBookResourceClass(
-            os.path.join(config.DocumentRoot, "addressbooks"),
-            directory, "/addressbooks/",
+            directory,
+            "/addressbooks/",
             _newStore,
         )
 

Modified: CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/export.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/export.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/export.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -39,8 +39,9 @@
 from twistedcaldav.config import ConfigurationError
 from twistedcaldav.ical import Component as iComponent, Property as iProperty
 from twistedcaldav.ical import iCalendarProductID
-from twistedcaldav.resource import isCalendarCollectionResource
-from twistedcaldav.static import CalDAVFile, CalendarHomeFile
+from twistedcaldav.resource import isCalendarCollectionResource,\
+    CalendarHomeResource
+from twistedcaldav.static import CalDAVFile
 from twistedcaldav.directory.directory import DirectoryService
 
 from calendarserver.tools.util import UsageError
@@ -123,7 +124,7 @@
         elif opt in ("-H", "--home"):
             path = abspath(arg)
             parent = CalDAVFile(dirname(abspath(path)))
-            calendarHome = CalendarHomeFile(arg, parent, dummyDirectoryRecord)
+            calendarHome = CalendarHomeResource(arg, parent, dummyDirectoryRecord)
             checkExists(calendarHome)
             calendarHomes.add(calendarHome)
 

Modified: CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/util.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/util.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/util.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -22,7 +22,7 @@
     "booleanArgument",
 ]
 
-import os, sys
+import os
 from time import sleep
 import socket
 from pwd import getpwnam
@@ -38,9 +38,8 @@
 from twistedcaldav.config import config, ConfigurationError
 from twistedcaldav.directory import augment, calendaruserproxy
 from twistedcaldav.directory.aggregate import AggregateDirectoryService
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord, DirectoryError
+from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
 from twistedcaldav.notify import installNotificationClient
-from twistedcaldav.static import CalendarHomeProvisioningFile
 from twistedcaldav.stdconfig import DEFAULT_CONFIG_FILE
 
 from txdav.common.datastore.file import CommonDataStore
@@ -68,13 +67,13 @@
                 _newStore = CommonDataStore(FilePath(config.DocumentRoot), True, False)
 
                 #
-                # Instantiating a CalendarHomeProvisioningResource with a directory
+                # Instantiating a DirectoryCalendarHomeProvisioningResource with a directory
                 # will register it with the directory (still smells like a hack).
                 #
                 # We need that in order to locate calendar homes via the directory.
                 #
-                from twistedcaldav.static import CalendarHomeProvisioningFile
-                CalendarHomeProvisioningFile(os.path.join(config.DocumentRoot, "calendars"), self, "/calendars/", _newStore)
+                from twistedcaldav.resource import DirectoryCalendarHomeProvisioningResource
+                DirectoryCalendarHomeProvisioningResource(self, "/calendars/", _newStore)
 
                 from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
                 self._principalCollection = DirectoryPrincipalProvisioningResource("/principals/", self)
@@ -143,8 +142,7 @@
     # Need a data store
     _newStore = CommonDataStore(FilePath(config.DocumentRoot), True, False)
 
-    calendarCollection = CalendarHomeProvisioningFile(
-        os.path.join(config.DocumentRoot, "calendars"),
+    calendarCollection = DirectoryCalendarHomeProvisioningResource(
         aggregate, "/calendars/",
         _newStore,
     )

Modified: CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/warmup.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/warmup.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/calendarserver/tools/warmup.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -33,8 +33,9 @@
 from os.path import dirname, abspath
 
 from twistedcaldav.config import ConfigurationError
-from twistedcaldav.resource import isPseudoCalendarCollectionResource
-from twistedcaldav.static import CalDAVFile, CalendarHomeFile
+from twistedcaldav.resource import isPseudoCalendarCollectionResource,\
+    CalendarHomeResource
+from twistedcaldav.static import CalDAVFile
 from twistedcaldav.directory.directory import DirectoryService
 
 from calendarserver.tools.util import loadConfig, getDirectory, dummyDirectoryRecord
@@ -104,7 +105,7 @@
         elif opt in ("-H", "--home"):
             path = abspath(arg)
             parent = CalDAVFile(dirname(abspath(path)))
-            calendarHome = CalendarHomeFile(arg, parent, dummyDirectoryRecord)
+            calendarHome = CalendarHomeResource(arg, parent, dummyDirectoryRecord)
             checkExists(calendarHome)
             calendarHomes.add(calendarHome)
 

Added: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/bind.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/bind.py	                        (rev 0)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/bind.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -0,0 +1,31 @@
+##
+# Copyright (c) 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.
+##
+
+"""
+Bind methods.
+Have to have this in a separate module for now.
+"""
+
+from twext.web2.dav.util import bindMethods
+
+##
+# Attach methods
+##
+
+def doBind():
+    import twistedcaldav.method
+    from twistedcaldav.resource import CalDAVResource
+    bindMethods(twistedcaldav.method, CalDAVResource)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/customxml.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/customxml.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -325,7 +325,7 @@
 
 class PubSubXMPPURIProperty (davxml.WebDAVTextElement):
     """
-    A calendarhomefile property to indicate the pubsub XMPP URI to subscribe to
+    A calendar home property to indicate the pubsub XMPP URI to subscribe to
     for notifications.
     """
     namespace = calendarserver_namespace
@@ -335,7 +335,7 @@
 
 class PubSubHeartbeatProperty (davxml.WebDAVElement):
     """
-    A calendarhomefile property to indicate the pubsub XMPP URI to subscribe to
+    A calendar home property to indicate the pubsub XMPP URI to subscribe to
     for server heartbeats.
     """
     namespace = calendarserver_namespace
@@ -361,7 +361,7 @@
 
 class PubSubXMPPServerProperty (davxml.WebDAVTextElement):
     """
-    A calendarhomefile property to indicate the pubsub XMPP hostname to
+    A calendar home property to indicate the pubsub XMPP hostname to
     contact for notifications.
     """
     namespace = calendarserver_namespace
@@ -973,6 +973,14 @@
         (calendarserver_namespace, "invite-reply")          : (0, None),
     }
 
+class Link (davxml.WebDAVEmptyElement):
+    """
+    Denotes a linked resource.
+    """
+    namespace = calendarserver_namespace
+    name = "link"
+
+
 ##
 # Extensions to davxml.ResourceType
 ##
@@ -988,3 +996,4 @@
 davxml.ResourceType.sharedownercalendar = davxml.ResourceType(davxml.Collection(), caldavxml.Calendar(), SharedOwner())
 davxml.ResourceType.sharedcalendar = davxml.ResourceType(davxml.Collection(), caldavxml.Calendar(), Shared())
 davxml.ResourceType.sharedaddressbook = davxml.ResourceType(davxml.Collection(), carddavxml.AddressBook(), Shared())
+davxml.ResourceType.link = davxml.ResourceType(Link())

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/addressbook.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/addressbook.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/addressbook.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -25,7 +25,6 @@
     "DirectoryAddressBookHomeTypeProvisioningResource",
     "DirectoryAddressBookHomeUIDProvisioningResource",
     "DirectoryAddressBookHomeResource",
-    "GlobalAddressBookResource",
 ]
 
 from twext.python.log import Logger
@@ -39,22 +38,30 @@
 
 from twistedcaldav.config import config
 from twistedcaldav.directory.idirectory import IDirectoryService
-from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn
-from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource
-from twistedcaldav.notifications import NotificationCollectionResource
-from twistedcaldav.resource import CalDAVResource, CalDAVComplianceMixIn
+from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn,\
+    DirectoryReverseProxyResource
+from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource,\
+    DAVResourceWithChildrenMixin
 
 log = Logger()
 
 # Use __underbars__ convention to avoid conflicts with directory resource types.
 uidsResourceName = "__uids__"
 
+# FIXME: copied from resource.py to avoid circular dependency
+class CalDAVComplianceMixIn(object):
+    def davComplianceClasses(self):
+        return (
+            tuple(super(CalDAVComplianceMixIn, self).davComplianceClasses())
+            + config.CalDAVComplianceClasses
+        )
 
 class DirectoryAddressBookProvisioningResource (
     AutoProvisioningResourceMixIn,
     ReadOnlyResourceMixIn,
     CalDAVComplianceMixIn,
     DAVResource,
+    DAVResourceWithChildrenMixin,
 ):
     def defaultAccessControlList(self):
         return config.ProvisioningResourceACL
@@ -64,7 +71,7 @@
     """
     Resource which provisions address book home collections as needed.    
     """
-    def __init__(self, directory, url):
+    def __init__(self, directory, url, store):
         """
         @param directory: an L{IDirectoryService} to provision address books from.
         @param url: the canonical URL for the resource.
@@ -73,9 +80,11 @@
         assert url.endswith("/"), "Collection URL must end in '/'"
 
         DAVResource.__init__(self)
+        DAVResourceWithChildrenMixin.__init__(self)
 
         self.directory = IDirectoryService(directory)
         self._url = url
+        self._newStore = store
 
         # FIXME: Smells like a hack
         directory.addressBookHomesCollection = self
@@ -91,15 +100,15 @@
 
         provisionChild(uidsResourceName)
 
-    def provisionChild(self, recordType):
-        raise NotImplementedError("Subclass must implement provisionChild()")
+    def provisionChild(self, name):
+        if name == uidsResourceName:
+            return DirectoryAddressBookHomeUIDProvisioningResource(self)
 
+        return DirectoryAddressBookHomeTypeProvisioningResource(self, name)
+
     def url(self):
         return self._url
 
-    def getChild(self, name):
-        return self.putChildren.get(name, None)
-
     def listChildren(self):
         return self.directory.recordTypes()
 
@@ -142,6 +151,7 @@
         assert recordType is not None
 
         DAVResource.__init__(self)
+        DAVResourceWithChildrenMixin.__init__(self)
 
         self.directory = parent.directory
         self.recordType = recordType
@@ -177,7 +187,7 @@
             # Not a listable collection
             raise HTTPError(responsecode.FORBIDDEN)
 
-    def createSimilarFile(self, path):
+    def makeChild(self, name):
         raise HTTPError(responsecode.NOT_FOUND)
 
     ##
@@ -199,6 +209,7 @@
 
 
 class DirectoryAddressBookHomeUIDProvisioningResource (DirectoryAddressBookProvisioningResource):
+
     def __init__(self, parent):
         """
         @param parent: the parent of this resource
@@ -206,13 +217,30 @@
         assert parent is not None
 
         DAVResource.__init__(self)
+        DAVResourceWithChildrenMixin.__init__(self)
 
         self.directory = parent.directory
         self.parent = parent
+        
+        # TODO: better way to get this class - perhaps request from the store
+        from twistedcaldav.resource import AddressBookHomeResource
+        self.homeResourceClass = AddressBookHomeResource
 
     def url(self):
         return joinURL(self.parent.url(), uidsResourceName)
 
+    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 getChild(self, name, record=None):
         raise NotImplementedError("DirectoryAddressBookHomeUIDProvisioningResource.getChild no longer exists.")
 
@@ -220,6 +248,34 @@
         # Not a listable collection
         raise HTTPError(responsecode.FORBIDDEN)
 
+    def homeResourceForRecord(self, record, request):
+
+        self.provision()
+        TRANSACTION_KEY = '_newStoreTransaction'
+        transaction = getattr(request, TRANSACTION_KEY, None)
+        if transaction is None:
+            transaction = self.parent._newStore.newTransaction(repr(request))
+            setattr(request, TRANSACTION_KEY, transaction)
+
+        name = record.uid
+
+        if record is None:
+            self.log_msg("No directory record with GUID %r" % (name,))
+            return None
+
+        if not record.enabledForAddressBooks:
+            self.log_msg("Directory record %r is not enabled for address books" % (record,))
+            return None
+
+        assert len(name) > 4, "Directory record has an invalid GUID: %r" % (name,)
+        
+        if record.locallyHosted():
+            child = self.homeResourceClass(self, record, transaction)
+        else:
+            child = DirectoryReverseProxyResource(self, record)
+
+        return child
+
     ##
     # DAV
     ##
@@ -238,7 +294,7 @@
         return self.parent.principalForRecord(record)
 
 
-class DirectoryAddressBookHomeResource (AutoProvisioningResourceMixIn, CalDAVResource):
+class DirectoryAddressBookHomeResource (AutoProvisioningResourceMixIn, DAVResource, DAVResourceWithChildrenMixin):
     """
     Address book home collection resource.
     """
@@ -249,13 +305,15 @@
         assert parent is not None
         assert record is not None
 
-        CalDAVResource.__init__(self)
+        DAVResource.__init__(self)
+        DAVResourceWithChildrenMixin.__init__(self)
 
         self.record = record
         self.parent = parent
 
         childlist = ()
         if config.Sharing.Enabled and config.Sharing.AddressBooks.Enabled and not config.Sharing.Calendars.Enabled:
+            from twistedcaldav.notifications import NotificationCollectionResource
             childlist += (
                 ("notification", NotificationCollectionResource),
             )
@@ -275,7 +333,6 @@
     
             childName = "addressbook"
             child = self.provisionChild(childName)
-            assert isinstance(child, CalDAVResource), "Child %r is not a %s: %r" % (childName, CalDAVResource.__name__, child) #@UndefinedVariable
 
             d = child.createAddressBookCollection()
         except:
@@ -370,43 +427,3 @@
             is quota-controlled, or C{None} if not quota controlled.
         """
         return config.UserQuota if config.UserQuota != 0 else None
-
-class GlobalAddressBookResource (CalDAVResource):
-    """
-    Global address book. All we care about is making sure permissions are setup.
-    """
-
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.sharedaddressbook)
-
-    def defaultAccessControlList(self):
-
-        aces = (
-            davxml.ACE(
-                davxml.Principal(davxml.Authenticated()),
-                davxml.Grant(
-                    davxml.Privilege(davxml.Read()),
-                    davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
-                    davxml.Privilege(davxml.Write()),
-                ),
-                davxml.Protected(),
-                TwistedACLInheritable(),
-           ),
-        )
-        
-        if config.GlobalAddressBook.EnableAnonymousReadAccess:
-            aces += (
-                davxml.ACE(
-                    davxml.Principal(davxml.Unauthenticated()),
-                    davxml.Grant(
-                        davxml.Privilege(davxml.Read()),
-                    ),
-                    davxml.Protected(),
-                    TwistedACLInheritable(),
-               ),
-            )
-        return davxml.ACL(*aces)
-
-    def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
-        # Permissions here are fixed, and are not subject to inheritance rules, etc.
-        return succeed(self.defaultAccessControlList())

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/aggregate.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/aggregate.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/aggregate.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -83,7 +83,6 @@
 
     #
     # Define calendarHomesCollection as a property so we can set it on contained services
-    # See CalendarHomeProvisioningFile.__init__()
     #
     def _getCalendarHomesCollection(self):
         return self._calendarHomesCollection
@@ -97,7 +96,6 @@
 
     #
     # Define addressBookHomesCollection as a property so we can set it on contained services
-    # See AddressBookHomeProvisioningFile.__init__()
     #
     def _getAddressBookHomesCollection(self):
         return self._addressBookHomesCollection

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendar.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendar.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -40,26 +40,32 @@
 from twistedcaldav import caldavxml
 from twistedcaldav.config import config
 from twistedcaldav.dropbox import DropBoxHomeResource
-from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource
-from twistedcaldav.freebusyurl import FreeBusyURLResource
-from twistedcaldav.resource import CalDAVResource, CalDAVComplianceMixIn
-from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource
+from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource,\
+    DAVResourceWithChildrenMixin
 from twistedcaldav.directory.idirectory import IDirectoryService
 from twistedcaldav.directory.wiki import getWikiACL
-from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn
-from twistedcaldav.notifications import NotificationCollectionResource
+from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn,\
+    DirectoryReverseProxyResource
 
 log = Logger()
 
 # Use __underbars__ convention to avoid conflicts with directory resource types.
 uidsResourceName = "__uids__"
 
+# FIXME: copied from resource.py to avoid circular dependency
+class CalDAVComplianceMixIn(object):
+    def davComplianceClasses(self):
+        return (
+            tuple(super(CalDAVComplianceMixIn, self).davComplianceClasses())
+            + config.CalDAVComplianceClasses
+        )
 
 class DirectoryCalendarProvisioningResource (
     AutoProvisioningResourceMixIn,
     ReadOnlyResourceMixIn,
     CalDAVComplianceMixIn,
     DAVResource,
+    DAVResourceWithChildrenMixin,
 ):
     def defaultAccessControlList(self):
         return config.ProvisioningResourceACL
@@ -69,7 +75,7 @@
     """
     Resource which provisions calendar home collections as needed.    
     """
-    def __init__(self, directory, url):
+    def __init__(self, directory, url, store):
         """
         @param directory: an L{IDirectoryService} to provision calendars from.
         @param url: the canonical URL for the resource.
@@ -78,9 +84,11 @@
         assert url.endswith("/"), "Collection URL must end in '/'"
 
         DAVResource.__init__(self)
+        DAVResourceWithChildrenMixin.__init__(self)
 
         self.directory = IDirectoryService(directory)
         self._url = url
+        self._newStore = store
 
         # FIXME: Smells like a hack
         directory.calendarHomesCollection = self
@@ -96,15 +104,15 @@
 
         provisionChild(uidsResourceName)
 
-    def provisionChild(self, recordType):
-        raise NotImplementedError("Subclass must implement provisionChild()")
+    def provisionChild(self, name):
+        if name == uidsResourceName:
+            return DirectoryCalendarHomeUIDProvisioningResource(self)
 
+        return DirectoryCalendarHomeTypeProvisioningResource(self, name)
+
     def url(self):
         return self._url
 
-    def getChild(self, name):
-        return self.putChildren.get(name, None)
-
     def listChildren(self):
         return self.directory.recordTypes()
 
@@ -147,6 +155,7 @@
         assert recordType is not None
 
         DAVResource.__init__(self)
+        DAVResourceWithChildrenMixin.__init__(self)
 
         self.directory = parent.directory
         self.recordType = recordType
@@ -182,7 +191,7 @@
             # Not a listable collection
             raise HTTPError(responsecode.FORBIDDEN)
 
-    def createSimilarFile(self, path):
+    def makeChild(self, name):
         raise HTTPError(responsecode.NOT_FOUND)
 
     ##
@@ -204,6 +213,7 @@
 
 
 class DirectoryCalendarHomeUIDProvisioningResource (DirectoryCalendarProvisioningResource):
+
     def __init__(self, parent):
         """
         @param parent: the parent of this resource
@@ -211,13 +221,30 @@
         assert parent is not None
 
         DAVResource.__init__(self)
+        DAVResourceWithChildrenMixin.__init__(self)
 
         self.directory = parent.directory
         self.parent = parent
+        
+        # TODO: better way to get this class - perhaps request from the store
+        from twistedcaldav.resource import CalendarHomeResource
+        self.homeResourceClass = CalendarHomeResource
 
     def url(self):
         return joinURL(self.parent.url(), uidsResourceName)
 
+    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 getChild(self, name, record=None):
         raise NotImplementedError("DirectoryCalendarProvisioningResource.getChild no longer exists.")
 
@@ -225,6 +252,34 @@
         # Not a listable collection
         raise HTTPError(responsecode.FORBIDDEN)
 
+    def homeResourceForRecord(self, record, request):
+
+        self.provision()
+        TRANSACTION_KEY = '_newStoreTransaction'
+        transaction = getattr(request, TRANSACTION_KEY, None)
+        if transaction is None:
+            transaction = self.parent._newStore.newTransaction(repr(request))
+            setattr(request, TRANSACTION_KEY, transaction)
+
+        name = record.uid
+
+        if record is None:
+            self.log_msg("No directory record with GUID %r" % (name,))
+            return None
+
+        if not record.enabledForCalendaring:
+            self.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():
+            child = self.homeResourceClass(self, record, transaction)
+        else:
+            child = DirectoryReverseProxyResource(self, record)
+
+        return child
+
     ##
     # DAV
     ##
@@ -243,7 +298,7 @@
         return self.parent.principalForRecord(record)
 
 
-class DirectoryCalendarHomeResource (AutoProvisioningResourceMixIn, CalDAVResource):
+class DirectoryCalendarHomeResource (AutoProvisioningResourceMixIn, DAVResource, DAVResourceWithChildrenMixin):
     """
     Calendar home collection resource.
     """
@@ -254,12 +309,14 @@
         assert parent is not None
         assert record is not None
 
-        CalDAVResource.__init__(self)
+        DAVResource.__init__(self)
+        DAVResourceWithChildrenMixin.__init__(self)
 
         self.record = record
         self.parent = parent
 
         # Cache children which must be of a specific type
+        from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource
         childlist = (
             ("inbox" , ScheduleInboxResource ),
             ("outbox", ScheduleOutboxResource),
@@ -269,10 +326,12 @@
                 ("dropbox", DropBoxHomeResource),
             )
         if config.FreeBusyURL.Enabled:
+            from twistedcaldav.freebusyurl import FreeBusyURLResource
             childlist += (
                 ("freebusy", FreeBusyURLResource),
             )
         if config.Sharing.Enabled and config.Sharing.Calendars.Enabled:
+            from twistedcaldav.notifications import NotificationCollectionResource
             childlist += (
                 ("notification", NotificationCollectionResource),
             )

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendaruserproxy.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendaruserproxy.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -128,13 +128,13 @@
         """
         return ProxyDBService
 
-    def resourceType(self, request):
+    def resourceType(self):
         if self.proxyType == "calendar-proxy-read":
-            return succeed(davxml.ResourceType.calendarproxyread)
+            return davxml.ResourceType.calendarproxyread
         elif self.proxyType == "calendar-proxy-write":
-            return succeed(davxml.ResourceType.calendarproxywrite)
+            return davxml.ResourceType.calendarproxywrite
         else:
-            return super(CalendarUserProxyPrincipalResource, self).resourceType(request)
+            return super(CalendarUserProxyPrincipalResource, self).resourceType()
 
     def isProxyType(self, read_write):
         if (

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/principal.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/principal.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -936,7 +936,6 @@
 
     def calendarHome(self, request):
         # FIXME: self.record.service.calendarHomesCollection smells like a hack
-        # See CalendarHomeProvisioningFile.__init__()
         service = self.record.service
         if hasattr(service, "calendarHomesCollection"):
             return service.calendarHomesCollection.homeForDirectoryRecord(self.record, request)
@@ -960,7 +959,6 @@
 
     def addressBookHome(self, request):
         # FIXME: self.record.service.addressBookHomesCollection smells like a hack
-        # See AddressBookHomeProvisioningFile.__init__()
         service = self.record.service
         if hasattr(service, "addressBookHomesCollection"):
             return service.addressBookHomesCollection.homeForDirectoryRecord(self.record, request)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/resource.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/resource.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/resource.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -13,6 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+from twistedcaldav.client.reverseproxy import ReverseProxyResource
+from twext.web2.dav.util import joinURL
 
 """
 Implements a directory-backed principal hierarchy.
@@ -69,3 +71,16 @@
         
         result = (yield super(AutoProvisioningResourceMixIn, self).locateChild(request, segments))
         returnValue(result)
+
+class DirectoryReverseProxyResource(ReverseProxyResource):
+    
+    def __init__(self, parent, record):
+        self.parent = parent
+        self.record = record
+        
+        super(DirectoryReverseProxyResource, self).__init__(self.record.hostedAt)
+    
+    def url(self):
+        return joinURL(self.parent.url(), self.record.uid)
+
+

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/test/test_principal.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/test/test_principal.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -23,7 +23,6 @@
 from twext.web2.dav.resource import AccessDeniedError
 from twext.web2.test.test_server import SimpleRequest
 
-from twistedcaldav.static import CalendarHomeProvisioningFile
 from twistedcaldav.config import config
 from twistedcaldav.directory import augment, calendaruserproxy
 from twistedcaldav.directory.directory import DirectoryService
@@ -358,21 +357,19 @@
         # Need to create a calendar home provisioner for each service.
         calendarRootResources = {}
 
-        # Need a data store
-        _newStore = CommonDataStore(FilePath(self.docroot), True, False)
-
         for directory in self.directoryServices:
-            url = "/homes_" + directory.__class__.__name__ + "/"
-            path = os.path.join(self.docroot, url[1:])
+            path = os.path.join(self.docroot, directory.__class__.__name__)
 
             if os.path.exists(path):
                 rmdir(path)
             os.mkdir(path)
 
-            provisioningResource = CalendarHomeProvisioningFile(
-                path,
+            # Need a data store
+            _newStore = CommonDataStore(path, True, False)
+
+            provisioningResource = DirectoryCalendarHomeProvisioningResource(
                 directory,
-                url,
+                "/calendars/",
                 _newStore
             )
 

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directorybackedaddressbook.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directorybackedaddressbook.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directorybackedaddressbook.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -94,8 +94,8 @@
            ),
         )
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.addressbook)
+    def resourceType(self):
+        return davxml.ResourceType.addressbook
 
     def isDirectoryBackedAddressBookCollection(self):
         return True

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/dropbox.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/dropbox.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/dropbox.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -41,8 +41,8 @@
     """
     Drop box collection resource.
     """
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.dropboxhome)
+    def resourceType(self):
+        return davxml.ResourceType.dropboxhome
 
     def isCollection(self):
         return True
@@ -83,8 +83,8 @@
     """
     Drop box resource.
     """
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.dropbox)
+    def resourceType(self):
+        return davxml.ResourceType.dropbox
 
     def isCollection(self):
         return True

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/extensions.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/extensions.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -21,6 +21,7 @@
 
 __all__ = [
     "DAVResource",
+    "DAVResourceWithChildren",
     "DAVPrincipalResource",
     "DAVFile",
     "ReadOnlyWritePropertiesResourceMixIn",
@@ -515,7 +516,7 @@
         for name in sorted(self.listChildren()):
             child = self.getChild(name)
 
-            url, name, size, lastModified, contentType = (yield self.getChildDirectoryEntry(child, name, request))
+            url, name, size, lastModified, contentType = self.getChildDirectoryEntry(child, name, request)
 
             # FIXME: gray out resources that are not readable
             output.append(
@@ -624,7 +625,6 @@
         result = (yield gotProperties(qnames))
         returnValue(result)
 
-    @inlineCallbacks
     def getChildDirectoryEntry(self, child, name, request):
         def orNone(value, default="?", f=None):
             if value is None:
@@ -643,7 +643,7 @@
             size = child.contentLength()
             lastModified = child.lastModified()
             rtypes = []
-            fullrtype = (yield child.resourceType(request))
+            fullrtype = child.resourceType()
             for rtype in fullrtype.children:
                 rtypes.append(rtype.name)
             if rtypes:
@@ -663,8 +663,16 @@
             size = None
             lastModified = None
             contentType = None
+            if hasattr(child, "resourceType"):
+                rtypes = []
+                fullrtype = child.resourceType()
+                for rtype in fullrtype.children:
+                    rtypes.append(rtype.name)
+                if rtypes:
+                    contentType = "(%s)" % (", ".join(rtypes),)
+                
 
-        returnValue((
+        return ((
             url,
             name,
             orNone(size),
@@ -698,14 +706,59 @@
         return super(DAVResource, self).render(request)
 
 
-    def resourceType(self, request):
+    def resourceType(self):
         # Allow live property to be overridden by dead property
         if self.deadProperties().contains((dav_namespace, "resourcetype")):
-            return succeed(self.deadProperties().get((dav_namespace, "resourcetype")))
-        return succeed(davxml.ResourceType())
+            return self.deadProperties().get((dav_namespace, "resourcetype"))
+        return davxml.ResourceType()
 
 
+class DAVResourceWithChildrenMixin (object):
+    """
+    Bits needed from twext.web2.static
+    """
 
+    def __init__(self):
+        self.putChildren = {}
+
+    def putChild(self, name, child):
+        """
+        Register a child with the given name with this resource.
+        @param name: the name of the child (a URI path segment)
+        @param child: the child to register
+        """
+        self.putChildren[name] = child
+
+    def getChild(self, name):
+        """
+        Look up a child resource.
+        @return: the child of this resource with the given name.
+        """
+        if name == "":
+            return self
+
+        result = self.putChildren.get(name, None)
+        if not result:
+            result = self.makeChild(name)
+        return result
+
+    def makeChild(self):
+        # Subclasses with real children need to override this and return the appropriate object
+        return None
+
+    def listChildren(self):
+        """
+        @return: a sequence of the names of all known children of this resource.
+        """
+        return self.putChildren.keys()
+
+    def locateChild(self, req, segments):
+        """
+        See L{IResource}C{.locateChild}.
+        """
+        # If getChild() finds a child resource, return it
+        return (self.getChild(segments[0]), segments[1:])
+
 class DAVPrincipalResource (DirectoryPrincipalPropertySearchMixIn,
                             SuperDAVPrincipalResource, LoggingMixIn,
                             DirectoryRenderingMixIn):
@@ -733,7 +786,7 @@
 
         if namespace == dav_namespace:
             if name == "resourcetype":
-                rtype = (yield self.resourceType(request))
+                rtype = self.resourceType()
                 returnValue(rtype)
 
         elif namespace == calendarserver_namespace:
@@ -775,14 +828,14 @@
     def expandedGroupMemberships(self):
         return succeed(())
 
-    def resourceType(self, request):
+    def resourceType(self):
         # Allow live property to be overridden by dead property
         if self.deadProperties().contains((dav_namespace, "resourcetype")):
-            return succeed(self.deadProperties().get((dav_namespace, "resourcetype")))
+            return self.deadProperties().get((dav_namespace, "resourcetype"))
         if self.isCollection():
-            return succeed(davxml.ResourceType(davxml.Principal(), davxml.Collection()))
+            return davxml.ResourceType(davxml.Principal(), davxml.Collection())
         else:
-            return succeed(davxml.ResourceType(davxml.Principal()))
+            return davxml.ResourceType(davxml.Principal())
 
 
 
@@ -791,24 +844,14 @@
     """
     Extended L{twext.web2.dav.static.DAVFile} implementation.
     """
-    def readProperty(self, property, request):
-        if type(property) is tuple:
-            qname = property
-        else:
-            qname = property.qname()
 
-        if qname == (dav_namespace, "resourcetype"):
-            return self.resourceType(request)
-
-        return super(DAVFile, self).readProperty(property, request)
-
-    def resourceType(self, request):
+    def resourceType(self):
         # Allow live property to be overridden by dead property
         if self.deadProperties().contains((dav_namespace, "resourcetype")):
-            return succeed(self.deadProperties().get((dav_namespace, "resourcetype")))
+            return self.deadProperties().get((dav_namespace, "resourcetype"))
         if self.isCollection():
-            return succeed(davxml.ResourceType.collection)
-        return succeed(davxml.ResourceType.empty)
+            return davxml.ResourceType.collection
+        return davxml.ResourceType.empty
 
     def render(self, request):
         if not self.fp.exists():

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/freebusyurl.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/freebusyurl.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/freebusyurl.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -32,7 +32,6 @@
 from twext.web2 import responsecode
 from twext.web2.dav import davxml
 from twext.web2.dav.http import ErrorResponse
-from twext.web2.dav.method.propfind import http_PROPFIND
 from twext.web2.dav.util import joinURL
 from twext.web2.http import HTTPError
 from twext.web2.http import Response
@@ -48,7 +47,7 @@
 from twistedcaldav.ical import parse_datetime
 from twistedcaldav.ical import parse_duration
 from twistedcaldav.resource import CalDAVResource, ReadOnlyNoCopyResourceMixIn
-from twistedcaldav.resource import deliverSchedulePrivilegeSet
+from twistedcaldav.schedule import deliverSchedulePrivilegeSet
 from twistedcaldav.scheduling.caldav import ScheduleViaCalDAV
 from twistedcaldav.scheduling.cuaddress import LocalCalendarUser
 from twistedcaldav.scheduling.scheduler import Scheduler
@@ -105,8 +104,8 @@
             )
         return davxml.ACL(*aces)
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.freebusyurl)
+    def resourceType(self):
+        return davxml.ResourceType.freebusyurl
 
     def contentType(self):
         return MimeType("text", "calendar", charset="utf-8")
@@ -146,8 +145,6 @@
         """
         return self._processFBURL(request)
 
-    http_PROPFIND = http_PROPFIND
-
     @inlineCallbacks
     def _processFBURL(self, request):
         

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/linkresource.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/linkresource.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/linkresource.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -18,15 +18,24 @@
 
 from twisted.internet.defer import inlineCallbacks, returnValue, maybeDeferred
 
-from twistedcaldav.resource import CalDAVComplianceMixIn
 from twext.web2.http import HTTPError
 from twext.web2 import responsecode
 from twext.web2.resource import WrapperResource
+from twistedcaldav.config import config
+from twext.web2.dav import davxml
 
 __all__ = [
     "LinkResource",
 ]
 
+# FIXME: copied from resource.py to avoid circular dependency
+class CalDAVComplianceMixIn(object):
+    def davComplianceClasses(self):
+        return (
+            tuple(super(CalDAVComplianceMixIn, self).davComplianceClasses())
+            + config.CalDAVComplianceClasses
+        )
+
 """
 A resource that is a soft-link to another.
 """
@@ -55,11 +64,8 @@
     def isCollection(self):
         return True
 
-    @inlineCallbacks
-    def resourceType(self, request):
-        hosted = (yield self.linkedResource(request))
-        result = (yield hosted.resourceType(request))
-        returnValue(result)
+    def resourceType(self):
+        return self._linkedResource.resourceType() if hasattr(self, "_linkedResource") else davxml.ResourceType.link
         
     def locateChild(self, request, segments):
         

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/mail.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/mail.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/mail.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -61,11 +61,12 @@
 from twistedcaldav.directory.util import NotFilePath
 from twistedcaldav.ical import Property
 from twistedcaldav.localization import translationTo
+from twistedcaldav.schedule import deliverSchedulePrivilegeSet
 from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
 from twistedcaldav.scheduling.itip import iTIPRequestStatus
 from twistedcaldav.scheduling.scheduler import IMIPScheduler
 from twistedcaldav.sql import AbstractSQLDatabase
-from twistedcaldav.static import CalDAVFile, deliverSchedulePrivilegeSet
+from twistedcaldav.static import CalDAVFile
 from twistedcaldav.util import AuthorizedHTTPGetter
 from twistedcaldav.stdconfig import DEFAULT_CONFIG, DEFAULT_CONFIG_FILE
 
@@ -219,8 +220,8 @@
 
         return succeed(self.iMIPACL)
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.ischeduleinbox)
+    def resourceType(self):
+        return davxml.ResourceType.ischeduleinbox
 
     def isCollection(self):
         return False

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/acl.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/acl.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/acl.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -29,8 +29,8 @@
 from twisted.internet.defer import inlineCallbacks, returnValue
 
 from twistedcaldav.resource import isAddressBookCollectionResource,\
-    isPseudoCalendarCollectionResource
-from twistedcaldav.static import AddressBookHomeFile, CalendarHomeFile
+    isPseudoCalendarCollectionResource,\
+    CalendarHomeResource, AddressBookHomeResource
 
 log = Logger()
 
@@ -42,7 +42,7 @@
     #
 
     if self.exists():
-        if isinstance(self, CalendarHomeFile) or isinstance(self, AddressBookHomeFile):
+        if isinstance(self, CalendarHomeResource) or isinstance(self, AddressBookHomeResource):
             raise HTTPError(responsecode.NOT_ALLOWED)
 
         parentURL = parentForURL(request.uri)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_common.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_common.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -674,7 +674,7 @@
             if do_implicit_action and self.allowImplicitSchedule:
 
                 # Cannot do implicit in sharee's shared calendar
-                isvirt = (yield self.destinationparent.isVirtualShare(self.request))
+                isvirt = self.destinationparent.isVirtualShare()
                 if isvirt:
                     raise HTTPError(ErrorResponse(
                         responsecode.FORBIDDEN,

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notifications.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notifications.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notifications.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -29,7 +29,6 @@
 
 from twisted.internet.defer import succeed, inlineCallbacks, returnValue
 
-from twistedcaldav.method.propfind import http_PROPFIND
 from twistedcaldav.resource import ReadOnlyNoCopyResourceMixIn, CalDAVResource
 from twistedcaldav.sql import AbstractSQLDatabase, db_prefix
 
@@ -65,13 +64,9 @@
         if response == responsecode.NO_CONTENT:
             yield self._parent.removedNotifictionMessage(request, self.resourceName())
         returnValue(response)
-
-    http_PROPFIND = http_PROPFIND
     
 class NotificationCollectionResource(ReadOnlyNoCopyResourceMixIn, CalDAVResource):
 
-    http_PROPFIND = http_PROPFIND
-    
     def notificationsDB(self):
         
         if not hasattr(self, "_notificationsDB"):
@@ -81,8 +76,8 @@
     def isCollection(self):
         return True
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.notification)
+    def resourceType(self):
+        return davxml.ResourceType.notification
 
     @inlineCallbacks
     def addNotification(self, request, uid, xmltype, xmldata):

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notify.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notify.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notify.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -606,7 +606,7 @@
 
     Uses pubsub XMPP requests to let subscribers know when there
     has been a change made to a DAV resource (currently just
-    CalendarHomeFiles).  Uses XMPP login info from the config file
+    CalendarHomeResources).  Uses XMPP login info from the config file
     to determine which pubsub service to connect to.  When it's
     time to send a notification, XMPPNotifier computes a node path
     corresponding to the DAV resource and emits a publish request

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/resource.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/resource.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -14,6 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+from twistedcaldav.index import SyncTokenValidException
+from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
+from uuid import uuid4
+import datetime
+from twisted.python.failure import Failure
+from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeResource
+from twistedcaldav.linkresource import LinkResource, LinkFollowerMixIn
+from twistedcaldav.directory.internal import InternalDirectoryRecord
 
 """
 CalDAV-aware resources.
@@ -40,7 +48,7 @@
 from twext.web2.dav.http import ErrorResponse
 
 from twisted.internet import reactor
-from twisted.internet.defer import Deferred, succeed, maybeDeferred
+from twisted.internet.defer import Deferred, succeed, maybeDeferred, fail
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twext.web2 import responsecode
 from twext.web2.dav import davxml
@@ -50,8 +58,7 @@
 from twext.web2.dav.resource import AccessDeniedError, DAVPrincipalCollectionResource,\
     davPrivilegeSet
 from twext.web2.dav.resource import TwistedACLInheritable
-from twext.web2.dav.util import joinURL, parentForURL, unimplemented, normalizeURL,\
-    bindMethods
+from twext.web2.dav.util import joinURL, parentForURL, unimplemented, normalizeURL
 from twext.web2.http import HTTPError, RedirectResponse, StatusResponse, Response
 from twext.web2.http_headers import MimeType
 from twext.web2.stream import MemoryStream
@@ -64,15 +71,17 @@
 from twistedcaldav.customxml import TwistedCalendarAccessProperty
 from twistedcaldav.customxml import calendarserver_namespace
 from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
+from twistedcaldav.directory.calendar import DirectoryCalendarHomeResource
 from twistedcaldav.extensions import DAVResource, DAVPrincipalResource,\
     PropertyNotFoundError
 from twistedcaldav.ical import Component
 from twistedcaldav.ical import Component as iComponent
 from twistedcaldav.ical import allowedComponents
 from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
-from twistedcaldav.notify import getPubSubConfiguration, getPubSubPath
+from twistedcaldav.notify import getPubSubConfiguration, getPubSubPath,\
+    ClientNotifier, getPubSubXMPPURI, getPubSubHeartbeatURI
 from twistedcaldav.notify import getNodeCacher, NodeCreationException
-from twistedcaldav.sharing import SharedCollectionMixin
+from twistedcaldav.sharing import SharedCollectionMixin, SharedHomeMixin
 from twistedcaldav.vcard import Component as vComponent
 
 from txdav.common.icommondatastore import InternalDataStoreError
@@ -132,43 +141,6 @@
 
     def http_COPY(self, request): return responsecode.FORBIDDEN
 
-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
 
@@ -464,7 +436,7 @@
         else:
             qname = property.qname()
 
-        isvirt = (yield self.isVirtualShare(request))
+        isvirt = self.isVirtualShare()
         if isvirt:
             if self.isShadowableProperty(qname):
                 ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
@@ -503,7 +475,7 @@
         else:
             qname = property.qname()
 
-        isvirt = (yield self.isVirtualShare(request))
+        isvirt = self.isVirtualShare()
 
         if self.isCalendarCollection() or self.isAddressBookCollection():
             # Push notification DAV property "pushkey"
@@ -550,6 +522,9 @@
             owner = (yield self.owner(request))
             returnValue(davxml.Owner(owner))
 
+        elif qname == davxml.ResourceType.qname():
+            returnValue(self.resourceType())
+
         elif qname == davxml.ResourceID.qname():
             returnValue(davxml.ResourceID(davxml.HRef.fromString(self.resourceID())))
 
@@ -628,7 +603,7 @@
                 returnValue(customxml.AllowedSharingModes(customxml.CanBeShared()))
 
         elif qname == customxml.SharedURL.qname():
-            isvirt = (yield self.isVirtualShare(request))
+            isvirt = self.isVirtualShare()
             
             if isvirt:
                 returnValue(customxml.SharedURL(davxml.HRef.fromString(self._share.hosturl)))
@@ -645,7 +620,7 @@
         )
         
         # Per-user Dav props currently only apply to a sharee's copy of a calendar
-        isvirt = (yield self.isVirtualShare(request))
+        isvirt = self.isVirtualShare()
         if isvirt and (self.isShadowableProperty(property.qname()) or (not self.isGlobalProperty(property.qname()))):
             yield self._preProcessWriteProperty(property, request)
             ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
@@ -746,14 +721,14 @@
                 sawShare = [child for child in property.children if child.qname() == (calendarserver_namespace, "shared-owner")]
                 if not shared and sawShare:
                     # Owner is trying to share a collection
-                    yield self.upgradeToShare(request)
+                    self.upgradeToShare()
                 elif shared and not sawShare:
                     # Remove share
                     yield self.downgradeFromShare(request)
                 returnValue(None)
             else:
                 # resourcetype cannot be changed but we will allow it to be set to the same value
-                currentType = (yield self.resourceType(request))
+                currentType = self.resourceType()
                 if currentType == property:
                     returnValue(None)
 
@@ -769,7 +744,7 @@
     def accessControlList(self, request, *args, **kwargs):
 
         acls = None
-        isvirt = (yield self.isVirtualShare(request))
+        isvirt = self.isVirtualShare()
         if isvirt:
             acls = self.shareeAccessControlList()
 
@@ -826,7 +801,7 @@
         Return the DAV:owner property value (MUST be a DAV:href or None).
         """
         
-        isVirt = (yield self.isVirtualShare(request))
+        isVirt = self.isVirtualShare()
         if isVirt:
             parent = (yield self.locateParent(request, self._share.hosturl))
         else:
@@ -842,7 +817,7 @@
         """
         Return the DAV:owner property value (MUST be a DAV:href or None).
         """
-        isVirt = (yield self.isVirtualShare(request))
+        isVirt = self.isVirtualShare()
         if isVirt:
             parent = (yield self.locateParent(request, self._share.hosturl))
         else:
@@ -860,7 +835,7 @@
         collection it will be the sharee, otherwise it will be the regular the ownerPrincipal.
         """
 
-        isVirt = (yield self.isVirtualShare(request))
+        isVirt = self.isVirtualShare()
         if isVirt:
             returnValue(self._shareePrincipal)
         else:
@@ -1013,7 +988,7 @@
 
         if depth != "0" and self.isCollection():
             basepath = request.urlForResource(self)
-            children = self.listChildren()
+            children = list(self.listChildren())
             getChild()
         else:
             completionDeferred.callback(None)
@@ -1339,14 +1314,14 @@
         """
 
         sharedParent = None
-        isvirt = (yield self.isVirtualShare(request))
+        isvirt = self.isVirtualShare()
         if isvirt:
             # A virtual share's quota root is the resource owner's root
             sharedParent = (yield request.locateResource(parentForURL(self._share.hosturl)))
         else:
             parent = (yield self.locateParent(request, request.urlForResource(self)))
             if isCalendarCollectionResource(parent) or isAddressBookCollectionResource(parent):
-                isvirt = (yield parent.isVirtualShare(request))
+                isvirt = parent.isVirtualShare()
                 if isvirt:
                     # A virtual share's quota root is the resource owner's root
                     sharedParent = (yield request.locateResource(parentForURL(parent._share.hosturl)))
@@ -1358,6 +1333,109 @@
 
         returnValue(result)
 
+    # Collection sync stuff
+
+    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)
+
 class CalendarPrincipalCollectionResource (DAVPrincipalCollectionResource, CalDAVResource):
     """
     CalDAV principal collection.
@@ -1636,7 +1714,570 @@
         """
         return None
 
+class CalendarHomeResource(SharedHomeMixin, DirectoryCalendarHomeResource, CalDAVResource):
+    """
+    Calendar home collection resource.
+    """
+    def __init__(self, parent, record, transaction):
+        """
+        """
 
+        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
+        CalDAVResource.__init__(self)
+        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 liveProperties(self):
+        
+        return super(CalendarHomeResource, 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 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.exists():
+            self.provisionShares()
+        return
+
+    def provisionChild(self, name):
+        from twistedcaldav.storebridge import StoreScheduleInboxResource
+        from twistedcaldav.storebridge import DropboxCollection
+        if config.EnableDropBox:
+            DropBoxHomeFileClass = DropboxCollection
+        else:
+            DropBoxHomeFileClass = None
+
+        if config.FreeBusyURL.Enabled:
+            from twistedcaldav.freebusyurl import FreeBusyURLResource
+            FreeBusyURLResourceClass = FreeBusyURLResource
+        else:
+            FreeBusyURLResourceClass = None
+            
+        # For storebridge stuff we special case this
+        if name == "notification" and config.Sharing.Enabled and config.Sharing.Calendars.Enabled:
+            return self.createNotificationsCollection()
+
+        from twistedcaldav.schedule import ScheduleOutboxResource
+        cls = {
+            "inbox"        : StoreScheduleInboxResource,
+            "outbox"       : ScheduleOutboxResource,
+            "dropbox"      : DropBoxHomeFileClass,
+            "freebusy"     : FreeBusyURLResourceClass,
+        }.get(name, None)
+
+        if cls is not None:
+            child = cls(self)
+            child.clientNotifier = self.clientNotifier.clone(child,
+                label="collection")
+            return child
+        return self.makeChild(name)
+
+    def createNotificationsCollection(self):
+        
+        txn = self._newStoreCalendarHome._transaction
+        notifications = txn.notificationsWithUID(self._newStoreCalendarHome.uid())
+
+        from twistedcaldav.storebridge import StoreNotificationCollectionResource
+        similar = StoreNotificationCollectionResource(
+            notifications,
+            self._newStoreCalendarHome,
+            principalCollections = self.principalCollections(),
+        )
+        self.propagateTransaction(similar)
+        similar.clientNotifier = self.clientNotifier.clone(similar,
+            label="collection")
+        return similar
+
+    def makeChild(self, name):
+
+        newCalendar = self._newStoreCalendarHome.calendarWithName(name)
+        if newCalendar is None:
+            # Local imports.due to circular dependency between modules.
+            from twistedcaldav.storebridge import (
+                 ProtoCalendarCollectionResource)
+            similar = ProtoCalendarCollectionResource(
+                self._newStoreCalendarHome,
+                principalCollections=self.principalCollections()
+            )
+        else:
+            from twistedcaldav.storebridge import CalendarCollectionResource
+            similar = CalendarCollectionResource(
+                newCalendar, self._newStoreCalendarHome,
+                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(CalendarHomeResource, self).getChild(name)
+
+    def listChildren(self):
+        """
+        @return: a sequence of the names of all known children of this resource.
+        """
+        children = set(self.putChildren.keys())
+        children.update(self._newStoreCalendarHome.listCalendars())
+        return children
+
+    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(CalendarHomeResource, self).readProperty(property, request)
+
+    http_ACL = None     # ACL method not supported
+
+class AddressBookHomeResource (LinkFollowerMixIn, SharedHomeMixin, DirectoryAddressBookHomeResource, CalDAVResource):
+    """
+    Address book home collection resource.
+    """
+    
+    def __init__(self, parent, record, transaction):
+        """
+        """
+
+        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)
+        )
+        CalDAVResource.__init__(self)
+        DirectoryAddressBookHomeResource.__init__(self, parent, record)
+
+        from twistedcaldav.storebridge import _NewStorePropertiesWrapper
+        self._dead_properties = _NewStorePropertiesWrapper(
+            self._newStoreAddressBookHome.properties()
+        )
+
+
+    def liveProperties(self):
+        return super(AddressBookHomeResource, 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 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):
+ 
+        # For storebridge stuff we special case this
+        if name == "notification" and config.Sharing.Enabled and config.Sharing.AddressBooks.Enabled and not config.Sharing.Calendars.Enabled:
+            return self.createNotificationsCollection()
+
+        return self.getAddressBookCollection(name)
+
+    def createNotificationsCollection(self):
+        
+        txn = self._newStoreAddressBookHome._transaction
+        notifications = txn.notificationsWithUID(self._newStoreAddressBookHome.uid())
+
+        from twistedcaldav.storebridge import StoreNotificationCollectionResource
+        similar = StoreNotificationCollectionResource(
+            notifications,
+            self._newStoreAddressBookHome,
+            principalCollections = self.principalCollections(),
+        )
+        self.propagateTransaction(similar)
+        similar.clientNotifier = self.clientNotifier.clone(similar,
+            label="collection")
+        return similar
+
+    def getAddressBookCollection(self, name):
+
+        # Check for public/global path
+        from twistedcaldav.storebridge import (
+            AddressBookCollectionResource,
+            ProtoAddressBookCollectionResource,
+            GlobalAddressBookCollectionResource,
+            ProtoGlobalAddressBookCollectionResource,
+        )
+        mainCls = AddressBookCollectionResource
+        protoCls = ProtoAddressBookCollectionResource
+        if isinstance(self.record, InternalDirectoryRecord):
+            if "global" in self.record.shortNames:
+                mainCls = GlobalAddressBookCollectionResource
+                protoCls = ProtoGlobalAddressBookCollectionResource
+
+        newAddressBook = self._newStoreAddressBookHome.addressbookWithName(name)
+        if newAddressBook is None:
+            # Local imports.due to circular dependency between modules.
+            similar = protoCls(
+                self._newStoreAddressBookHome,
+                principalCollections=self.principalCollections()
+            )
+        else:
+            similar = mainCls(
+                newAddressBook, self._newStoreAddressBookHome,
+                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
+
+        result = super(AddressBookHomeResource, self).getChild(name)
+        if not result:
+            result = self.getAddressBookCollection(name)
+        return result
+
+    def listChildren(self):
+        """
+        @return: a sequence of the names of all known children of this resource.
+        """
+        children = set(self.putChildren.keys())
+        children.update(self._newStoreAddressBookHome.listAddressbooks())
+        return children
+
+    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(AddressBookHomeResource, self).readProperty(property, request)
+
+    http_ACL = None     # ACL method not supported
+
+class GlobalAddressBookResource (ReadOnlyResourceMixIn, CalDAVResource):
+    """
+    Global address book. All we care about is making sure permissions are setup.
+    """
+
+    def resourceType(self):
+        return davxml.ResourceType.sharedaddressbook
+
+    def defaultAccessControlList(self):
+
+        aces = (
+            davxml.ACE(
+                davxml.Principal(davxml.Authenticated()),
+                davxml.Grant(
+                    davxml.Privilege(davxml.Read()),
+                    davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
+                    davxml.Privilege(davxml.Write()),
+                ),
+                davxml.Protected(),
+                TwistedACLInheritable(),
+           ),
+        )
+        
+        if config.GlobalAddressBook.EnableAnonymousReadAccess:
+            aces += (
+                davxml.ACE(
+                    davxml.Principal(davxml.Unauthenticated()),
+                    davxml.Grant(
+                        davxml.Privilege(davxml.Read()),
+                    ),
+                    davxml.Protected(),
+                    TwistedACLInheritable(),
+               ),
+            )
+        return davxml.ACL(*aces)
+
+    def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
+        # Permissions here are fixed, and are not subject to inheritance rules, etc.
+        return succeed(self.defaultAccessControlList())
+
+
 class AuthenticationWrapper(SuperAuthenticationWrapper):
 
     """ AuthenticationWrapper implementation which allows overriding
@@ -1692,3 +2333,4 @@
         return False
     else:
         return resource.isAddressBookCollection()
+

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/schedule.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/schedule.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -25,7 +25,7 @@
     "IScheduleInboxResource",
 ]
 
-from twext.web2.dav.http import ErrorResponse
+from twext.web2.dav.http import ErrorResponse, MultiStatusResponse
 
 from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 from twext.web2 import responsecode
@@ -33,6 +33,7 @@
 from twext.web2.dav.element.extensions import SyncCollection
 from twext.web2.dav.element.rfc2518 import HRef
 from twext.web2.dav.noneprops import NonePropertyStore
+from twext.web2.dav.resource import davPrivilegeSet
 from twext.web2.dav.util import joinURL, normalizeURL
 from twext.web2.http import HTTPError
 from twext.web2.http import Response
@@ -43,15 +44,51 @@
     CalendarFreeBusySet, ScheduleCalendarTransp
 from twistedcaldav.config import config
 from twistedcaldav.customxml import calendarserver_namespace
-from twistedcaldav.extensions import DAVResource
-from twistedcaldav.resource import CalDAVResource, ReadOnlyNoCopyResourceMixIn,\
-    deliverSchedulePrivilegeSet
+from twistedcaldav.extensions import DAVResource, DAVResourceWithChildrenMixin
+from twistedcaldav.resource import CalDAVResource, ReadOnlyNoCopyResourceMixIn
 from twistedcaldav.resource import isCalendarCollectionResource
 from twistedcaldav.scheduling.scheduler import CalDAVScheduler, IScheduleScheduler
 
 from txdav.propertystore.base import PropertyName
 
-class CalendarSchedulingCollectionResource (CalDAVResource):
+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)
+
+class CalendarSchedulingCollectionResource (CalDAVResource, DAVResourceWithChildrenMixin):
     """
     CalDAV principal resource.
 
@@ -65,6 +102,7 @@
         assert parent is not None
 
         CalDAVResource.__init__(self, principalCollections=parent.principalCollections())
+        DAVResourceWithChildrenMixin.__init__(self)
 
         self.parent = parent
 
@@ -101,25 +139,9 @@
             (caldav_namespace, "schedule-default-calendar-URL"),
         )
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.scheduleInbox)
+    def resourceType(self):
+        return davxml.ResourceType.scheduleInbox
 
-    def defaultAccessControlList(self):
-        
-        privs = (
-            davxml.Privilege(caldavxml.ScheduleDeliver()),
-        )
-        if config.Scheduling.CalDAV.OldDraftCompatibility:
-            privs += (davxml.Privilege(caldavxml.Schedule()),)
-
-        return davxml.ACL(
-            # CalDAV:schedule-deliver for any authenticated user
-            davxml.ACE(
-                davxml.Principal(davxml.Authenticated()),
-                davxml.Grant(*privs),
-            ),
-        )
-
     @inlineCallbacks
     def readProperty(self, property, request):
         if type(property) is tuple:
@@ -259,6 +281,29 @@
             davxml.HRef(defaultCalendarURL))
         )
 
+    ##
+    # ACL
+    ##
+
+    def supportedPrivileges(self, request):
+        return succeed(deliverSchedulePrivilegeSet)
+
+    def defaultAccessControlList(self):
+        
+        privs = (
+            davxml.Privilege(caldavxml.ScheduleDeliver()),
+        )
+        if config.Scheduling.CalDAV.OldDraftCompatibility:
+            privs += (davxml.Privilege(caldavxml.Schedule()),)
+
+        return davxml.ACL(
+            # CalDAV:schedule-deliver for any authenticated user
+            davxml.ACE(
+                davxml.Principal(davxml.Authenticated()),
+                davxml.Grant(*privs),
+            ),
+        )
+
 class ScheduleOutboxResource (CalendarSchedulingCollectionResource):
     """
     CalDAV schedule Outbox resource.
@@ -266,6 +311,37 @@
     Extends L{DAVResource} to provide CalDAV functionality.
     """
 
+    def resourceType(self):
+        return davxml.ResourceType.scheduleOutbox
+
+    @inlineCallbacks
+    def http_POST(self, request):
+        """
+        The CalDAV POST method.
+    
+        This uses a generator function yielding either L{waitForDeferred} objects or L{Response} objects.
+        This allows for code that follows a 'linear' execution pattern rather than having to use nested
+        L{Deferred} callbacks. The logic is easier to follow this way plus we don't run into deep nesting
+        issues which the other approach would have with large numbers of recipients.
+        """
+        # Check authentication and access controls
+        yield self.authorize(request, (caldavxml.ScheduleSend(),))
+
+        # This is a local CALDAV scheduling operation.
+        scheduler = CalDAVScheduler(request, self)
+
+        # Do the POST processing treating
+        result = (yield scheduler.doSchedulingViaPOST())
+        returnValue(result.response())
+
+
+    ##
+    # ACL
+    ##
+
+    def supportedPrivileges(self, request):
+        return succeed(sendSchedulePrivilegeSet)
+
     def defaultAccessControlList(self):
         if config.EnableProxyPrincipals:
             myPrincipal = self.parent.principalForRecord()
@@ -287,29 +363,13 @@
         else:
             return super(ScheduleOutboxResource, self).defaultAccessControlList()
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.scheduleOutbox)
+    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)))
 
-    @inlineCallbacks
-    def http_POST(self, request):
-        """
-        The CalDAV POST method.
-    
-        This uses a generator function yielding either L{waitForDeferred} objects or L{Response} objects.
-        This allows for code that follows a 'linear' execution pattern rather than having to use nested
-        L{Deferred} callbacks. The logic is easier to follow this way plus we don't run into deep nesting
-        issues which the other approach would have with large numbers of recipients.
-        """
-        # Check authentication and access controls
-        yield self.authorize(request, (caldavxml.ScheduleSend(),))
-
-        # This is a local CALDAV scheduling operation.
-        scheduler = CalDAVScheduler(request, self)
-
-        # Do the POST processing treating
-        result = (yield scheduler.doSchedulingViaPOST())
-        returnValue(result.response())
-
 class IScheduleInboxResource (ReadOnlyNoCopyResourceMixIn, DAVResource):
     """
     iSchedule Inbox resource.
@@ -338,8 +398,8 @@
     def checkPreconditions(self, request):
         return None
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.ischeduleinbox)
+    def resourceType(self):
+        return davxml.ResourceType.ischeduleinbox
 
     def isCollection(self):
         return False

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/utils.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/utils.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/utils.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -14,7 +14,7 @@
 # limitations under the License.
 ##
 
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 from twistedcaldav.method import report_common
 from twext.web2.dav.util import joinURL
 
@@ -40,12 +40,10 @@
         request._rememberResource(calendar_home, calendar_home.url())
 
         # Run a UID query against the UID
-        @inlineCallbacks
         def queryCalendarCollection(collection, uri):
             if not allow_shared:
-                isvirt = (yield collection.isVirtualShare(request))
-                if isvirt:
-                    returnValue(True)
+                if collection.isVirtualShare():
+                    return succeed(True)
 
             rname = collection.index().resourceNameForUID(uid)
             if rname:
@@ -56,9 +54,9 @@
                 result["resource_name"] = rname
                 result["calendar_collection"] = collection
                 result["calendar_collection_uri"] = uri
-                returnValue(False)
+                return succeed(False)
             else:
-                returnValue(True)
+                return succeed(True)
         
         # NB We are by-passing privilege checking here. That should be OK as the data found is not
         # exposed to the user.

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharing.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharing.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -66,26 +66,23 @@
                 return None
         return self.isShared(request).addCallback(sharedOK)
 
-    @inlineCallbacks
-    def upgradeToShare(self, request):
+    def upgradeToShare(self):
         """ Upgrade this collection to a shared state """
         
         # Change resourcetype
-        rtype = (yield self.resourceType(request))
+        rtype = self.resourceType()
         rtype = davxml.ResourceType(*(rtype.children + (customxml.SharedOwner(),)))
         self.writeDeadProperty(rtype)
         
         # Create invites database
         self.invitesDB().create()
-
-        returnValue(True)
     
     @inlineCallbacks
     def downgradeFromShare(self, request):
         
         # Change resource type (note this might be called after deleting a resource
         # so we have to cope with that)
-        rtype = (yield self.resourceType(request))
+        rtype = self.resourceType()
         rtype = davxml.ResourceType(*([child for child in rtype.children if child != customxml.SharedOwner()]))
         self.writeDeadProperty(rtype)
         
@@ -212,9 +209,9 @@
         elif hasattr(self, "_newStoreAddressBook"):
             self._newStoreAddressBook.setSharingUID(self._shareePrincipal.principalUID())
 
-    def isVirtualShare(self, request):
+    def isVirtualShare(self):
         """ Return True if this is a shared calendar collection """
-        return succeed(hasattr(self, "_isVirtualShare"))
+        return hasattr(self, "_isVirtualShare")
 
     def removeVirtualShare(self, request):
         """ Return True if this is a shared calendar collection """
@@ -226,17 +223,16 @@
             shareeHome = self._shareePrincipal.addressBookHome(request)
         return shareeHome.removeShare(request, self._share)
 
-    @inlineCallbacks
-    def resourceType(self, request):
+    def resourceType(self):
         superObject = super(SharedCollectionMixin, self)
         try:
             superMethod = superObject.resourceType
         except AttributeError:
             rtype = davxml.ResourceType()
         else:
-            rtype = (yield superMethod(request))
+            rtype = superMethod()
 
-        isVirt = (yield self.isVirtualShare(request))
+        isVirt = self.isVirtualShare()
         if isVirt:
             rtype = davxml.ResourceType(
                 *(
@@ -244,7 +240,7 @@
                     (customxml.Shared(),)
                 )
             )
-        returnValue(rtype)
+        return rtype
         
     def sharedResourceType(self):
         """
@@ -635,10 +631,7 @@
 
             def _autoShare(isShared, request):
                 if not isShared:
-                    return self.upgradeToShare(request)
-                else:
-                    return succeed(True)
-                raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Cannot upgrade to shared calendar"))
+                    self.upgradeToShare()
 
             @inlineCallbacks
             def _processInviteDoc(_, request):

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/static.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/static.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+from twistedcaldav.index import Index
 
 """
 CalDAV-aware static resources.
@@ -22,85 +23,43 @@
 __all__ = [
     "CalDAVFile",
     "AutoProvisioningFileMixIn",
-    "CalendarHomeProvisioningFile",
-    "CalendarHomeUIDProvisioningFile",
-    "CalendarHomeFile",
-    "ScheduleFile",
-    "ScheduleInboxFile",
-    "ScheduleOutboxFile",
-    "DropBoxHomeFile",
-    "DropBoxCollectionFile",
-    "DropBoxChildFile",
-    "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.http import ErrorResponse
 from twext.web2.dav.idav import IDAVResource
-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.dav.util import parentForURL, bindMethods
 
 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.linkresource import LinkFollowerMixIn
 
-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
 from twistedcaldav.datafilters.privateevents import PrivateEventFilter
 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.vcardindex import AddressBookIndex
-from twistedcaldav.notify import getPubSubConfiguration, getPubSubXMPPURI
-from twistedcaldav.notify import getPubSubHeartbeatURI, getPubSubPath
-from twistedcaldav.notify import ClientNotifier, getNodeCacher
 
 log = Logger()
 
@@ -290,7 +249,7 @@
 
 # FIXME: move cache implementation!
             # Determine the cache key
-#            isvirt = (yield self.isVirtualShare(request))
+#            isvirt = self.isVirtualShare()
 #            if isvirt:
 #                principal = (yield self.resourceOwnerPrincipal(request))
 #                if principal:
@@ -549,111 +508,6 @@
         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()
@@ -830,889 +684,6 @@
             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)
-
-
-
-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_KEY = '_newStoreTransaction'
-        transaction = getattr(request, TRANSACTION_KEY, None)
-        if transaction is None:
-            transaction = self.parent._newStore.newTransaction(repr(request))
-            setattr(request, TRANSACTION_KEY, transaction)
-
-        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:
-            FreeBusyURLResourceClass = FreeBusyURLResource
-        else:
-            FreeBusyURLResourceClass = None
-            
-        # For storebridge stuff we special case this
-        if name == "notification" and config.Sharing.Enabled and config.Sharing.Calendars.Enabled:
-            return self.createNotificationsFile(self.fp.child(name).path)
-
-        cls, isFileType = {
-            "inbox"        : (StoreScheduleInboxFile, True,),
-            "outbox"       : (ScheduleOutboxFile, True,),
-            "dropbox"      : (DropBoxHomeFileClass, True,),
-            "freebusy"     : (FreeBusyURLResourceClass, False,),
-        }.get(name, (None, True,))
-
-        if cls is not None:
-            if isFileType:
-                child = cls(self.fp.child(name).path, self)
-            else:
-                child = cls(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 NotificationCollectionFile
-        similar = NotificationCollectionFile(
-            notifications,
-            self._newStoreCalendarHome,
-            principalCollections = self.principalCollections(),
-        )
-        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 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_KEY = '_newStoreTransaction'
-        transaction = getattr(request, TRANSACTION_KEY, None)
-        if transaction is None:
-            transaction = self.parent._newStore.newTransaction(repr(request))
-            setattr(request, TRANSACTION_KEY, transaction)
-
-        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):
- 
-        # For storebridge stuff we special case this
-        if name == "notification" and config.Sharing.Enabled and config.Sharing.AddressBooks.Enabled and not config.Sharing.Calendars.Enabled:
-            return self.createNotificationsFile(self.fp.child(name).path)
-
-        return self.createSimilarFile(self.fp.child(name).path)
-
-    def createNotificationsFile(self, path):
-        
-        txn = self._newStoreAddressBookHome._transaction
-        notifications = txn.notificationsWithUID(self._newStoreAddressBookHome.uid())
-
-        from twistedcaldav.storebridge import NotificationCollectionFile
-        similar = NotificationCollectionFile(
-            notifications,
-            self._newStoreAddressBookHome,
-            principalCollections = self.principalCollections(),
-        )
-        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)
-
-            # 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.
@@ -1756,23 +727,6 @@
             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
 ##
@@ -1790,43 +744,6 @@
     # 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
 
@@ -1874,10 +791,6 @@
 
 bindMethods(twistedcaldav.method, CalDAVFile)
 
-# Some resources do not support some methods
-setattr(CalendarHomeFile, "http_ACL", None)
-setattr(AddressBookHomeFile, "http_ACL", None)
-
 # FIXME: Little bit of a circular dependency here...
 twistedcaldav.method.acl.CalDAVFile      = CalDAVFile
 twistedcaldav.method.copymove.CalDAVFile = CalDAVFile

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/storebridge.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/storebridge.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -14,6 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+from twistedcaldav.schedule import ScheduleInboxResource
+from twistedcaldav.extensions import DAVResourceWithChildrenMixin
 
 """
 Wrappers to translate between the APIs in L{txcaldav.icalendarstore} and
@@ -45,17 +47,15 @@
 from twext.web2.http import HTTPError, StatusResponse, Response
 from twext.web2.stream import ProducerStream, readStream, MemoryStream
 
-from twistedcaldav.static import CalDAVFile, ScheduleInboxFile, \
-    GlobalAddressBookFile
+from twistedcaldav.static import CalDAVFile
 from twistedcaldav.vcard import Component as VCard
-from twistedcaldav.resource import CalDAVResource
+from twistedcaldav.resource import CalDAVResource, GlobalAddressBookResource
 
 from txdav.common.icommondatastore import NoSuchObjectResourceError, \
     InternalDataStoreError
 from txdav.propertystore.base import PropertyName
 
 from twistedcaldav.caldavxml import ScheduleTag, caldav_namespace
-from twistedcaldav.method.propfind import http_PROPFIND
 from twistedcaldav.notifications import NotificationCollectionResource,\
     NotificationResource
 from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
@@ -205,32 +205,28 @@
     @classmethod
     def transform(cls, self, calendar, home):
         """
-        Transform C{self} into a L{CalendarCollectionFile}.
+        Transform C{self} into a L{CalendarCollectionResource}.
         """
         self.__class__ = cls
         self._initializeWithCalendar(calendar, home)
 
 
-    def createSimilarFile(self, path):
+    def makeChild(self, name):
         """
         Create a L{CalendarObjectFile} or L{ProtoCalendarObjectFile} based on a
         path object.
         """
-        if not isinstance(path, FilePath):
-            path = FilePath(path)
 
-        newStoreObject = self._newStoreCalendar.calendarObjectWithName(
-            path.basename()
-        )
+        newStoreObject = self._newStoreCalendar.calendarObjectWithName(name)
 
         if newStoreObject is not None:
-            similar = CalendarObjectFile(newStoreObject, path,
+            similar = CalendarObjectFile(newStoreObject, newStoreObject._path,
                 principalCollections=self._principalCollections)
         else:
             # FIXME: creation in http_PUT should talk to a specific resource
             # type; this is the domain of StoreCalendarObjectResource.
             # similar = ProtoCalendarObjectFile(self._newStoreCalendar, path)
-            similar = ProtoCalendarObjectFile(self._newStoreCalendar, path,
+            similar = ProtoCalendarObjectFile(self._newStoreCalendar, self._newStoreCalendar._path.child(name),
                 principalCollections=self._principalCollections)
 
         # FIXME: tests should be failing without this line.
@@ -238,17 +234,25 @@
         self.propagateTransaction(similar)
         return similar
 
+    def listChildren(self):
+        """
+        @return: a sequence of the names of all known children of this resource.
+        """
+        children = set(self.putChildren.keys())
+        children.update(self._newStoreCalendar.listCalendarObjects())
+        return children
 
+
     def quotaSize(self, request):
         # FIXME: tests, workingness
         return succeed(0)
 
 
 
-class StoreScheduleInboxFile(_CalendarChildHelper, ScheduleInboxFile):
+class StoreScheduleInboxResource(_CalendarChildHelper, ScheduleInboxResource):
 
     def __init__(self, *a, **kw):
-        super(StoreScheduleInboxFile, self).__init__(*a, **kw)
+        super(StoreScheduleInboxResource, self).__init__(*a, **kw)
         self.parent.propagateTransaction(self)
         home = self.parent._newStoreCalendarHome
         storage = home.calendarWithName("inbox")
@@ -265,10 +269,6 @@
         )
 
 
-    def isCollection(self):
-        return True
-
-
     def provisionFile(self):
         pass
 
@@ -297,7 +297,7 @@
             qname = property.qname()
 
         if qname == (dav_namespace, "resourcetype"):
-            return self.resourceType(request)
+            return succeed(self.resourceType())
         return super(_GetChildHelper, self).readProperty(property, request)
 
 
@@ -310,10 +310,7 @@
         return super(_GetChildHelper, self).http_GET(request)
 
 
-    http_PROPFIND = http_PROPFIND
 
-
-
 class DropboxCollection(_GetChildHelper):
     """
     A collection of all dropboxes (containers for attachments), presented as a
@@ -322,9 +319,7 @@
     """
     # FIXME: no direct tests for this class at all.
 
-    def __init__(self, path, parent, *a, **kw):
-        # FIXME: constructor signature takes a 'path' because CalendarHomeFile
-        # requires it, but we don't need it (and shouldn't have it) eventually.
+    def __init__(self, parent, *a, **kw):
         super(DropboxCollection, self).__init__(
             *a, principalCollections=parent.principalCollections(), **kw)
         self._newStoreCalendarHome = parent._newStoreCalendarHome
@@ -349,8 +344,8 @@
         return objectDropbox
 
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.dropboxhome)
+    def resourceType(self,):
+        return davxml.ResourceType.dropboxhome
 
 
     def listChildren(self):
@@ -396,8 +391,8 @@
         return True
 
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.dropbox)
+    def resourceType(self):
+        return davxml.ResourceType.dropbox
 
 
     def getChild(self, name):
@@ -608,17 +603,18 @@
 
 
 
-class CalendarCollectionFile(_CalendarChildHelper, CalDAVFile):
+class CalendarCollectionResource(_CalendarChildHelper, CalDAVResource, DAVResourceWithChildrenMixin):
     """
     Wrapper around a L{txcaldav.icalendar.ICalendar}.
     """
 
     def __init__(self, calendar, home, *args, **kw):
         """
-        Create a CalendarCollectionFile from a L{txcaldav.icalendar.ICalendar}
-        and the arguments required for L{CalDAVFile}.
+        Create a CalendarCollectionResource from a L{txcaldav.icalendar.ICalendar}
+        and the arguments required for L{CalDAVResource}.
         """
-        super(CalendarCollectionFile, self).__init__(*args, **kw)
+        super(CalendarCollectionResource, self).__init__(*args, **kw)
+        DAVResourceWithChildrenMixin.__init__(self)
         self._initializeWithCalendar(calendar, home)
 
 
@@ -690,7 +686,7 @@
 
         # Is this a sharee's view of a shared calendar?  If so, they can't do
         # scheduling onto it, so just delete it and move on.
-        isVirtual = yield self.isVirtualShare(request)
+        isVirtual =self.isVirtualShare()
         if isVirtual:
             log.debug("Removing shared calendar %s" % (self,))
             yield self.removeVirtualShare(request)
@@ -729,7 +725,7 @@
         self._newStoreParentHome.removeCalendarWithName(
             self._newStoreCalendar.name()
         )
-        self.__class__ = ProtoCalendarCollectionFile
+        self.__class__ = ProtoCalendarCollectionResource
         del self._newStoreCalendar
 
         # FIXME: handle exceptions, possibly like this:
@@ -773,17 +769,17 @@
         basename = destination.fp.basename()
         calendar = self._newStoreCalendar
         calendar.rename(basename)
-        CalendarCollectionFile.transform(destination, calendar,
+        CalendarCollectionResource.transform(destination, calendar,
                                          self._newStoreParentHome)
         del self._newStoreCalendar
-        self.__class__ = ProtoCalendarCollectionFile
+        self.__class__ = ProtoCalendarCollectionResource
         self.movedCalendar(request, defaultCalendar,
                            destination, destinationURI)
         returnValue(NO_CONTENT)
 
 
 
-class NoParent(CalDAVFile):
+class NoParent(CalDAVResource):
     def http_MKCALENDAR(self, request):
         return CONFLICT
 
@@ -793,7 +789,7 @@
 
 
 
-class ProtoCalendarCollectionFile(CalDAVFile):
+class ProtoCalendarCollectionResource(CalDAVResource):
     """
     A resource representing a calendar collection which hasn't yet been created.
     """
@@ -801,7 +797,7 @@
     def __init__(self, home, *args, **kw):
         """
         A placeholder resource for a calendar collection which does not yet
-        exist, but will become a L{CalendarCollectionFile}.
+        exist, but will become a L{CalendarCollectionResource}.
 
         @param home: The calendar home which will be this resource's parent,
             when it exists.
@@ -809,18 +805,18 @@
         @type home: L{txcaldav.icalendarstore.ICalendarHome}
         """
         self._newStoreParentHome = home
-        super(ProtoCalendarCollectionFile, self).__init__(*args, **kw)
+        super(ProtoCalendarCollectionResource, self).__init__(*args, **kw)
 
 
     def isCollection(self):
         return True
 
-    def createSimilarFile(self, path):
+    def makeChild(self, name):
         # FIXME: this is necessary for 
         # twistedcaldav.test.test_mkcalendar.
         #     MKCALENDAR.test_make_calendar_no_parent - there should be a more
         # structured way to refuse creation with a non-existent parent.
-        return NoParent(path)
+        return NoParent()
 
 
     def provisionFile(self):
@@ -842,7 +838,7 @@
         newStoreCalendar = self._newStoreParentHome.calendarWithName(
             calendarName
         )
-        CalendarCollectionFile.transform(
+        CalendarCollectionResource.transform(
             self, newStoreCalendar, self._newStoreParentHome
         )
         return d
@@ -1008,7 +1004,7 @@
         required.
 
         @param request: Unused by this implementation; present for signature
-            compatibility with L{CalendarCollectionFile.storeRemove}.
+            compatibility with L{CalendarCollectionResource.storeRemove}.
 
         @type request: L{twext.web2.iweb.IRequest}
 
@@ -1194,32 +1190,27 @@
     @classmethod
     def transform(cls, self, addressbook, home):
         """
-        Transform C{self} into a L{AddressBookCollectionFile}.
+        Transform C{self} into a L{AddressBookCollectionResource}.
         """
         self.__class__ = cls
         self._initializeWithAddressBook(addressbook, home)
 
 
-    def createSimilarFile(self, path):
+    def makeChild(self, name):
         """
         Create a L{AddressBookObjectFile} or L{ProtoAddressBookObjectFile} based on a
         path object.
         """
-        if not isinstance(path, FilePath):
-            path = FilePath(path)
+        newStoreObject = self._newStoreAddressBook.addressbookObjectWithName(name)
 
-        newStoreObject = self._newStoreAddressBook.addressbookObjectWithName(
-            path.basename()
-        )
-
         if newStoreObject is not None:
-            similar = AddressBookObjectFile(newStoreObject, path,
+            similar = AddressBookObjectFile(newStoreObject, newStoreObject._path,
                 principalCollections=self._principalCollections)
         else:
             # FIXME: creation in http_PUT should talk to a specific resource
             # type; this is the domain of StoreAddressBookObjectResource.
             # similar = ProtoAddressBookObjectFile(self._newStoreAddressBook, path)
-            similar = ProtoAddressBookObjectFile(self._newStoreAddressBook, path,
+            similar = ProtoAddressBookObjectFile(self._newStoreAddressBook, self._newStoreAddressBook._path.child(name),
                 principalCollections=self._principalCollections)
 
         # FIXME: tests should be failing without this line.
@@ -1227,24 +1218,34 @@
         self.propagateTransaction(similar)
         return similar
 
+    def listChildren(self):
+        """
+        @return: a sequence of the names of all known children of this resource.
+        """
+        children = set(self.putChildren.keys())
+        children.update(self._newStoreAddressBook.listAddressbookObjects())
+        return children
 
+
+
     def quotaSize(self, request):
         # FIXME: tests, workingness
         return succeed(0)
 
 
 
-class AddressBookCollectionFile(_AddressBookChildHelper, CalDAVFile):
+class AddressBookCollectionResource(_AddressBookChildHelper, CalDAVResource, DAVResourceWithChildrenMixin):
     """
     Wrapper around a L{txcarddav.iaddressbook.IAddressBook}.
     """
 
     def __init__(self, addressbook, home, *args, **kw):
         """
-        Create a AddressBookCollectionFile from a L{txcarddav.iaddressbook.IAddressBook}
-        and the arguments required for L{CalDAVFile}.
+        Create a AddressBookCollectionResource from a L{txcarddav.iaddressbook.IAddressBook}
+        and the arguments required for L{CalDAVResource}.
         """
-        super(AddressBookCollectionFile, self).__init__(*args, **kw)
+        super(AddressBookCollectionResource, self).__init__(*args, **kw)
+        DAVResourceWithChildrenMixin.__init__(self)
         self._initializeWithAddressBook(addressbook, home)
 
 
@@ -1301,7 +1302,7 @@
         """
 
         # Check virtual share first
-        isVirtual = yield self.isVirtualShare(request)
+        isVirtual = self.isVirtualShare()
         if isVirtual:
             log.debug("Removing shared calendar %s" % (self,))
             yield self.removeVirtualShare(request)
@@ -1340,7 +1341,7 @@
         self._newStoreParentHome.removeAddressBookWithName(
             self._newStoreAddressBook.name()
         )
-        self.__class__ = ProtoAddressBookCollectionFile
+        self.__class__ = ProtoAddressBookCollectionResource
         del self._newStoreAddressBook
 
         # FIXME: handle exceptions, possibly like this:
@@ -1379,15 +1380,15 @@
         basename = destination.fp.basename()
         addressbook = self._newStoreAddressBook
         addressbook.rename(basename)
-        AddressBookCollectionFile.transform(destination, addressbook,
+        AddressBookCollectionResource.transform(destination, addressbook,
                                          self._newStoreParentHome)
         del self._newStoreAddressBook
-        self.__class__ = ProtoAddressBookCollectionFile
+        self.__class__ = ProtoAddressBookCollectionResource
         returnValue(NO_CONTENT)
 
 
 
-class ProtoAddressBookCollectionFile(CalDAVFile):
+class ProtoAddressBookCollectionResource(CalDAVResource):
     """
     A resource representing an addressbook collection which hasn't yet been created.
     """
@@ -1395,7 +1396,7 @@
     def __init__(self, home, *args, **kw):
         """
         A placeholder resource for an addressbook collection which does not yet
-        exist, but will become a L{AddressBookCollectionFile}.
+        exist, but will become a L{AddressBookCollectionResource}.
 
         @param home: The addressbook home which will be this resource's parent,
             when it exists.
@@ -1403,19 +1404,19 @@
         @type home: L{txcarddav.iaddressbookstore.IAddressBookHome}
         """
         self._newStoreParentHome = home
-        super(ProtoAddressBookCollectionFile, self).__init__(*args, **kw)
+        super(ProtoAddressBookCollectionResource, self).__init__(*args, **kw)
 
 
     def isCollection(self):
         return True
 
 
-    def createSimilarFile(self, path):
+    def makeChild(self, name):
         # FIXME: this is necessary for 
         # twistedcaldav.test.test_mkcol.
         #     MKCOL.test_make_addressbook_no_parent - there should be a more
         # structured way to refuse creation with a non-existent parent.
-        return NoParent(path)
+        return NoParent()
 
 
     def provisionFile(self):
@@ -1438,7 +1439,7 @@
         newStoreAddressBook = self._newStoreParentHome.addressbookWithName(
             Name
         )
-        AddressBookCollectionFile.transform(
+        AddressBookCollectionResource.transform(
             self, newStoreAddressBook, self._newStoreParentHome
         )
         return d
@@ -1461,104 +1462,19 @@
         return succeed(0)
 
 
-class GlobalAddressBookCollectionFile(_AddressBookChildHelper, GlobalAddressBookFile):
+class GlobalAddressBookCollectionResource(GlobalAddressBookResource, AddressBookCollectionResource):
     """
     Wrapper around a L{txcarddav.iaddressbook.IAddressBook}.
     """
+    pass
 
-    def __init__(self, addressbook, home, *args, **kw):
-        """
-        Create a GlobalAddressBookCollectionFile from a L{txcarddav.iaddressbook.IAddressBook}
-        and the arguments required for L{CalDAVFile}.
-        """
-        super(GlobalAddressBookCollectionFile, self).__init__(*args, **kw)
-        self._initializeWithAddressBook(addressbook, home)
-
-
-    def isCollection(self):
-        return True
-
-    def isAddressBookCollection(self):
-        """
-        Yes, it is a calendar collection.
-        """
-        return True
-
-class ProtoGlobalAddressBookCollectionFile(GlobalAddressBookFile):
+class ProtoGlobalAddressBookCollectionResource(GlobalAddressBookResource, ProtoAddressBookCollectionResource):
     """
     A resource representing an addressbook collection which hasn't yet been created.
     """
+    pass
 
-    def __init__(self, home, *args, **kw):
-        """
-        A placeholder resource for an addressbook collection which does not yet
-        exist, but will become a L{GlobalAddressBookCollectionFile}.
 
-        @param home: The addressbook home which will be this resource's parent,
-            when it exists.
-
-        @type home: L{txcarddav.iaddressbookstore.IAddressBookHome}
-        """
-        self._newStoreParentHome = home
-        super(ProtoGlobalAddressBookCollectionFile, self).__init__(*args, **kw)
-
-
-    def isCollection(self):
-        return True
-
-
-    def createSimilarFile(self, path):
-        # FIXME: this is necessary for 
-        # twistedcaldav.test.test_mkcol.
-        #     MKCOL.test_make_addressbook_no_parent - there should be a more
-        # structured way to refuse creation with a non-existent parent.
-        return NoParent(path)
-
-
-    def provisionFile(self):
-        """
-        Create an addressbook collection.
-        """
-        # FIXME: this should be done in the backend; provisionDefaultAddressBooks
-        # should go away.
-        return self.createAddressBookCollection()
-
-
-    def createAddressBookCollection(self):
-        """
-        Override C{createAddressBookCollection} to actually do the work.
-        """
-        d = succeed(CREATED)
-
-        Name = self.fp.basename()
-        self._newStoreParentHome.createAddressBookWithName(Name)
-        newStoreAddressBook = self._newStoreParentHome.addressbookWithName(
-            Name
-        )
-        GlobalAddressBookCollectionFile.transform(
-            self, newStoreAddressBook, self._newStoreParentHome
-        )
-        return d
-
-
-    def exists(self):
-        # FIXME: tests
-        return False
-
-
-    def provision(self):
-        """
-        This resource should do nothing if it's provisioned.
-        """
-        # FIXME: should be deleted, or raise an exception
-
-
-    def quotaSize(self, request):
-        # FIXME: tests, workingness
-        return succeed(0)
-
-
-
 class AddressBookObjectFile(CalDAVFile, FancyEqMixin):
     """
     A resource wrapping a addressbook object.
@@ -1785,9 +1701,6 @@
         return self.getChild(segments[0]), segments[1:]
 
 
-    def getChild(self, name):
-        return None
-
     def notificationsDB(self):
         """
         Retrieve the new-style index wrapper.
@@ -1809,18 +1722,13 @@
         self._initializeWithNotifications(notifications, home)
 
 
-    def createSimilarFile(self, path):
+    def makeChild(self, name):
         """
         Create a L{NotificationObjectFile} or L{ProtoNotificationObjectFile} based on a
         path object.
         """
-        if not isinstance(path, FilePath):
-            path = FilePath(path)
+        newStoreObject = self._newStoreNotifications.notificationObjectWithName(name)
 
-        newStoreObject = self._newStoreNotifications.notificationObjectWithName(
-            path.basename()
-        )
-
         if newStoreObject is not None:
             similar = StoreNotificationObjectFile(newStoreObject, self)
         else:
@@ -1834,14 +1742,23 @@
         self.propagateTransaction(similar)
         return similar
 
+    def listChildren(self):
+        """
+        @return: a sequence of the names of all known children of this resource.
+        """
+        children = set(self.putChildren.keys())
+        children.update(self._newStoreNotifications.listNotificationObjects())
+        return children
 
+
+
     def quotaSize(self, request):
         # FIXME: tests, workingness
         return succeed(0)
 
 
 
-class NotificationCollectionFile(_NotificationChildHelper,
+class StoreNotificationCollectionResource(_NotificationChildHelper,
                                       NotificationCollectionResource):
     """
     Wrapper around a L{txcaldav.icalendar.ICalendar}.
@@ -1849,25 +1766,13 @@
 
     def __init__(self, notifications, home, *args, **kw):
         """
-        Create a CalendarCollectionFile from a L{txcaldav.icalendar.ICalendar}
-        and the arguments required for L{CalDAVFile}.
+        Create a CalendarCollectionResource from a L{txcaldav.icalendar.ICalendar}
+        and the arguments required for L{CalDAVResource}.
         """
-        super(NotificationCollectionFile, self).__init__(*args, **kw)
+        super(StoreNotificationCollectionResource, self).__init__(*args, **kw)
         self._initializeWithNotifications(notifications, home)
 
 
-    def getChild(self, name):
-        notificationObject = self._newStoreNotifications.notificationObjectWithName(name)
-        if notificationObject is None:
-            return None
-        notification = StoreNotificationObjectFile(
-            notificationObject,
-            self,
-        )
-        self.propagateTransaction(notification)
-        return notification
-
-
     def listChildren(self):
         l = []
         for notification in self._newStoreNotifications.notificationObjects():
@@ -1886,7 +1791,7 @@
         self._newStoreNotifications.removeNotificationObjectWithName(record.name)
         return succeed(None)
         
-class ProtoNotificationCollectionFile(NotificationCollectionResource):
+class StoreProtoNotificationCollectionResource(NotificationCollectionResource):
     """
     A resource representing a notification collection which hasn't yet been created.
     """
@@ -1894,7 +1799,7 @@
     def __init__(self, home, *args, **kw):
         """
         A placeholder resource for a notification collection which does not yet
-        exist, but will become a L{NotificationCollectionFile}.
+        exist, but will become a L{StoreNotificationCollectionResource}.
 
         @param home: The calendar home which will be this resource's parent,
             when it exists.
@@ -1902,18 +1807,18 @@
         @type home: L{txcaldav.icalendarstore.ICalendarHome}
         """
         self._newStoreParentHome = home
-        super(ProtoNotificationCollectionFile, self).__init__(*args, **kw)
+        super(StoreProtoNotificationCollectionResource, self).__init__(*args, **kw)
 
 
     def isCollection(self):
         return True
 
-    def createSimilarFile(self, path):
+    def makeChild(self, name):
         # FIXME: this is necessary for 
         # twistedcaldav.test.test_mkcalendar.
         #     MKCALENDAR.test_make_calendar_no_parent - there should be a more
         # structured way to refuse creation with a non-existent parent.
-        return NoParent(path)
+        return NoParent()
 
 
     def provisionFile(self):
@@ -1935,7 +1840,7 @@
         newStoreNotification = self._newStoreParentHome.childWithName(
             notificationName
         )
-        NotificationCollectionFile.transform(
+        StoreNotificationCollectionResource.transform(
             self, newStoreNotification, self._newStoreParentHome
         )
         return d

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_schedule.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_schedule.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_schedule.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -14,8 +14,6 @@
 # limitations under the License.
 ##
 
-import os
-
 from twext.web2 import responsecode
 from twext.web2.iweb import IResponse
 from twext.web2.dav import davxml
@@ -24,7 +22,6 @@
 from twext.web2.test.test_server import SimpleRequest
 
 from twistedcaldav import caldavxml
-from twistedcaldav.static import ScheduleInboxFile
 
 from twistedcaldav.test.util import HomeTestCase
 
@@ -38,8 +35,6 @@
         """
 
         inbox_uri  = "/inbox/"
-        #inbox_path = os.path.join(self.docroot, "inbox")
-        #self.site.resource.putChild("inbox", ScheduleInboxFile(inbox_path, self.site.resource))
 
         def propfind_cb(response):
             response = IResponse(response)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_sharing.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_sharing.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -103,42 +103,42 @@
     def test_upgradeToShareOnCreate(self):
         request = SimpleRequest(self.site, "MKCOL", "/calendar/")
 
-        rtype = (yield self.resource.resourceType(request))
+        rtype = self.resource.resourceType()
         self.assertEquals(rtype, davxml.ResourceType.calendar)
         propInvite = (yield self.resource.readProperty(customxml.Invite, request))
         self.assertEquals(propInvite, None)
 
-        yield self.resource.upgradeToShare(request)
+        self.resource.upgradeToShare()
 
-        rtype = (yield self.resource.resourceType(request))
+        rtype = self.resource.resourceType()
         self.assertEquals(rtype, davxml.ResourceType.sharedownercalendar)
         propInvite = (yield self.resource.readProperty(customxml.Invite, request))
         self.assertEquals(propInvite, customxml.Invite())
         
         isShared = (yield self.resource.isShared(request))
         self.assertTrue(isShared)
-        isVShared = (yield self.resource.isVirtualShare(request))
+        isVShared = self.resource.isVirtualShare()
         self.assertFalse(isVShared)
 
     @inlineCallbacks
     def test_upgradeToShareAfterCreate(self):
         request = SimpleRequest(self.site, "PROPPATCH", "/calendar/")
 
-        rtype = (yield self.resource.resourceType(request))
+        rtype = self.resource.resourceType()
         self.assertEquals(rtype, davxml.ResourceType.calendar)
         propInvite = (yield self.resource.readProperty(customxml.Invite, request))
         self.assertEquals(propInvite, None)
 
-        yield self.resource.upgradeToShare(request)
+        self.resource.upgradeToShare()
 
-        rtype = (yield self.resource.resourceType(request))
+        rtype = self.resource.resourceType()
         self.assertEquals(rtype, davxml.ResourceType.sharedownercalendar)
         propInvite = (yield self.resource.readProperty(customxml.Invite, request))
         self.assertEquals(propInvite, customxml.Invite())
         
         isShared = (yield self.resource.isShared(request))
         self.assertTrue(isShared)
-        isVShared = (yield self.resource.isVirtualShare(request))
+        isVShared = self.resource.isVirtualShare()
         self.assertFalse(isVShared)
 
     @inlineCallbacks
@@ -147,27 +147,27 @@
 
         self.resource.writeDeadProperty(davxml.ResourceType.sharedownercalendar)
         self.resource.writeDeadProperty(customxml.Invite())
-        rtype = (yield self.resource.resourceType(request))
+        rtype = self.resource.resourceType()
         self.assertEquals(rtype, davxml.ResourceType.sharedownercalendar)
         propInvite = (yield self.resource.readProperty(customxml.Invite, None))
         self.assertEquals(propInvite, customxml.Invite())
 
         yield self.resource.downgradeFromShare(None)
 
-        rtype = (yield self.resource.resourceType(request))
+        rtype = self.resource.resourceType()
         self.assertEquals(rtype, davxml.ResourceType.calendar)
         propInvite = (yield self.resource.readProperty(customxml.Invite, None))
         self.assertEquals(propInvite, None)
         
         isShared = (yield self.resource.isShared(None))
         self.assertFalse(isShared)
-        isVShared = (yield self.resource.isVirtualShare(None))
+        isVShared = self.resource.isVirtualShare()
         self.assertFalse(isVShared)
 
     @inlineCallbacks
     def test_POSTaddInviteeAlreadyShared(self):
         
-        yield self.resource.upgradeToShare(SimpleRequest(self.site, "MKCOL", "/calendar/"))
+        self.resource.upgradeToShare()
 
         yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
 <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
@@ -192,7 +192,7 @@
         
         isShared = (yield self.resource.isShared(None))
         self.assertTrue(isShared)
-        isVShared = (yield self.resource.isVirtualShare(None))
+        isVShared = self.resource.isVirtualShare()
         self.assertFalse(isVShared)
 
     @inlineCallbacks
@@ -228,7 +228,7 @@
     @inlineCallbacks
     def test_POSTupdateInvitee(self):
         
-        yield self.resource.upgradeToShare(SimpleRequest(self.site, "MKCOL", "/calendar/"))
+        self.resource.upgradeToShare()
 
         yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
 <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
@@ -264,7 +264,7 @@
     @inlineCallbacks
     def test_POSTremoveInvitee(self):
         
-        yield self.resource.upgradeToShare(SimpleRequest(self.site, "MKCOL", "/calendar/"))
+        self.resource.upgradeToShare()
 
         yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
 <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
@@ -290,7 +290,7 @@
     @inlineCallbacks
     def test_POSTaddMoreInvitees(self):
         
-        yield self.resource.upgradeToShare(SimpleRequest(self.site, "MKCOL", "/calendar/"))
+        self.resource.upgradeToShare()
 
         yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
 <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
@@ -344,7 +344,7 @@
     @inlineCallbacks
     def test_POSTaddRemoveInvitees(self):
         
-        yield self.resource.upgradeToShare(SimpleRequest(self.site, "MKCOL", "/calendar/"))
+        self.resource.upgradeToShare()
 
         yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
 <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
@@ -394,7 +394,7 @@
     @inlineCallbacks
     def test_POSTaddRemoveSameInvitee(self):
         
-        yield self.resource.upgradeToShare(SimpleRequest(self.site, "MKCOL", "/calendar/"))
+        self.resource.upgradeToShare()
 
         yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
 <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
@@ -444,7 +444,7 @@
     @inlineCallbacks
     def test_POSTaddInvalidInvitee(self):
         
-        yield self.resource.upgradeToShare(SimpleRequest(self.site, "MKCOL", "/calendar/"))
+        self.resource.upgradeToShare()
 
         response = (yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
 <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
@@ -475,7 +475,7 @@
     @inlineCallbacks
     def test_POSTremoveInvalidInvitee(self):
         
-        yield self.resource.upgradeToShare(SimpleRequest(self.site, "MKCOL", "/calendar/"))
+        self.resource.upgradeToShare()
 
         yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
 <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_wrapping.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_wrapping.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/test_wrapping.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -27,8 +27,8 @@
 from twistedcaldav.ical import Component as VComponent
 from twistedcaldav.vcard import Component as VCComponent
 
-from twistedcaldav.storebridge import ProtoCalendarCollectionFile, \
-    ProtoAddressBookCollectionFile, DropboxCollection
+from twistedcaldav.storebridge import ProtoCalendarCollectionResource, \
+    ProtoAddressBookCollectionResource, DropboxCollection
 
 from twistedcaldav.test.util import TestCase
 
@@ -137,7 +137,7 @@
 
     def test_createStore(self):
         """
-        Creating a CalendarHomeProvisioningFile will create a paired
+        Creating a DirectoryCalendarHomeProvisioningResource will create a paired
         CalendarStore.
         """
         self.assertIsInstance(self.calendarCollection._newStore, CalendarStore)
@@ -149,7 +149,7 @@
     def test_lookupCalendarHome(self):
         """
         When a L{CalDAVFile} representing an existing calendar home is looked
-        up in a CalendarHomeFile, it will create a corresponding
+        up in a CalendarHomeResource, it will create a corresponding
         L{CalendarHome} via C{newTransaction().calendarHomeWithUID}.
         """
         calDavFile = yield self.getResource("calendars/users/wsanchez/")
@@ -171,7 +171,7 @@
         )
         self.commit()
         self.assertIsInstance(dropBoxResource, DropboxCollection)
-        self.assertEquals((yield dropBoxResource.resourceType(None)),
+        self.assertEquals(dropBoxResource.resourceType(),
                           davxml.ResourceType.dropboxhome)
 
 
@@ -179,14 +179,14 @@
     def test_lookupExistingCalendar(self):
         """
         When a L{CalDAVFile} representing an existing calendar collection is
-        looked up in a L{CalendarHomeFile} representing a calendar home, it
+        looked up in a L{CalendarHomeResource} representing a calendar home, it
         will create a corresponding L{Calendar} via
         C{CalendarHome.calendarWithName}.
         """
         calDavFile = yield self.getResource("calendars/users/wsanchez/calendar")
         self.commit()
         self.assertEquals(calDavFile.fp, calDavFile._newStoreCalendar._path)
-        self.assertEquals((yield calDavFile.resourceType(None)),
+        self.assertEquals(calDavFile.resourceType(),
                           davxml.ResourceType.calendar)
 
 
@@ -194,13 +194,13 @@
     def test_lookupNewCalendar(self):
         """
         When a L{CalDAVFile} which represents a not-yet-created calendar
-        collection is looked up in a L{CalendarHomeFile} representing a calendar
+        collection is looked up in a L{CalendarHomeResource} representing a calendar
         home, it will initially have a new storage backend set to C{None}, but
         when the calendar is created via a protocol action, the backend will be
         initialized to match.
         """
         calDavFile = yield self.getResource("calendars/users/wsanchez/frobozz")
-        self.assertIsInstance(calDavFile, ProtoCalendarCollectionFile)
+        self.assertIsInstance(calDavFile, ProtoCalendarCollectionResource)
         calDavFile.createCalendarCollection()
         self.commit()
         self.assertEquals(calDavFile.fp, calDavFile._newStoreCalendar._path)
@@ -211,7 +211,7 @@
         """
         When a L{CalDAVFile} I{not} representing a calendar collection - one of
         the special collections, like the dropbox or freebusy URLs - is looked
-        up in a L{CalendarHomeFile} representing a calendar home, it will I{not}
+        up in a L{CalendarHomeResource} representing a calendar home, it will I{not}
         create a corresponding L{Calendar} via C{CalendarHome.calendarWithName}.
         """
         for specialName in ['dropbox', 'freebusy', 'notifications']:
@@ -301,7 +301,7 @@
         initialized to match.
         """
         calDavFile = yield self.getResource("addressbooks/users/wsanchez/frobozz")
-        self.assertIsInstance(calDavFile, ProtoAddressBookCollectionFile)
+        self.assertIsInstance(calDavFile, ProtoAddressBookCollectionResource)
         calDavFile.createAddressBookCollection()
         self.commit()
         self.assertEquals(calDavFile.fp, calDavFile._newStoreAddressBook._path)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/util.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/test/util.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -40,12 +40,12 @@
 
 from twistedcaldav import memcacher
 from twistedcaldav.config import config
-from twistedcaldav.static import CalDAVFile, CalendarHomeProvisioningFile,\
-    AddressBookHomeProvisioningFile
-from twistedcaldav.directory.xmlfile import XMLDirectoryService
+from twistedcaldav.static import CalDAVFile, AddressBookHomeProvisioningFile
 from twistedcaldav.directory import augment
+from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
 from twistedcaldav.directory.principal import (
     DirectoryPrincipalProvisioningResource)
+from twistedcaldav.directory.xmlfile import XMLDirectoryService
 
 from txdav.common.datastore.file import CommonDataStore
 
@@ -96,7 +96,7 @@
 
     def setupCalendars(self):
         """
-        Set up the resource at /calendars (a L{CalendarHomeProvisioningFile}),
+        Set up the resource at /calendars (a L{DirectoryCalendarHomeProvisioningResource}),
         and assign it as C{self.calendarCollection}.
         """
         path = self.site.resource.fp.child("calendars")
@@ -105,8 +105,7 @@
         # Need a data store
         _newStore = CommonDataStore(self.site.resource.fp, True, False)
 
-        self.calendarCollection = CalendarHomeProvisioningFile(
-            path,
+        self.calendarCollection = DirectoryCalendarHomeProvisioningResource(
             self.directoryService,
             "/calendars/",
             _newStore
@@ -293,7 +292,7 @@
     def setUp(self):
         """
         Replace self.site.resource with an appropriately provisioned
-        CalendarHomeFile, and replace self.docroot with a path pointing at that
+        CalendarHomeResource, and replace self.docroot with a path pointing at that
         file.
         """
         super(HomeTestCase, self).setUp()
@@ -305,8 +304,7 @@
         # Need a data store
         _newStore = CommonDataStore(fp, True, False)
 
-        self.homeProvisioner = CalendarHomeProvisioningFile(
-            os.path.join(fp.path, "calendars"),
+        self.homeProvisioner = DirectoryCalendarHomeProvisioningResource(
             self.directoryService, "/calendars/",
             _newStore
         )

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/timezoneservice.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/timezoneservice.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/timezoneservice.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -90,8 +90,8 @@
             ),
         )
 
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.timezones)
+    def resourceType(self):
+        return davxml.ResourceType.timezones
 
     def isCollection(self):
         return False

Modified: CalendarServer/branches/new-store-no-caldavfile/txcaldav/calendarstore/file.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/txcaldav/calendarstore/file.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/txcaldav/calendarstore/file.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -75,7 +75,7 @@
 
 
     def calendarWithName(self, name):
-        if name == 'dropbox':
+        if name in ('dropbox', 'notifications', 'freebusy'):
             # "dropbox" is a file storage area, not a calendar.
             return None
         else:
@@ -86,12 +86,24 @@
     removeCalendarWithName = CommonHome.removeChildWithName
 
     def calendars(self):
+        """
+        Return a generator of the child resource objects.
+        """
         for child in self.children():
             if child.name() in ('dropbox', 'notification'):
                 continue
             yield child
 
+    def listCalendars(self):
+        """
+        Return a generator of the child resource names.
+        """
+        for name in self.listChildren():
+            if name in ('dropbox', 'notification'):
+                continue
+            yield name
 
+
     def calendarObjectWithDropboxID(self, dropboxID):
         """
         Implement lookup with brute-force scanning.
@@ -157,6 +169,7 @@
 
     ownerCalendarHome = CommonHomeChild.ownerHome
     calendarObjects = CommonHomeChild.objectResources
+    listCalendarObjects = CommonHomeChild.listObjectResources
     calendarObjectWithName = CommonHomeChild.objectResourceWithName
     calendarObjectWithUID = CommonHomeChild.objectResourceWithUID
     createCalendarObjectWithName = CommonHomeChild.createObjectResourceWithName

Modified: CalendarServer/branches/new-store-no-caldavfile/txcarddav/addressbookstore/file.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/txcarddav/addressbookstore/file.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/txcarddav/addressbookstore/file.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -64,6 +64,7 @@
         self._childClass = AddressBook
 
     addressbooks = CommonHome.children
+    listAddressbooks = CommonHome.listChildren
     addressbookWithName = CommonHome.childWithName
     createAddressBookWithName = CommonHome.createChildWithName
     removeAddressBookWithName = CommonHome.removeChildWithName
@@ -112,6 +113,7 @@
 
     ownerAddressBookHome = CommonHomeChild.ownerHome
     addressbookObjects = CommonHomeChild.objectResources
+    listAddressbookObjects = CommonHomeChild.listObjectResources
     addressbookObjectWithName = CommonHomeChild.objectResourceWithName
     addressbookObjectWithUID = CommonHomeChild.objectResourceWithUID
     createAddressBookObjectWithName = CommonHomeChild.createObjectResourceWithName

Modified: CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/__init__.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/__init__.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/__init__.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -0,0 +1,19 @@
+##
+# Copyright (c) 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.
+##
+
+"""
+xxxDAV protocol data store for Twisted.
+"""

Modified: CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/file.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/file.py	2010-07-20 02:56:47 UTC (rev 5922)
+++ CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/file.py	2010-07-21 20:29:32 UTC (rev 5923)
@@ -295,12 +295,27 @@
         return self._shares
 
     def children(self):
+        """
+        Return a set of the child resource objects.
+        """
         return set(self._newChildren.itervalues()) | set(
             self.childWithName(name)
             for name in self._path.listdir()
             if not name.startswith(".")
         )
 
+    def listChildren(self):
+        """
+        Return a set of the names of the child resources.
+        """
+        return set(
+            [child.name() for child in self._newChildren.itervalues()]
+        ) | set(
+            name
+            for name in self._path.listdir()
+            if not name.startswith(".")
+        )
+
     def childWithName(self, name):
         child = self._newChildren.get(name)
         if child is not None:
@@ -508,6 +523,9 @@
         self.properties().setPerUserUID(uid)
 
     def objectResources(self):
+        """
+        Return a list of object resource objects.
+        """
         return sorted((
             self.objectResourceWithName(name)
             for name in (
@@ -520,6 +538,21 @@
         )
 
 
+    def listObjectResources(self):
+        """
+        Return a list of object resource names.
+        """
+        return sorted((
+            name
+            for name in (
+                set(self._newObjectResources.iterkeys()) |
+                set(name for name in self._path.listdir()
+                    if not name.startswith(".")) -
+                set(self._removedObjectResources)
+            ))
+        )
+
+
     def objectResourceWithName(self, name):
         if name in self._removedObjectResources:
             return None
@@ -739,6 +772,7 @@
         return ResourceType.notification
 
     notificationObjects = CommonHomeChild.objectResources
+    listNotificationObjects = CommonHomeChild.listObjectResources
     notificationObjectWithName = CommonHomeChild.objectResourceWithName
     removeNotificationObjectWithUID = CommonHomeChild.removeObjectResourceWithUID
     notificationObjectsSinceToken = CommonHomeChild.objectResourcesSinceToken
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100721/d34c1d56/attachment-0001.html>


More information about the calendarserver-changes mailing list