[CalendarServer-changes] [4524] CalendarServer/branches/more-deferreds-3

source_changes at macosforge.org source_changes at macosforge.org
Thu Sep 3 10:58:16 PDT 2009


Revision: 4524
          http://trac.macosforge.org/projects/calendarserver/changeset/4524
Author:   sagen at apple.com
Date:     2009-09-03 10:58:15 -0700 (Thu, 03 Sep 2009)
Log Message:
-----------
Checkpoint -- more API deferred

Modified Paths:
--------------
    CalendarServer/branches/more-deferreds-3/calendarserver/provision/root.py
    CalendarServer/branches/more-deferreds-3/calendarserver/sidecar/task.py
    CalendarServer/branches/more-deferreds-3/calendarserver/tools/principals.py
    CalendarServer/branches/more-deferreds-3/calendarserver/tools/util.py
    CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py
    CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
    CalendarServer/branches/more-deferreds-3/twistedcaldav/accesslog.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/aggregate.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/appleopendirectory.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/cachingdirectory.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/directory.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/resource.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sudo.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_cachedirectory.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_calendar.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_guidchange.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_opendirectory.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_proxyprincipalmembers.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_sudo.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_xmlfile.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/util.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/wiki.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/xmlfile.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_mkcalendar.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/upgrade.py

Removed Paths:
-------------
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/apache.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldappleopendirectory.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldxmlfile.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sqldb.py

Modified: CalendarServer/branches/more-deferreds-3/calendarserver/provision/root.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/provision/root.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/provision/root.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -19,7 +19,7 @@
     "RootResource",
 ]
 
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 from twisted.cred.error import LoginFailed, UnauthorizedLogin
 
 from twisted.web2 import responsecode
@@ -95,7 +95,7 @@
         return self._dead_properties
 
     def defaultAccessControlList(self):
-        return config.RootResourceACL
+        return succeed(config.RootResourceACL)
 
     @inlineCallbacks
     def checkSacl(self, request):
@@ -135,7 +135,7 @@
         request.checkingSACL = True
 
         for collection in self.principalCollections():
-            principal = collection._principalForURI(authzUser.children[0].children[0].data)
+            principal = (yield collection._principalForURI(authzUser.children[0].children[0].data))
             if principal is None:
                 response = (yield UnauthorizedResponse.makeResponse(
                     request.credentialFactories,
@@ -180,14 +180,14 @@
                     username = (yield proxy.callRemote(wikiConfig["UserMethod"], token))
                     log.debug("Wiki lookup returned user: %s" % (username,))
                     directory = request.site.resource.getDirectory()
-                    record = directory.recordWithShortName("users", username)
+                    record = (yield directory.recordWithShortName("users", username))
                     if record is None:
                         raise HTTPError(StatusResponse(
                             responsecode.FORBIDDEN,
                             "The username (%s) corresponding to your sessionID was not found by calendar server." % (username,)
                         ))
                     for collection in self.principalCollections():
-                        principal = collection.principalForRecord(record)
+                        principal = (yield collection.principalForRecord(record))
                         if principal is not None:
                             break
                     else:
@@ -217,8 +217,7 @@
                                     davxml.HRef.fromString("/principals/wikis/%s/" % (wikiName,))
                                 )
 
-                    child = (yield super(RootResource, self).locateChild(request, segments))
-                    returnValue(child)
+                    returnValue((yield super(RootResource, self).locateChild(request, segments)))
 
                 # FIXME: should catch something more specific than Exception
                 except Exception, e:
@@ -275,8 +274,7 @@
             except KeyError:
                 pass
 
-        child = (yield super(RootResource, self).locateChild(request, segments))
-        returnValue(child)
+        returnValue((yield super(RootResource, self).locateChild(request, segments)))
 
     def http_COPY       (self, request): return responsecode.FORBIDDEN
     def http_MOVE       (self, request): return responsecode.FORBIDDEN

Modified: CalendarServer/branches/more-deferreds-3/calendarserver/sidecar/task.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/sidecar/task.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/sidecar/task.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -92,7 +92,7 @@
     log.debug("Processing inbox item %s" % (inboxItemFile,))
 
     principals = rootResource.getChild("principals")
-    ownerPrincipal = principals.principalForUID(uuid)
+    ownerPrincipal = (yield principals.principalForUID(uuid))
     cua = "urn:uuid:%s" % (uuid,)
     owner = LocalCalendarUser(cua, ownerPrincipal,
         inboxFile, ownerPrincipal.scheduleInboxURL())
@@ -111,7 +111,7 @@
         # originator is the organizer
         originator = calendar.getOrganizer()
 
-    originatorPrincipal = principals.principalForCalendarUserAddress(originator)
+    originatorPrincipal = (yield principals.principalForCalendarUserAddress(originator))
     originator = LocalCalendarUser(originator, originatorPrincipal)
     recipients = (owner,)
     scheduler = DirectScheduler(FakeRequest(rootResource, "PUT"), inboxItemFile)

Modified: CalendarServer/branches/more-deferreds-3/calendarserver/tools/principals.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/tools/principals.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/tools/principals.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -144,6 +144,7 @@
                 raise AssertionError("Unknown proxy type")
 
             try:
+                # MOR: what to do here?
                 principalForPrincipalID(arg, checkOnly=True)
             except ValueError, e:
                 abort(e)
@@ -152,6 +153,7 @@
 
         elif opt in ("", "--remove-proxy"):
             try:
+                # MOR: what to do here?
                 principalForPrincipalID(arg, checkOnly=True)
             except ValueError, e:
                 abort(e)
@@ -201,6 +203,7 @@
     #
     for arg in args:
         try:
+            # MOR: what to do here?
             principalForPrincipalID(arg, checkOnly=True)
         except ValueError, e:
             abort(e)
@@ -256,7 +259,7 @@
         for principalID in principalIDs:
             # Resolve the given principal IDs to principals
             try:
-                principal = principalForPrincipalID(principalID)
+                principal = (yield principalForPrincipalID(principalID))
             except ValueError:
                 principal = None
 
@@ -275,6 +278,7 @@
         #
         reactor.stop()
 
+ at inlineCallbacks
 def principalForPrincipalID(principalID, checkOnly=False, directory=None):
     
     # Allow a directory parameter to be passed in, but default to config.directory
@@ -287,14 +291,14 @@
         raise ValueError("Can't resolve paths yet")
 
         if checkOnly:
-            return None
+            returnValue(None)
 
     if principalID.startswith("("):
         try:
             i = principalID.index(")")
 
             if checkOnly:
-                return None
+                returnValue(None)
 
             recordType = principalID[1:i]
             shortName = principalID[i+1:]
@@ -302,26 +306,26 @@
             if not recordType or not shortName or "(" in recordType:
                 raise ValueError()
 
-            return directory.principalCollection.principalForShortName(recordType, shortName)
+            returnValue((yield directory.principalCollection.principalForShortName(recordType, shortName)))
 
         except ValueError:
             pass
 
     if ":" in principalID:
         if checkOnly:
-            return None
+            returnValue(None)
 
         recordType, shortName = principalID.split(":", 1)
 
-        return directory.principalCollection.principalForShortName(recordType, shortName)
+        returnValue((yield directory.principalCollection.principalForShortName(recordType, shortName)))
 
     try:
         guid = UUID(principalID)
 
         if checkOnly:
-            return None
+            returnValue(None)
 
-        return directory.principalCollection.principalForUID(guid)
+        returnValue((yield directory.principalCollection.principalForUID(guid)))
     except ValueError:
         pass
 
@@ -340,7 +344,7 @@
 @inlineCallbacks
 def action_listProxies(principal, *proxyTypes):
     for proxyType in proxyTypes:
-        subPrincipal = proxySubprincipal(principal, proxyType)
+        subPrincipal = (yield proxySubprincipal(principal, proxyType))
         if subPrincipal is None:
             print "No %s proxies for %s" % (proxyType, principal)
             continue
@@ -360,7 +364,7 @@
 @inlineCallbacks
 def action_addProxy(principal, proxyType, *proxyIDs):
     for proxyID in proxyIDs:
-        proxyPrincipal = principalForPrincipalID(proxyID)
+        proxyPrincipal = (yield principalForPrincipalID(proxyID))
         (yield action_addProxyPrincipal(principal, proxyType, proxyPrincipal))
 
 @inlineCallbacks
@@ -393,7 +397,7 @@
 @inlineCallbacks
 def action_removeProxy(principal, *proxyIDs, **kwargs):
     for proxyID in proxyIDs:
-        proxyPrincipal = principalForPrincipalID(proxyID)
+        proxyPrincipal = (yield principalForPrincipalID(proxyID))
         (yield action_removeProxyPrincipal(principal, proxyPrincipal, **kwargs))
 
 @inlineCallbacks
@@ -402,7 +406,7 @@
     for proxyType in proxyTypes:
         proxyURL = proxyPrincipal.url()
 
-        subPrincipal = proxySubprincipal(principal, proxyType)
+        subPrincipal = (yield proxySubprincipal(principal, proxyType))
         if subPrincipal is None:
             sys.stderr.write("Unable to edit %s proxies for %s\n" % (proxyType, principal))
             continue

Modified: CalendarServer/branches/more-deferreds-3/calendarserver/tools/util.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/tools/util.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/tools/util.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -25,6 +25,7 @@
 import os
 from time import sleep
 
+from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.python.reflect import namedClass
 
 import socket
@@ -69,21 +70,24 @@
 
         principalCollection = property(getPrincipalCollection, setPrincipalCollection)
 
+        @inlineCallbacks
         def calendarHomeForRecord(self, record):
-            principal = self.principalCollection.principalForRecord(record)
+            principal = (yield self.principalCollection.principalForRecord(record))
             if principal:
                 try:
-                    return principal.calendarHome()
+                    returnValue(principal.calendarHome())
                 except AttributeError:
                     pass
-            return None
+            returnValue(None)
 
+        @inlineCallbacks
         def calendarHomeForShortName(self, recordType, shortName):
-            principal = self.principalCollection.principalForShortName(recordType, shortName)
+            principal = (yield self.principalCollection.principalForShortName(recordType, shortName))
             if principal:
-                return principal.calendarHome()
-            return None
+                returnValue(principal.calendarHome())
+            returnValue(None)
 
+        # Deferred
         def principalForCalendarUserAddress(self, cua):
             return self.principalCollection.principalForCalendarUserAddress(cua)
 
@@ -100,7 +104,7 @@
     baseGUID = "51856FD4-5023-4890-94FE-4356C4AAC3E4"
     def recordTypes(self): return ()
     def listRecords(self): return ()
-    def recordWithShortName(self): return None
+    def recordWithShortName(self): return succeed(None)
 
 dummyDirectoryRecord = DirectoryRecord(
     service = DummyDirectoryService(),

Modified: CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -48,7 +48,7 @@
 
     # Only allow administrators to access
     def defaultAccessControlList(self):
-        return davxml.ACL(*config.AdminACEs)
+        return succeed(davxml.ACL(*config.AdminACEs))
     
     def etag(self):
         # Can't be calculated here
@@ -149,7 +149,7 @@
         # Add details if a resource has been selected.
         if resourceId:
         
-            principal = self.getResourceById(request, resourceId)
+            principal = (yield self.getResourceById(request, resourceId))
     
             # Update the auto-schedule value if specified.
             if autoSchedule is not None and (autoSchedule == "true" or autoSchedule == "false"):
@@ -158,15 +158,15 @@
 
             # Update the proxies if specified.
             for proxyId in removeProxies:
-                proxy = self.getResourceById(request, proxyId)
+                proxy = (yield self.getResourceById(request, proxyId))
                 (yield action_removeProxyPrincipal(principal, proxy, proxyTypes=["read", "write"]))
 
             for proxyId in makeReadProxies:
-                proxy = self.getResourceById(request, proxyId)
+                proxy = (yield self.getResourceById(request, proxyId))
                 (yield action_addProxyPrincipal(principal, "read", proxy))
 
             for proxyId in makeWriteProxies:
-                proxy = self.getResourceById(request, proxyId)
+                proxy = (yield self.getResourceById(request, proxyId))
                 (yield action_addProxyPrincipal(principal, "write", proxy))
                 
             # Add the detailed content
@@ -435,6 +435,7 @@
         htmlContent.addCallback(_defer)
         return htmlContent
 
+    # Deferred
     def getResourceById(self, request, resourceId):
         if resourceId.startswith("/"):
             return request.locateResource(resourceId)

Modified: CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -41,15 +41,17 @@
 
 class WebCalendarResource (ReadOnlyResourceMixIn, DAVFile):
     def defaultAccessControlList(self):
-        return davxml.ACL(
-            davxml.ACE(
-                davxml.Principal(davxml.Authenticated()),
-                davxml.Grant(
-                    davxml.Privilege(davxml.Read()),
+        return succeed(
+            davxml.ACL(
+                davxml.ACE(
+                    davxml.Principal(davxml.Authenticated()),
+                    davxml.Grant(
+                        davxml.Privilege(davxml.Read()),
+                    ),
+                    davxml.Protected(),
+                    TwistedACLInheritable(),
                 ),
-                davxml.Protected(),
-                TwistedACLInheritable(),
-            ),
+            )
         )
 
     def etag(self):

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch	2009-09-03 17:58:15 UTC (rev 4524)
@@ -13,7 +13,7 @@
  from twisted.python import log
  from twisted.python.failure import Failure
 -from twisted.internet.defer import Deferred, maybeDeferred, succeed
-+from twisted.internet.defer import Deferred, maybeDeferred, succeed, inlineCallbacks
++from twisted.internet.defer import Deferred, maybeDeferred, succeed, inlineCallbacks, returnValue
  from twisted.internet.defer import waitForDeferred, deferredGenerator
 -from twisted.cred.error import LoginFailed, UnauthorizedLogin
  from twisted.internet import reactor
@@ -126,7 +126,7 @@
              if (qname not in qnames) and (qname[0] != twisted_private_namespace):
                  qnames.add(qname)
  
-@@ -495,37 +529,54 @@
+@@ -495,37 +529,62 @@
          in the dead property store may or may not be ignored when reading the
          property with L{readProperty}.
          """
@@ -177,25 +177,32 @@
 +        d.addCallback(callback)
 +        return d
  
++    @inlineCallbacks
      def displayName(self):
 -        if self.hasDeadProperty((davxml.dav_namespace, "displayname")):
 -            return str(self.readDeadProperty((davxml.dav_namespace, "displayname")))
--        else:
++        if (yield self.hasDeadProperty((davxml.dav_namespace, "displayname"))):
++            returnValue(str((yield self.readDeadProperty((davxml.dav_namespace, "displayname")))))
+         else:
 -            return super(DAVPropertyMixIn, self).displayName()
++            returnValue((yield super(DAVPropertyMixIn, self).displayName()))
+ 
++        """
 +        def callback(result):
 +            if result:
 +                return str(self.readDeadProperty((davxml.dav_namespace, "displayname")))
 +            else:
 +                return super(DAVPropertyMixIn, self).displayName()
- 
++
 +        d = self.hasDeadProperty((davxml.dav_namespace, "displayname"))
 +        d.addCallback(callback)
 +        return d
++        """
 +
  class DAVResource (DAVPropertyMixIn, StaticRenderMixin):
      """
      WebDAV resource.
-@@ -578,11 +629,10 @@
+@@ -578,11 +637,10 @@
  
          completionDeferred = Deferred()
          basepath = request.urlForResource(self)
@@ -209,7 +216,7 @@
  
          def checkPrivileges(child):
              if child is None:
-@@ -595,7 +645,7 @@
+@@ -595,7 +653,7 @@
              d.addCallback(lambda _: child)
              return d
  
@@ -218,7 +225,7 @@
              if child is None:
                  callback(None, childpath + "/")
              else:
-@@ -603,14 +653,15 @@
+@@ -603,14 +661,15 @@
                      callback(child, childpath + "/")
                      if depth == "infinity":
                          d = child.findChildren(depth, request, callback, privileges)
@@ -237,7 +244,7 @@
              try:
                  childname = children.pop()
              except IndexError:
-@@ -619,10 +670,10 @@
+@@ -619,10 +678,10 @@
                  childpath = joinURL(basepath, childname)
                  d = request.locateChildResource(self, childname)
                  d.addCallback(checkPrivileges)
@@ -250,7 +257,7 @@
  
          return completionDeferred
  
-@@ -642,41 +693,43 @@
+@@ -642,41 +701,43 @@
      # Authentication
      ##
  
@@ -321,7 +328,25 @@
      def authenticate(self, request):
          if not (
              hasattr(request, 'portal') and 
-@@ -781,7 +834,7 @@
+@@ -761,7 +822,7 @@
+         # and deny any type of write access (PUT, DELETE, etc.) to
+         # everything.
+         #
+-        return readonlyACL
++        return succeed(readonlyACL)
+ 
+     def defaultAccessControlList(self):
+         """
+@@ -772,7 +833,7 @@
+         # The default behaviour is no ACL; we should inherrit from the parent
+         # collection.
+         #
+-        return davxml.ACL()
++        return succeed(davxml.ACL())
+ 
+     def setAccessControlList(self, acl):
+         """
+@@ -781,7 +842,7 @@
          This implementation stores the ACL in the private property
          C{(L{twisted_private_namespace}, "acl")}.
          """
@@ -330,7 +355,7 @@
  
      def mergeAccessControlList(self, new_acl, request):
          """
-@@ -926,7 +979,9 @@
+@@ -926,7 +987,9 @@
          # FIXME: verify acl is self-consistent
  
          # Step 11
@@ -341,7 +366,7 @@
          yield None
  
      mergeAccessControlList = deferredGenerator(mergeAccessControlList)
-@@ -1089,7 +1144,9 @@
+@@ -1089,7 +1152,9 @@
              return url
  
          try:
@@ -352,8 +377,68 @@
          except HTTPError, e:
              assert e.response.code == responsecode.NOT_FOUND, (
                  "Expected %s response from readDeadProperty() exception, not %s"
-@@ -1635,7 +1692,9 @@
+@@ -1102,9 +1167,11 @@
  
+             if myURL == "/":
+                 # If we get to the root without any ACLs, then use the default.
+-                acl = self.defaultRootAccessControlList()
++                acl = waitForDeferred(self.defaultRootAccessControlList())
+             else:
+-                acl = self.defaultAccessControlList()
++                acl = waitForDeferred(self.defaultAccessControlList())
++            yield acl
++            acl = acl.getResult()
+ 
+         # Dynamically update privileges for those ace's that are inherited.
+         if inheritance:
+@@ -1223,16 +1290,21 @@
+             It will errback with an HTTPError(responsecode.FORBIDDEN) if
+             the principal isn't found.
+         """
+-        authnPrincipal = self.findPrincipalForAuthID(authid)
++        authnPrincipal = waitForDeferred(self.findPrincipalForAuthID(authid))
++        yield authnPrincipal
++        authnPrincipal = authnPrincipal.getResult()
+ 
+         if authnPrincipal is None:
+             log.msg("Could not find the principal resource for user id: %s" % (authid,))
+             raise HTTPError(responsecode.FORBIDDEN)
+ 
+-        d = self.authorizationPrincipal(request, authid, authnPrincipal)
+-        d.addCallback(lambda authzPrincipal: (authnPrincipal, authzPrincipal))
+-        return d
++        authzPrincipal = waitForDeferred(self.authorizationPrincipal(request, authid, authnPrincipal))
++        yield authzPrincipal
++        authzPrincipal = authzPrincipal.getResult()
++        yield (authnPrincipal, authzPrincipal)
+ 
++    principalsForAuthID = deferredGenerator(principalsForAuthID)
++
+     def findPrincipalForAuthID(self, authid):
+         """
+         Return authentication and authoirization prinicipal identifiers for the
+@@ -1247,11 +1319,16 @@
+             If not found return None.
+         """
+         for collection in self.principalCollections():
+-            principal = collection.principalForUser(authid)
++            principal = waitForDeferred(collection.principalForUser(authid))
++            yield principal
++            principal = principal.getResult()
+             if principal is not None:
+-                return principal
+-        return None
++                yield principal
++                return
++        yield None
+ 
++    findPrincipalForAuthID = deferredGenerator(findPrincipalForAuthID)
++
+     def authorizationPrincipal(self, request, authid, authnPrincipal):
+         """
+         Determine the authorization principal for the given request and authentication principal.
+@@ -1635,7 +1712,9 @@
+ 
          # Check this resource first
          if self.isCollection():
 -            qroot = self.quotaRoot(request)
@@ -363,7 +448,7 @@
              if qroot is not None:
                  used = waitForDeferred(self.currentQuotaUse(request))
                  yield used
-@@ -1666,14 +1725,17 @@
+@@ -1666,14 +1745,17 @@
  
      def hasQuota(self, request):
          """
@@ -383,7 +468,7 @@
              yield True
              return
          
-@@ -1705,10 +1767,19 @@
+@@ -1705,10 +1787,19 @@
          @return: a C{int} containing the maximum allowed bytes if this collection
              is quota-controlled, or C{None} if not quota controlled.
          """
@@ -406,7 +491,7 @@
      
      def quotaRootParent(self, request):
          """
-@@ -1724,7 +1795,10 @@
+@@ -1724,7 +1815,10 @@
              parent = waitForDeferred(request.locateResource(url))
              yield parent
              parent = parent.getResult()
@@ -418,7 +503,7 @@
                  yield parent
                  return
  
-@@ -1741,11 +1815,19 @@
+@@ -1741,11 +1835,19 @@
          assert maxsize is None or isinstance(maxsize, int), "maxsize must be an int or None"
          
          if maxsize is not None:
@@ -441,7 +526,7 @@
      
      def quotaSize(self, request):
          """
-@@ -1795,7 +1877,10 @@
+@@ -1795,7 +1897,10 @@
          
          # Check this resource first
          if self.isCollection():
@@ -453,7 +538,7 @@
                  d = waitForDeferred(self.updateQuotaUse(request, adjust))
                  yield d
                  d.getResult()
-@@ -1825,20 +1910,34 @@
+@@ -1825,20 +1930,34 @@
              is quota-controlled, or C{None} if not quota controlled.
          """
          assert self.isCollection(), "Only collections can have a quota root"
@@ -497,7 +582,7 @@
      def updateQuotaUse(self, request, adjust):
          """
          Update the quota used value on this resource.
-@@ -1848,25 +1947,32 @@
+@@ -1848,25 +1967,32 @@
          @return: an L{Deferred} with a C{int} result containing the current used byte if this collection
              is quota-controlled, or C{None} if not quota controlled.
          """
@@ -547,7 +632,7 @@
      ##
      # HTTP
      ##
-@@ -1880,7 +1986,7 @@
+@@ -1880,7 +2006,7 @@
          # If this is a collection and the URI doesn't end in "/", redirect.
          #
          if self.isCollection() and request.path[-1:] != "/":

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch	2009-09-03 17:58:15 UTC (rev 4524)
@@ -6,11 +6,20 @@
  
  from twisted.cred.portal import Portal
  
-+from twisted.internet.defer import waitForDeferred, deferredGenerator
++from twisted.internet.defer import waitForDeferred, deferredGenerator, succeed
 +
  from twisted.web2 import responsecode
  from twisted.web2.auth import basic
  from twisted.web2.stream import MemoryStream
+@@ -57,7 +59,7 @@
+         if typeResource:
+             user = typeResource.children.get(shortName, None)
+ 
+-        return user
++        return succeed(user)
+ 
+ class ACL(twisted.web2.dav.test.util.TestCase):
+     """
 @@ -68,7 +70,9 @@
          os.mkdir(docroot)
  

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/accesslog.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/accesslog.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/accesslog.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -79,6 +79,11 @@
                         uidz = str(request.authzUser.children[0])
                         
                     def convertUIDtoShortName(uid):
+                        # MOR: recordWithUID is now deferred -- not sure what to do here, so shortcircuiting for the moment:
+                        return uid
+                        # Cyrus suggests adding the records as attributes of
+                        # the request objects when authn/authz are added
+
                         uid = uid.rstrip("/")
                         uid = uid[uid.rfind("/") + 1:]
                         record = request.site.resource.getDirectory().recordWithUID(uid)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/aggregate.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/aggregate.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/aggregate.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -30,7 +30,7 @@
 from twistedcaldav.directory.idirectory import IDirectoryService
 from twistedcaldav.directory.directory import DirectoryService, DirectoryError
 from twistedcaldav.directory.directory import UnknownRecordTypeError
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 
 class AggregateDirectoryService(DirectoryService):
     """
@@ -89,22 +89,27 @@
     def recordTypes(self):
         return set(self._recordTypes)
 
+    @inlineCallbacks
     def listRecords(self, recordType):
-        records = self._query("listRecords", recordType)
+        records = (yield self._query("listRecords", recordType))
         if records is None:
-            return ()
+            returnValue( () )
         else:
-            return records
+            returnValue(records)
 
+    # Deferred
     def recordWithShortName(self, recordType, shortName):
         return self._query("recordWithShortName", recordType, shortName)
 
+    # Deferred
     def recordWithUID(self, uid):
         return self._queryAll("recordWithUID", uid)
 
+    # Deferred
     def recordWithAuthID(self, authID):
         return self._queryAll("recordWithAuthID", authID)
 
+    # Deferred
     def recordWithCalendarUserAddress(self, address):
         return self._queryAll("recordWithCalendarUserAddress", address)
 
@@ -132,24 +137,27 @@
         except KeyError:
             raise UnknownRecordTypeError(recordType)
 
+    # Deferred
     def _query(self, query, recordType, *args):
         try:
             service = self.serviceForRecordType(recordType)
         except UnknownRecordTypeError:
-            return None
+            return succeed(None)
 
+        # query is deferred
         return getattr(service, query)(
             recordType[len(service.recordTypePrefix):],
             *[a[len(service.recordTypePrefix):] for a in args]
         )
 
+    @inlineCallbacks
     def _queryAll(self, query, *args):
         for service in self._recordTypes.values():
-            record = getattr(service, query)(*args)
+            record = (yield getattr(service, query)(*args))
             if record is not None:
-                return record
+                returnValue(record)
         else:
-            return None
+            returnValue(None)
 
     userRecordTypes = [DirectoryService.recordType_users]
 

Deleted: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/apache.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/apache.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/apache.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -1,220 +0,0 @@
-##
-# Copyright (c) 2006-2009 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.
-##
-
-"""
-Apache UserFile/GroupFile compatible directory service implementation.
-"""
-
-__all__ = [
-    "BasicDirectoryService",
-    "DigestDirectoryService",
-]
-
-from crypt import crypt
-
-from twisted.python.filepath import FilePath
-from twisted.cred.credentials import UsernamePassword
-
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.directory import UnknownRecordTypeError, DirectoryConfigurationError
-
-class AbstractDirectoryService(DirectoryService):
-    """
-    Abstract Apache-compatible implementation of L{IDirectoryService}.
-    """
-    def __repr__(self):
-        return "<%s %r: %r %r>" % (self.__class__.__name__, self.realmName, self.userFile, self.groupFile)
-
-    def __init__(self, params):
-        defaults = {
-            'realmName' : '',
-            'userFile' : None,
-            'groupFile' : None,
-        }
-        ignored = None
-        params = self.getParams(params, defaults, ignored)
-
-        super(AbstractDirectoryService, self).__init__()
-
-        userFile = params["userFile"]
-        if not userFile:
-            raise DirectoryConfigurationError("Invalid Apache user file name: %r" % (userFile,))
-
-        if userFile and type(userFile) is str:
-            userFile = FilePath(userFile)
-
-        groupFile = params["groupFile"]
-        if groupFile and type(groupFile) is str:
-            groupFile = FilePath(groupFile)
-
-        self.realmName = params["realmName"]
-        self.userFile = userFile
-        self.groupFile = groupFile
-
-    def recordTypes(self):
-        recordTypes = (DirectoryService.recordType_users,)
-        if self.groupFile is not None:
-            recordTypes += (DirectoryService.recordType_groups,)
-        return recordTypes
-
-    def listRecords(self, recordType):
-        for entryShortName, entryData in self.entriesForRecordType(recordType):
-            if recordType == DirectoryService.recordType_users:
-                yield self.userRecordClass(
-                    service       = self,
-                    recordType    = recordType,
-                    shortName     = entryShortName,
-                    cryptPassword = entryData,
-                )
-
-            elif recordType == DirectoryService.recordType_groups:
-                yield GroupRecord(
-                    service    = self,
-                    recordType = recordType,
-                    shortName  = entryShortName,
-                    members    = entryData,
-                )
-
-            else:
-                # Subclass should cover the remaining record types
-                raise UnknownRecordTypeError("Unknown record type: %s" % (recordType,))
-
-    def recordWithShortName(self, recordType, shortName):
-        for entryShortName, entryData in self.entriesForRecordType(recordType):
-            if entryShortName == shortName:
-                if recordType == DirectoryService.recordType_users:
-                    return self.userRecordClass(
-                        service       = self,
-                        recordType    = recordType,
-                        shortName     = entryShortName,
-                        cryptPassword = entryData,
-                    )
-
-                if recordType == DirectoryService.recordType_groups:
-                    return GroupRecord(
-                        service    = self,
-                        recordType = recordType,
-                        shortName  = entryShortName,
-                        members    = entryData,
-                    )
-
-                # Subclass should cover the remaining record types
-                raise UnknownRecordTypeError("Unknown record type: %s" % (recordType,))
-
-        return None
-
-    def entriesForRecordType(self, recordType):
-        if recordType == DirectoryService.recordType_users:
-            recordFile = self.userFile
-        elif recordType == DirectoryService.recordType_groups:
-            recordFile = self.groupFile
-        else:
-            raise UnknownRecordTypeError("Unknown record type: %s" % (recordType,))
-
-        if recordFile is None:
-            return
-
-        try:
-            handle = recordFile.open()
-        except IOError, OSError:
-            self.log_error("Auth file (for %s) not found: %s" % (recordType, recordFile.path))
-            return
-
-        try:
-            for entry in handle:
-                if entry and entry[0] != "#":
-                    try:
-                        shortName, rest = entry.rstrip("\n").split(":", 1)
-                    except ValueError:
-                        continue
-                    yield shortName, rest
-        finally:
-            handle.close()
-
-class AbstractDirectoryRecord(DirectoryRecord):
-    """
-    Abstract Apache-compatible implementation of L{IDirectoryRecord}.
-    """
-    def __init__(self, service, recordType, shortName):
-        super(AbstractDirectoryRecord, self).__init__(
-            service               = service,
-            recordType            = recordType,
-            guid                  = None,
-            shortNames            = (shortName,),
-        )
-
-class AbstractUserRecord(AbstractDirectoryRecord):
-    def __init__(self, service, recordType, shortName, cryptPassword=None):
-        super(AbstractUserRecord, self).__init__(service, recordType, shortName)
-
-        self._cryptPassword = cryptPassword
-
-    def groups(self):
-        for group in self.service.listRecords(DirectoryService.recordType_groups):
-            for member in group.members():
-                if member == self:
-                    yield group
-                    continue
-
-class BasicUserRecord(AbstractUserRecord):
-    """
-    Apache UserFile implementation of L{IDirectoryRecord}.
-    """
-    def verifyCredentials(self, credentials):
-        if self._cryptPassword in ("", "*", "x"):
-            return False
-
-        if isinstance(credentials, UsernamePassword):
-            return crypt(credentials.password, self._cryptPassword) == self._cryptPassword
-
-        return super(BasicUserRecord, self).verifyCredentials(credentials)
-
-class BasicDirectoryService(AbstractDirectoryService):
-    """
-    Apache UserFile/GroupFile implementation of L{IDirectoryService}.
-    """
-    baseGUID = "DDF1E45C-CADE-4FCD-8AE6-B4B41D72B325"
-    userRecordClass = BasicUserRecord
-
-class DigestUserRecord(AbstractUserRecord):
-    """
-    Apache DigestUserFile implementation of L{IDirectoryRecord}.
-    """
-    def verifyCredentials(self, credentials):
-        raise NotImplementedError()
-
-class DigestDirectoryService(AbstractDirectoryService):
-    """
-    Apache DigestUserFile/GroupFile implementation of L{IDirectoryService}.
-    """
-    baseGUID = "0C719D1B-0A14-4074-8740-6D96A7D0C787"
-    userRecordClass = DigestUserRecord
-
-class GroupRecord(AbstractDirectoryRecord):
-    """
-    Apache GroupFile implementation of L{IDirectoryRecord}.
-    """
-    def __init__(self, service, recordType, shortName, members=()):
-        super(GroupRecord, self).__init__(service, recordType, shortName)
-
-        if type(members) is str:
-            members = tuple(m.strip() for m in members.split(","))
-
-        self._members = members
-
-    def members(self):
-        for shortName in self._members:
-            yield self.service.recordWithShortName(DirectoryService.recordType_users, shortName)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/appleopendirectory.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/appleopendirectory.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -35,6 +35,7 @@
 import dsattributes
 import dsquery
 
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 from twisted.internet.threads import deferToThread
 from twisted.cred.credentials import UsernamePassword
 from twisted.web2.auth.digest import DigestedCredentials
@@ -120,8 +121,12 @@
             h = (h + hash(getattr(self, attr))) & sys.maxint
         return h
 
-    def _expandGroupMembership(self, members, nestedGroups, processedGUIDs=None, returnGroups=False):
+    @inlineCallbacks
+    def _expandGroupMembership(self, members, nestedGroups, processedGUIDs=None, results=None, returnGroups=False):
 
+        if results is None:
+            results = set()
+
         if processedGUIDs is None:
             processedGUIDs = set()
 
@@ -134,7 +139,7 @@
         for memberGUID in members:
             if memberGUID not in processedGUIDs:
                 processedGUIDs.add(memberGUID)
-                yield memberGUID
+                results.add(memberGUID)
 
         for groupGUID in nestedGroups:
             if groupGUID in processedGUIDs:
@@ -149,7 +154,9 @@
                 dsattributes.kDSStdRecordTypeGroups,
                 [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
             ))
-            result = opendirectory.queryRecordsWithAttribute_list(
+            # MOR: Doublecheck this
+            result = (yield deferToThread(
+                opendirectory.queryRecordsWithAttribute_list,
                 self.directory,
                 dsattributes.kDS1AttrGeneratedUID,
                 groupGUID,
@@ -157,7 +164,7 @@
                 False,
                 dsattributes.kDSStdRecordTypeGroups,
                 [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
-            )
+            ))
 
             if not result:
                 self.log_error("Couldn't find group %s when trying to expand nested groups."
@@ -168,16 +175,18 @@
 
             processedGUIDs.add(groupGUID)
             if returnGroups:
-                yield groupGUID
+                results.add(groupGUID)
 
-            for GUID in self._expandGroupMembership(
+            yield self._expandGroupMembership(
                 group.get(dsattributes.kDSNAttrGroupMembers, []),
                 group.get(dsattributes.kDSNAttrNestedGroups, []),
                 processedGUIDs,
+                results,
                 returnGroups,
-            ):
-                yield GUID
+            )
 
+        returnValue(results)
+
     def _calendarUserAddresses(self, recordType, recordData):
         """
         Extract specific attributes from the directory record for use as calendar user address.
@@ -206,6 +215,7 @@
             self.recordType_resources,
         )
 
+    @inlineCallbacks
     def groupsForGUID(self, guid):
         
         attrs = [
@@ -227,7 +237,8 @@
                 recordType,
                 attrs,
             ))
-            results = opendirectory.queryRecordsWithAttribute_list(
+            results = (yield deferToThread(
+                opendirectory.queryRecordsWithAttribute_list,
                 self.directory,
                 query.attribute,
                 query.value,
@@ -235,7 +246,7 @@
                 False,
                 recordType,
                 attrs,
-            )
+            ))
         except opendirectory.ODError, ex:
             self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
             raise
@@ -258,7 +269,8 @@
                 recordType,
                 attrs,
             ))
-            results = opendirectory.queryRecordsWithAttribute_list(
+            results = (yield deferToThread(
+                opendirectory.queryRecordsWithAttribute_list,
                 self.directory,
                 query.attribute,
                 query.value,
@@ -266,7 +278,7 @@
                 False,
                 recordType,
                 attrs,
-            )
+            ))
         except opendirectory.ODError, ex:
             self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
             raise
@@ -278,7 +290,7 @@
             if recordGUID:
                 guids.add(recordGUID)
 
-        return guids
+        returnValue(guids)
 
     def proxiesForGUID(self, recordType, guid):
         
@@ -361,24 +373,13 @@
     _fromODRecordTypes = dict([(b, a) for a, b in _toODRecordTypes.iteritems()])
 
 
+    @inlineCallbacks
     def recordsMatchingFields(self, fields, operand="or", recordType=None):
 
         # Note that OD applies case-sensitivity globally across the entire
         # query, not per expression, so the current code uses whatever is
         # specified in the last field in the fields list
 
-        def collectResults(results):
-            self.log_info("Got back %d records from OD" % (len(results),))
-            for key, val in results.iteritems():
-                self.log_debug("OD result: %s %s" % (key, val))
-                try:
-                    guid = val[dsattributes.kDS1AttrGeneratedUID]
-                    record = self.recordWithGUID(guid)
-                    if record:
-                        yield record
-                except KeyError:
-                    pass
-
         def multiQuery(directory, queries, attrs, operand):
             results = {}
 
@@ -426,17 +427,30 @@
 
         queries = buildQueries(recordTypes, fields, self._ODFields)
 
-        deferred = deferToThread(
+        odResults = (yield deferToThread(
             multiQuery,
             self.directory,
             queries,
             [ dsattributes.kDS1AttrGeneratedUID ],
             operand
-        )
-        deferred.addCallback(collectResults)
-        return deferred
+        ))
 
+        results = []
+        self.log_info("Got back %d records from OD" % (len(results),))
+        for key, val in odResults.iteritems():
+            self.log_debug("OD result: %s %s" % (key, val))
+            try:
+                guid = val[dsattributes.kDS1AttrGeneratedUID]
+                record = (yield self.recordWithGUID(guid))
+                if record:
+                    results.append(record)
+            except KeyError:
+                pass
 
+        returnValue(results)
+
+
+    @inlineCallbacks
     def queryDirectory(self, recordTypes, indexType, indexKey,
         lookupMethod=opendirectory.queryRecordsWithAttribute_list):
         
@@ -509,7 +523,8 @@
                 listRecordTypes,
                 attrs,
             ))
-            results = lookupMethod(
+            results = (yield deferToThread(
+                lookupMethod,
                 self.directory,
                 query.attribute,
                 query.value,
@@ -517,13 +532,13 @@
                 False,
                 listRecordTypes,
                 attrs,
-            )
+            ))
             self.log_debug("opendirectory.queryRecordsWithAttribute_list matched records: %s" % (len(results),))
 
         except opendirectory.ODError, ex:
             if ex.message[1] == -14140 or ex.message[1] == -14200:
                 # Unsupported attribute on record - don't fail
-                return
+                returnValue(None)
             else:
                 self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
                 raise
@@ -603,7 +618,8 @@
                             dsattributes.kDSStdRecordTypeGroups,
                             [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups,],
                         ))
-                        results = lookupMethod(
+                        results = (yield deferToThread(
+                            lookupMethod,
                             self.directory,
                             attributeToMatch,
                             valueToMatch,
@@ -611,7 +627,7 @@
                             False,
                             dsattributes.kDSStdRecordTypeGroups,
                             [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups,],
-                        )
+                        ))
 
                         if len(results) == 1:
                             members = results[0][1].get(dsattributes.kDSNAttrGroupMembers, [])
@@ -619,7 +635,7 @@
                         else:
                             members = []
                             nestedGroups = []
-                        self.restrictedGUIDs = set(self._expandGroupMembership(members, nestedGroups, returnGroups=True))
+                        self.restrictedGUIDs = (yield self._expandGroupMembership(members, nestedGroups, returnGroups=True))
                         self.log_debug("Got %d restricted group members" % (len(self.restrictedGUIDs),))
                         self.restrictedTimestamp = time.time()
 
@@ -701,9 +717,9 @@
             # Fetch the set of groups this record is a member of so we can
             # cache it, rather than have each process make the same group
             # lookup
-            record._groupMembershipGUIDs = self.groupsForGUID(record.guid)
+            record._groupMembershipGUIDs = (yield self.groupsForGUID(record.guid))
 
-            self.recordCacheForType(recordType).addRecord(record, indexType, origIndexKey)
+            yield self.recordCacheForType(recordType).addRecord(record, indexType, origIndexKey)
 
     def _parseResourceInfo(self, plist, guid, recordType, shortname):
         """
@@ -732,6 +748,7 @@
 
         return (autoaccept, proxy, read_only_proxy,)
 
+    @inlineCallbacks
     def getResourceInfo(self):
         """
         Resource information including proxy assignments for resource and
@@ -743,6 +760,7 @@
             dsattributes.kDS1AttrGeneratedUID,
             dsattributes.kDSNAttrResourceInfo,
         ]
+        results = []
 
         for recordType in (dsattributes.kDSStdRecordTypePlaces, dsattributes.kDSStdRecordTypeResources):
             try:
@@ -751,11 +769,12 @@
                     recordType,
                     attrs,
                 ))
-                results = opendirectory.listAllRecordsWithAttributes_list(
+                results = (yield deferToThread(
+                    opendirectory.listAllRecordsWithAttributes_list,
                     self.directory,
                     recordType,
                     attrs,
-                )
+                ))
             except opendirectory.ODError, ex:
                 self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
                 raise
@@ -769,7 +788,8 @@
                             recordGUID, recordType, recordShortName)
                     except ValueError:
                         continue
-                    yield recordGUID, autoSchedule, proxy, readOnlyProxy
+                    results.append((recordGUID, autoSchedule, proxy, readOnlyProxy))
+        returnValue(results)
 
 
     def isAvailable(self):
@@ -861,44 +881,56 @@
             self.fullName
         )
 
+    @inlineCallbacks
     def members(self):
         if self.recordType != self.service.recordType_groups:
-            return
+            returnValue(None)
 
+        results = []
         for guid in self._memberGUIDs:
-            userRecord = self.service.recordWithGUID(guid)
+            userRecord = (yield self.service.recordWithGUID(guid))
             if userRecord is not None:
-                yield userRecord
+                results.append(userRecord)
+        returnValue(results)
 
+    @inlineCallbacks
     def groups(self):
         if self._groupMembershipGUIDs is None:
             self._groupMembershipGUIDs = self.service.groupsForGUID(self.guid)
 
+        results = []
         for guid in self._groupMembershipGUIDs:
-            record = self.service.recordWithGUID(guid)
+            record = (yield self.service.recordWithGUID(guid))
             if record:
-                yield record
+                results.append(record)
+        returnValue(results)
 
+    @inlineCallbacks
     def verifyCredentials(self, credentials):
         if isinstance(credentials, UsernamePassword):
             # Check cached password
             try:
                 if credentials.password == self.password:
-                    return True
+                    returnValue(True)
             except AttributeError:
                 pass
 
             # Check with directory services
             try:
-                if opendirectory.authenticateUserBasic(self.service.directory, self.nodeName, self.shortNames[0], credentials.password):
+                if (yield deferToThread(
+                    opendirectory.authenticateUserBasic,
+                    self.service.directory,
+                    self.nodeName,
+                    self.shortNames[0],
+                    credentials.password)):
                     # Cache the password to avoid future DS queries
                     self.password = credentials.password
-                    return True
+                    returnValue(True)
             except opendirectory.ODError, e:
                 self.log_error("OpenDirectory (node=%s) error while performing basic authentication for user %s: %s"
                             % (self.service.realmName, self.shortNames[0], e))
 
-            return False
+            returnValue(False)
 
         elif isinstance(credentials, DigestedCredentials):
             #
@@ -923,23 +955,24 @@
                     "missing digest response field: %s in: %s"
                     % (self.service.realmName, self.shortNames[0], e, credentials.fields)
                 )
-                return False
+                returnValue(False)
 
             try:
                 if self.digestcache[credentials.fields["uri"]] == response:
-                    return True
+                    returnValue(True)
             except (AttributeError, KeyError):
                 pass
 
             try:
-                if opendirectory.authenticateUserDigest(
+                if (yield deferToThread(
+                    opendirectory.authenticateUserDigest,
                     self.service.directory,
                     self.nodeName,
                     self.shortNames[0],
                     challenge,
                     response,
                     credentials.originalMethod if credentials.originalMethod else credentials.method
-                ):
+                )):
                     try:
                         cache = self.digestcache
                     except AttributeError:
@@ -947,7 +980,7 @@
 
                     cache[credentials.fields["uri"]] = response
 
-                    return True
+                    returnValue(True)
                 else:
                     self.log_debug(
 """OpenDirectory digest authentication failed with:
@@ -963,11 +996,11 @@
                     "OpenDirectory (node=%s) error while performing digest authentication for user %s: %s"
                     % (self.service.realmName, self.shortNames[0], e)
                 )
-                return False
+                returnValue(False)
 
-            return False
+            returnValue(False)
 
-        return super(OpenDirectoryRecord, self).verifyCredentials(credentials)
+        returnValue((yield super(OpenDirectoryRecord, self).verifyCredentials(credentials)))
 
 class OpenDirectoryInitError(DirectoryError):
     """

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/cachingdirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/cachingdirectory.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/cachingdirectory.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -34,6 +34,7 @@
 from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord, DirectoryError
 from twistedcaldav.log import LoggingMixIn
 from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 
 
 class RecordTypeCache(object):
@@ -72,6 +73,7 @@
             CachingDirectoryService.INDEX_TYPE_AUTHID   : {},
         }
 
+    # MOR: Defer this
     def addRecord(self, record, indexType, indexKey, useMemcache=True,
         neverExpire=False):
 
@@ -94,7 +96,9 @@
                 self.log_debug("Memcache: storing %s" % (key,))
                 self.directoryService.memcacheSet(key, record)
 
+        return succeed(None) # MOR: Remove this when really deferred
 
+    # MOR: Defer this
     def removeRecord(self, record):
         if record in self.records:
             self.records.remove(record)
@@ -113,6 +117,8 @@
                             self.log_debug("Missing record index item; type: %s, item: %s" % (indexType, item))
                 else:
                     raise AssertionError("Data from record attribute must be str, list or tuple")
+
+        return succeed(None) # MOR: Remove this when really deferred
         
     def findRecord(self, indexType, indexKey):
         return self.recordsIndexedBy[indexType].get(indexKey)
@@ -158,6 +164,8 @@
                 debug=0, pickleProtocol=2)
         return self.memcacheClient
 
+
+    @inlineCallbacks
     def memcacheSet(self, key, record):
 
         hideService = isinstance(record, DirectoryRecord)
@@ -167,12 +175,12 @@
                 record.service = None # so we don't pickle service
 
             key = base64.b64encode(key)
-            if not self._getMemcacheClient().set(key, record, time=self.cacheTimeout):
+            if not (yield self._getMemcacheClient().set(key, record, time=self.cacheTimeout)):
                 self.log_error("Could not write to memcache, retrying")
-                if not self._getMemcacheClient(refresh=True).set(
+                if not (yield self._getMemcacheClient(refresh=True).set(
                     key, record,
                     time=self.cacheTimeout
-                ):
+                )):
                     self.log_error("Could not write to memcache again, giving up")
                     del self.memcacheClient
                     raise DirectoryMemcacheError("Failed to write to memcache")
@@ -180,22 +188,23 @@
             if hideService:
                 record.service = self
 
+    @inlineCallbacks
     def memcacheGet(self, key):
 
         key = base64.b64encode(key)
         try:
-            record = self._getMemcacheClient().get(key)
+            record = (yield self._getMemcacheClient().get(key))
             if record is not None and isinstance(record, DirectoryRecord):
                 record.service = self
         except memcacheclient.MemcacheError:
             self.log_error("Could not read from memcache, retrying")
             try:
-                record = self._getMemcacheClient(refresh=True).get(key)
+                record = (yield self._getMemcacheClient(refresh=True).get(key))
             except memcacheclient.MemcacheError:
                 self.log_error("Could not read from memcache again, giving up")
                 del self.memcacheClient
                 raise DirectoryMemcacheError("Failed to read from memcache")
-        return record
+        returnValue(record)
 
     def _initCaches(self, cacheClass):
         self._recordCaches = dict([
@@ -223,16 +232,17 @@
     def recordWithShortName(self, recordType, shortName):
         return self._lookupRecord((recordType,), CachingDirectoryService.INDEX_TYPE_SHORTNAME, shortName)
 
+    @inlineCallbacks
     def recordWithCalendarUserAddress(self, address):
         address = normalizeCUAddr(address)
         record = None
         if address.startswith("urn:uuid:"):
             guid = address[9:]
-            record = self.recordWithGUID(guid)
+            record = (yield self.recordWithGUID(guid))
         elif address.startswith("mailto:"):
-            record = self._lookupRecord(None, CachingDirectoryService.INDEX_TYPE_CUA, address)
+            record = (yield self._lookupRecord(None, CachingDirectoryService.INDEX_TYPE_CUA, address))
 
-        return record if record and record.enabledForCalendaring else None
+        returnValue(record if record and record.enabledForCalendaring else None)
 
     def recordWithAuthID(self, authID):
         return self._lookupRecord(None, CachingDirectoryService.INDEX_TYPE_AUTHID, authID)
@@ -242,6 +252,7 @@
 
     recordWithUID = recordWithGUID
 
+    @inlineCallbacks
     def _lookupRecord(self, recordTypes, indexType, indexKey, cacheOnMiss=True):
 
         if recordTypes is None:
@@ -254,9 +265,10 @@
                 if recordType in supportedRecordTypes:
                     typesToQuery.append(recordType)
             if not typesToQuery:
-                return None
+                returnValue(None)
             recordTypes = typesToQuery
 
+        @inlineCallbacks
         def lookup():
             for recordType in recordTypes:
                 record = self.recordCacheForType(recordType).findRecord(indexType, indexKey)
@@ -266,16 +278,16 @@
                         record.cachedTime != 0 and
                         time.time() - record.cachedTime > self.cacheTimeout
                     ):
-                        self.recordCacheForType(recordType).removeRecord(record)
-                        return None
+                        yield self.recordCacheForType(recordType).removeRecord(record)
+                        returnValue(None)
                     else:
-                        return record
+                        returnValue(record)
             else:
-                return None
+                returnValue(None)
 
-        record = lookup()
+        record = (yield lookup())
         if record:
-            return record
+            returnValue(record)
 
         if cacheOnMiss:
             
@@ -283,38 +295,38 @@
             try:
                 disabledTime = self._disabledKeys[indexType][indexKey]
                 if time.time() - disabledTime < self.cacheTimeout:
-                    return None
+                    returnValue(None)
             except KeyError:
                 pass
             
             # Check memcache
             if config.Memcached.ClientEnabled:
                 key = "dir|%s|%s" % (indexType, indexKey)
-                record = self.memcacheGet(key)
+                record = (yield self.memcacheGet(key))
                 self.log_debug("Memcache: checking %s" % (key,))
                 if record is None:
                     self.log_debug("Memcache: miss %s" % (key,))
                 else:
                     self.log_debug("Memcache: hit %s" % (key,))
-                    self.recordCacheForType(record.recordType).addRecord(record, indexType, indexKey, useMemcache=False)
-                    return record
+                    yield self.recordCacheForType(record.recordType).addRecord(record, indexType, indexKey, useMemcache=False)
+                    returnValue(record)
 
                 # Check negative memcache
-                val = self.memcacheGet("-%s" % (key,))
+                val = (yield self.memcacheGet("-%s" % (key,)))
                 if val == 1:
                     self.log_debug("Memcache: negative %s" % (key,))
                     self._disabledKeys[indexType][indexKey] = time.time()
-                    return None
+                    returnValue(None)
 
             # Try query
             self.log_debug("Faulting record for attribute '%s' with value '%s'" % (indexType, indexKey,))
-            self.queryDirectory(recordTypes, indexType, indexKey)
+            yield self.queryDirectory(recordTypes, indexType, indexKey)
             
             # Now try again from cache
-            record = lookup()
+            record = (yield lookup())
             if record:
                 self.log_debug("Found record for attribute '%s' with value '%s'" % (indexType, indexKey,))
-                return record
+                returnValue(record)
 
 
             # Add to negative cache with timestamp
@@ -323,9 +335,9 @@
 
             if config.Memcached.ClientEnabled:
                 self.log_debug("Memcache: storing (negative) %s" % (key,))
-                self.memcacheSet("-%s" % (key,), 1)
+                yield self.memcacheSet("-%s" % (key,), 1)
 
-        return None
+        returnValue(None)
 
     def queryDirectory(self, recordTypes, indexType, indexKey):
         raise NotImplementedError()

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -58,13 +58,32 @@
     DAVResource,
 ):
     def defaultAccessControlList(self):
-        return config.ProvisioningResourceACL
+        return succeed(config.ProvisioningResourceACL)
 
 
 class DirectoryCalendarHomeProvisioningResource (DirectoryCalendarProvisioningResource):
     """
     Resource which provisions calendar home collections as needed.    
     """
+
+    @classmethod
+    @inlineCallbacks
+    def fetch(cls, *a, **kw):
+        self = (yield super(DirectoryCalendarHomeProvisioningResource, cls).fetch(*a, **kw))
+        #
+        # Create children
+        #
+
+        @inlineCallbacks
+        def _provisionChild(name):
+            self.putChild(name, (yield self.provisionChild(name)))
+
+        for recordType in self.directory.recordTypes():
+            (yield _provisionChild(recordType))
+
+        (yield _provisionChild(uidsResourceName))
+        returnValue(self)
+
     def __init__(self, directory, url):
         """
         @param directory: an L{IDirectoryService} to provision calendars from.
@@ -81,17 +100,7 @@
         # FIXME: Smells like a hack
         directory.calendarHomesCollection = self
 
-        #
-        # Create children
-        #
-        def provisionChild(name):
-            self.putChild(name, self.provisionChild(name))
 
-        for recordType in self.directory.recordTypes():
-            provisionChild(recordType)
-
-        provisionChild(uidsResourceName)
-
     def provisionChild(self, recordType):
         raise NotImplementedError("Subclass must implement provisionChild()")
 
@@ -99,7 +108,7 @@
         return self._url
 
     def getChild(self, name):
-        return self.putChildren.get(name, None)
+        return succeed(self.putChildren.get(name, None))
 
     def listChildren(self):
         return succeed(self.directory.recordTypes())
@@ -109,17 +118,19 @@
         # See DirectoryPrincipalProvisioningResource.__init__()
         return self.directory.principalCollection.principalCollections()
 
+    # Deferred
     def principalForRecord(self, record):
         # FIXME: directory.principalCollection smells like a hack
         # See DirectoryPrincipalProvisioningResource.__init__()
         return self.directory.principalCollection.principalForRecord(record)
 
+    @inlineCallbacks
     def homeForDirectoryRecord(self, record):
-        uidResource = self.getChild(uidsResourceName)
+        uidResource = (yield self.getChild(uidsResourceName))
         if uidResource is None:
-            return succeed(None)
+            returnValue(None)
         else:
-            return uidResource.getChild(record.uid)
+            returnValue((yield uidResource.getChild(record.uid)))
 
     ##
     # DAV
@@ -158,25 +169,26 @@
             returnValue(self)
 
         if record is None:
-            record = self.directory.recordWithShortName(self.recordType, name)
+            record = (yield self.directory.recordWithShortName(self.recordType, name))
             if record is None:
                 returnValue(None)
 
         returnValue((yield self._parent.homeForDirectoryRecord(record)))
 
+    @inlineCallbacks
     def listChildren(self):
         if config.EnablePrincipalListings:
 
-            def _recordShortnameExpand():
-                for record in self.directory.listRecords(self.recordType):
-                    if record.enabledForCalendaring:
-                        for shortName in record.shortNames:
-                            yield shortName
+            results = []
+            for record in (yield self.directory.listRecords(self.recordType)):
+                if record.enabledForCalendaring:
+                    for shortName in record.shortNames:
+                        results.append(shortName)
 
-            return succeed(_recordShortnameExpand())
+            returnValue(results)
         else:
             # Not a listable collection
-            return fail(HTTPError(responsecode.FORBIDDEN))
+            raise HTTPError(responsecode.FORBIDDEN)
 
     def createSimilarFile(self, path):
         raise HTTPError(responsecode.NOT_FOUND)
@@ -195,6 +207,7 @@
     def principalCollections(self):
         return self._parent.principalCollections()
 
+    # Deferred
     def principalForRecord(self, record):
         return self._parent.principalForRecord(record)
 
@@ -221,7 +234,7 @@
             returnValue(self)
 
         if record is None:
-            record = self.directory.recordWithUID(name)
+            record = (yield self.directory.recordWithUID(name))
             if record is None:
                 returnValue(None)
 
@@ -245,6 +258,7 @@
     def principalCollections(self):
         return self.parent.principalCollections()
 
+    # Deferred
     def principalForRecord(self, record):
         return self.parent.principalForRecord(record)
 
@@ -295,15 +309,22 @@
         self.parent = parent
 
 
+    @inlineCallbacks
     def provisionDefaultCalendars(self):
 
         # Disable notifications during provisioning
         if hasattr(self, "clientNotifier"):
             self.clientNotifier.disableNotify()
 
-        @inlineCallbacks
-        def setupFreeBusy(_, child):
-            # Default calendar is initially opaque to freebusy
+        try:
+            yield self.provision()
+
+            childName = "calendar"
+            childURL = joinURL(self.url(), childName)
+            child = (yield self.provisionChild(childName))
+            
+            assert isinstance(child, CalDAVResource), "Child %r is not a %s: %r" % (childName, CalDAVResource.__name__, child)
+            yield child.createCalendarCollection()
             yield child.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()))
 
             # FIXME: Shouldn't have to call provision() on another resource
@@ -312,41 +333,18 @@
             # This will go away once we remove the free-busy-set property on inbox.
 
             # Set calendar-free-busy-set on inbox
-            inbox = self.getChild("inbox")
+            inbox = (yield self.getChild("inbox"))
             yield inbox.provision()
             yield inbox.processFreeBusyCalendar(childURL, True)
 
             # Default calendar is marked as the default for scheduling
             yield inbox.writeDeadProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(childURL)))
 
-            returnValue(self)
-
-        try:
-            d = self.provision()
-
-            childName = "calendar"
-            childURL = joinURL(self.url(), childName)
-            d.addCallback(lambda _: self.provisionChild(childName))
-            
-            def _makeChild(child):
-                assert isinstance(child, CalDAVResource), "Child %r is not a %s: %r" % (childName, CalDAVResource.__name__, child)
-                return child.createCalendarCollection().addCallback(setupFreeBusy, child)
-
-            d.addCallback(_makeChild)
-        except:
-            # We want to make sure to re-enable notifications, so do so
-            # if there is an immediate exception above, or via errback, below
+        finally:
             if hasattr(self, "clientNotifier"):
                 self.clientNotifier.enableNotify(None)
-            raise
 
-        # Re-enable notifications
-        if hasattr(self, "clientNotifier"):
-            d.addCallback(self.clientNotifier.enableNotify)
-            d.addErrback(self.clientNotifier.enableNotify)
 
-        return d
-
     def provisionChild(self, name):
         raise NotImplementedError("Subclass must implement provisionChild()")
 
@@ -370,14 +368,18 @@
     # ACL
     ##
 
+    @inlineCallbacks
     def owner(self, request):
-        return succeed(davxml.HRef(self.principalForRecord().principalURL()))
+        principal = (yield self.principalForRecord())
+        returnValue(davxml.HRef(principal.principalURL()))
 
+    # Deferred
     def ownerPrincipal(self, request):
-        return succeed(self.principalForRecord())
+        return self.principalForRecord()
 
+    @inlineCallbacks
     def defaultAccessControlList(self):
-        myPrincipal = self.principalForRecord()
+        myPrincipal = (yield self.principalForRecord())
 
         aces = (
             # Inheritable DAV:all access for the resource's associated principal.
@@ -426,7 +428,7 @@
                 ),
             )
 
-        return davxml.ACL(*aces)
+        returnValue(davxml.ACL(*aces))
 
     @inlineCallbacks
     def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
@@ -439,11 +441,12 @@
         else:
             # ...otherwise permissions are fixed, and are not subject to
             # inheritance rules, etc.
-            returnValue(self.defaultAccessControlList())
+            returnValue((yield self.defaultAccessControlList()))
 
     def principalCollections(self):
         return self.parent.principalCollections()
 
+    # Deferred
     def principalForRecord(self):
         return self.parent.principalForRecord(self.record)
 

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -71,11 +71,11 @@
             for principal in config.AdminPrincipals
         ))
 
-        return davxml.ACL(*aces)
+        return succeed(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())
+        return self.defaultAccessControlList()
 
 class CalendarUserProxyPrincipalResource (CalDAVComplianceMixIn, PermissionsMixIn, DAVPrincipalResource, DAVFile):
     """
@@ -150,13 +150,14 @@
         return True
 
     def etag(self):
-        return None
+        return succeed(None)
 
     def deadProperties(self):
         if not hasattr(self, "_dead_properties"):
             self._dead_properties = NonePropertyStore(self)
         return self._dead_properties
 
+    # Deferred
     def writeProperty(self, property, request):
         assert isinstance(property, davxml.WebDAVElement)
 
@@ -183,7 +184,7 @@
         principals = []
         newUIDs = set()
         for uri in members:
-            principal = self.pcollection._principalForURI(uri)
+            principal = (yield self.pcollection._principalForURI(uri))
             # Invalid principals MUST result in an error.
             if principal is None or principal.principalURL() != uri:
                 raise HTTPError(StatusResponse(
@@ -205,7 +206,7 @@
         
         changedUIDs = newUIDs.symmetric_difference(oldUIDs)
         for uid in changedUIDs:
-            principal = self.pcollection.principalForUID(uid)
+            principal = (yield self.pcollection.principalForUID(uid))
             if principal:
                 yield principal.cacheNotifier.changed()
             
@@ -306,7 +307,7 @@
         if uid not in uids:
             from twistedcaldav.directory.principal import DirectoryPrincipalResource
             uids.add(uid)
-            principal = self.pcollection.principalForUID(uid)
+            principal = (yield self.pcollection.principalForUID(uid))
             if isinstance(principal, CalendarUserProxyPrincipalResource):
                 members = yield self._directGroupMembers()
                 for member in members:
@@ -330,7 +331,7 @@
         found = []
         missing = []
         for uid in members:
-            p = self.pcollection.principalForUID(uid)
+            p = (yield self.pcollection.principalForUID(uid))
             if p:
                 found.append(p)
                 # Make sure any outstanding deletion timer entries for
@@ -343,8 +344,7 @@
         for uid in missing:
             cacheTimeout = config.DirectoryService.params.get("cacheTimeout", 30) * 60 # in seconds
 
-            yield self._index().removePrincipal(uid,
-                delay=cacheTimeout*2)
+            yield self._index().removePrincipal(uid, delay=cacheTimeout*2)
 
         returnValue(found)
 
@@ -358,7 +358,7 @@
     def groupMemberships(self):
         # Get membership UIDs and map to principal resources
         memberships = yield self._index().getMemberships(self.uid)
-        returnValue([p for p in [self.pcollection.principalForUID(uid) for uid in memberships] if p])
+        returnValue([p for p in [(yield self.pcollection.principalForUID(uid)) for uid in memberships] if p])
 
 class CalendarUserProxyDatabase(AbstractSQLDatabase, LoggingMixIn):
     """

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/directory.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/directory.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -35,7 +35,7 @@
 from twisted.cred.error import UnauthorizedLogin
 from twisted.cred.checkers import ICredentialsChecker
 from twisted.web2.dav.auth import IPrincipalCredentials
-from twisted.internet.defer import succeed, maybeDeferred
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed, maybeDeferred
 
 from twistedcaldav.log import LoggingMixIn
 from twistedcaldav.directory.idirectory import IDirectoryService, IDirectoryRecord
@@ -130,35 +130,36 @@
     def recordWithUID(self, uid):
         for record in self.allRecords():
             if record.uid == uid:
-                return record
-        return None
+                return succeed(record)
+        return succeed(None)
 
     def recordWithGUID(self, guid):
         for record in self.allRecords():
             if record.guid == guid:
-                return record
-        return None
+                return succeed(record)
+        return succeed(None)
 
     def recordWithAuthID(self, authID):
         for record in self.allRecords():
             if authID in record.authIDs:
-                return record
-        return None
+                return succeed(record)
+        return succeed(None)
 
+    @inlineCallbacks
     def recordWithCalendarUserAddress(self, address):
         address = normalizeCUAddr(address)
         record = None
         if address.startswith("urn:uuid:"):
             guid = address[9:]
-            record = self.recordWithGUID(guid)
+            record = (yield self.recordWithGUID(guid))
         elif address.startswith("mailto:"):
             for record in self.allRecords():
                 if address in record.calendarUserAddresses:
                     break
             else:
-                return None
+                returnValue(None)
 
-        return record if record and record.enabledForCalendaring else None
+        returnValue(record if record and record.enabledForCalendaring else None)
 
     def allRecords(self):
         for recordType in self.recordTypes():
@@ -251,7 +252,7 @@
         return succeed(yieldMatches(recordType))
 
     def getResourceInfo(self):
-        return ()
+        return succeed(())
 
     def isAvailable(self):
         return True
@@ -362,13 +363,13 @@
         return h
 
     def members(self):
-        return ()
+        return succeed(())
 
     def groups(self):
-        return ()
+        return succeed(())
 
     def verifyCredentials(self, credentials):
-        return False
+        return succeed(False)
 
     # Mapping from directory record.recordType to RFC2445 CUTYPE values
     _cuTypes = {

Deleted: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldappleopendirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldappleopendirectory.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldappleopendirectory.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -1,1176 +0,0 @@
-##
-# Copyright (c) 2006-2009 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.
-##
-
-"""
-Apple Open Directory directory service implementation.
-"""
-
-__all__ = [
-    "OpenDirectoryService",
-    "OpenDirectoryInitError",
-]
-
-import sys
-from random import random
-from uuid import UUID
-
-from xml.parsers.expat import ExpatError
-
-import opendirectory
-import dsattributes
-import dsquery
-
-from twisted.internet.reactor import callLater
-from twisted.internet.threads import deferToThread
-from twisted.cred.credentials import UsernamePassword
-from twisted.web2.auth.digest import DigestedCredentials
-
-from twext.python.plistlib import readPlistFromString
-
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.directory import DirectoryError, UnknownRecordTypeError
-from twistedcaldav.directory.principal import cuAddressConverter
-from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
-
-class OpenDirectoryService(DirectoryService):
-    """
-    Open Directory implementation of L{IDirectoryService}.
-    """
-    baseGUID = "891F8321-ED02-424C-BA72-89C32F215C1E"
-
-    def __repr__(self):
-        return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.node)
-
-    def __init__(
-        self,
-        node="/Search",
-        restrictEnabledRecords=False,
-        restrictToGroup="",
-        dosetup=True,
-        cacheTimeout=30
-    ):
-        """
-        @param node: an OpenDirectory node name to bind to.
-        @param restrictEnabledRecords: C{True} if a group in the directory is to be used to determine
-            which calendar users are enabled.
-        @param restrictToGroup: C{str} guid or name of group used to restrict enabled users.
-        @param dosetup: if C{True} then the directory records are initialized,
-                        if C{False} they are not.
-                        This should only be set to C{False} when doing unit tests.
-        @param cacheTimeout: C{int} number of minutes before cache is invalidated.
-        """
-        try:
-            directory = opendirectory.odInit(node)
-        except opendirectory.ODError, e:
-            self.log_error("Open Directory (node=%s) Initialization error: %s" % (node, e))
-            raise
-
-        self.realmName = node
-        self.directory = directory
-        self.node = node
-        self.restrictEnabledRecords = restrictEnabledRecords
-        self.restrictToGroup = restrictToGroup
-        try:
-            UUID(self.restrictToGroup)
-        except:
-            self.restrictToGUID = False
-        else:
-            self.restrictToGUID = True
-        self.restrictedGUIDs = None
-        self.cacheTimeout = cacheTimeout
-        self._records = {}
-        self._delayedCalls = set()
-
-        if dosetup:
-            for recordType in self.recordTypes():
-                self.recordsForType(recordType)
-
-    def __cmp__(self, other):
-        if not isinstance(other, DirectoryRecord):
-            return super(DirectoryRecord, self).__eq__(other)
-
-        for attr in ("directory", "node"):
-            diff = cmp(getattr(self, attr), getattr(other, attr))
-            if diff != 0:
-                return diff
-        return 0
-
-    def __hash__(self):
-        h = hash(self.__class__)
-        for attr in ("directory", "node"):
-            h = (h + hash(getattr(self, attr))) & sys.maxint
-        return h
-
-    def _expandGroupMembership(self, members, nestedGroups, processedGUIDs=None, returnGroups=False):
-
-        if processedGUIDs is None:
-            processedGUIDs = set()
-
-        if isinstance(members, str):
-            members = [members]
-
-        if isinstance(nestedGroups, str):
-            nestedGroups = [nestedGroups]
-
-        for memberGUID in members:
-            if memberGUID not in processedGUIDs:
-                processedGUIDs.add(memberGUID)
-                yield memberGUID
-
-        for groupGUID in nestedGroups:
-            if groupGUID in processedGUIDs:
-                continue
-
-            self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
-                self.directory,
-                dsattributes.kDS1AttrGeneratedUID,
-                groupGUID,
-                dsattributes.eDSExact,
-                False,
-                dsattributes.kDSStdRecordTypeGroups,
-                [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
-            ))
-            result = opendirectory.queryRecordsWithAttribute_list(
-                self.directory,
-                dsattributes.kDS1AttrGeneratedUID,
-                groupGUID,
-                dsattributes.eDSExact,
-                False,
-                dsattributes.kDSStdRecordTypeGroups,
-                [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
-            )
-
-            if not result:
-                self.log_error("Couldn't find group %s when trying to expand nested groups."
-                             % (groupGUID,))
-                continue
-
-            group = result[0][1]
-
-            processedGUIDs.add(groupGUID)
-            if returnGroups:
-                yield groupGUID
-
-            for GUID in self._expandGroupMembership(
-                group.get(dsattributes.kDSNAttrGroupMembers, []),
-                group.get(dsattributes.kDSNAttrNestedGroups, []),
-                processedGUIDs,
-                returnGroups,
-            ):
-                yield GUID
-
-    def _calendarUserAddresses(self, recordType, recordData):
-        """
-        Extract specific attributes from the directory record for use as calendar user address.
-        
-        @param recordData: a C{dict} containing the attributes retrieved from the directory.
-        @return: a C{set} of C{str} for each expanded calendar user address.
-        """
-        # Now get the addresses
-        result = set()
-        
-        # Add each email address as a mailto URI
-        emails = recordData.get(dsattributes.kDSNAttrEMailAddress)
-        if emails is not None:
-            if isinstance(emails, str):
-                emails = [emails]
-            for email in emails:
-                result.add("mailto:%s" % (email.lower(),))
-                
-        return result
-
-    def _parseResourceInfo(self, plist, guid, recordType, shortname):
-        """
-        Parse OD ResourceInfo attribute and extract information that the server needs.
-
-        @param plist: the plist that is the attribute value.
-        @type plist: str
-        @param guid: the directory GUID of the record being parsed.
-        @type guid: str
-        @param shortname: the record shortname of the record being parsed.
-        @type shortname: str
-        @return: a C{tuple} of C{bool} for auto-accept, C{str} for proxy GUID, C{str} for read-only proxy GUID.
-        """
-        try:
-            plist = readPlistFromString(plist)
-            wpframework = plist.get("com.apple.WhitePagesFramework", {})
-            autoaccept = wpframework.get("AutoAcceptsInvitation", False)
-            proxy = wpframework.get("CalendaringDelegate", None)
-            read_only_proxy = wpframework.get("ReadOnlyCalendaringDelegate", None)
-        except (ExpatError, AttributeError), e:
-            self.log_error(
-                "Failed to parse ResourceInfo attribute of record (%s)%s (guid=%s): %s\n%s" %
-                (recordType, shortname, guid, e, plist,)
-            )
-            raise ValueError("Invalid ResourceInfo")
-
-        return (autoaccept, proxy, read_only_proxy,)
-
-    def recordTypes(self):
-        return (
-            self.recordType_users,
-            self.recordType_groups,
-            self.recordType_locations,
-            self.recordType_resources,
-        )
-
-    def _storage(self, recordType):
-        try:
-            storage = self._records[recordType]
-        except KeyError:
-            self.reloadCache(recordType)
-            storage = self._records[recordType]
-        else:
-            if storage["status"] == "stale":
-                storage["status"] = "loading"
-
-                def onError(f):
-                    storage["status"] = "stale" # Keep trying
-                    self.log_error(
-                        "Unable to load records of type %s from OpenDirectory due to unexpected error: %s"
-                        % (recordType, f)
-                    )
-
-                # Reload the restricted access group details if reloading user records
-                if recordType == self.recordType_users:
-                    self.restrictedGUIDs = None
-
-                d = deferToThread(self.reloadCache, recordType)
-                d.addErrback(onError)
-
-        return storage
-
-    def recordsForType(self, recordType):
-        """
-        @param recordType: a record type
-        @return: a dictionary containing all records for the given record
-        type.  Keys are short names and values are the corresponding
-        OpenDirectoryRecord for the given record type.
-        """
-        return self._storage(recordType)["records"]
-
-    def listRecords(self, recordType):
-        return self.recordsForType(recordType).itervalues()
-
-    def recordWithShortName(self, recordType, shortName):
-        try:
-            return self.recordsForType(recordType)[shortName]
-        except KeyError:
-            # Check negative cache
-            if shortName in self._storage(recordType)["disabled names"]:
-                return None
-
-            # Cache miss; try looking the record up, in case it is new
-            # FIXME: This is a blocking call (hopefully it's a fast one)
-            self.reloadCache(recordType, lookup=("shortName", shortName,))
-            record = self.recordsForType(recordType).get(shortName, None)
-            if record is None:
-                # Add to negative cache
-                self._storage(recordType)["disabled names"].add(shortName)
-            return record
-
-    def recordWithCalendarUserAddress(self, address):
-        address = normalizeCUAddr(address)
-        record = None
-        if address.startswith("urn:uuid:"):
-            guid = address[9:]
-            record = self.recordWithGUID(guid)
-        elif address.startswith("mailto:"):
-            record = self._recordWithAttribute("cuas", "disabled cuas", "cua", address)
-
-        return record if record and record.enabledForCalendaring else None
-
-    def recordWithGUID(self, guid):
-        return self._recordWithAttribute("guids", "disabled guids", "guid", guid)
-
-    recordWithUID = recordWithGUID
-
-    def recordWithAuthID(self, authID):
-        return self._recordWithAttribute("authIDs", "disabled authIDs", "authID", authID)
-
-    def _recordWithAttribute(self, cacheKey, disabledKey, lookupKey, value):
-        def lookup():
-            for recordType in self.recordTypes():
-                record = self._storage(recordType)[cacheKey].get(value, None)
-                if record:
-                    return record
-            else:
-                return None
-
-        record = lookup()
-
-        if record is None:
-            # Cache miss; try looking the record up, in case it is new
-            for recordType in self.recordTypes():
-                # Check negative cache
-                if value in self._storage(recordType)[disabledKey]:
-                    continue
-
-                try:
-                    self.reloadCache(recordType, lookup=(lookupKey, value,))
-                    record = lookup()
-                except opendirectory.ODError, e:
-                    if e.message[1] == -14140 or e.message[1] == -14200:
-                        # Unsupported attribute on record - don't fail
-                        record = None
-                    else:
-                        raise
-
-                if record is None:
-                    self._storage(recordType)[disabledKey].add(value)
-                else:
-                    self.log_info("Faulted record with %s %s into %s record cache"
-                                  % (lookupKey, value, recordType))
-                    break
-            else:
-                # Nothing found; add to negative cache
-                self.log_info("Unable to find any record with %s %s" % (lookupKey, value,))
-
-        return record
-
-    def groupsForGUID(self, guid):
-        
-        # Lookup in index
-        try:
-            return self._storage(self.recordType_groups)["groupsForGUID"][guid]
-        except KeyError:
-            return ()
-
-    def proxiesForGUID(self, recordType, guid):
-        
-        # Lookup in index
-        try:
-            return self._storage(recordType)["proxiesForGUID"][guid]
-        except KeyError:
-            return ()
-
-    def readOnlyProxiesForGUID(self, recordType, guid):
-        
-        # Lookup in index
-        try:
-            return self._storage(recordType)["readOnlyProxiesForGUID"][guid]
-        except KeyError:
-            return ()
-
-    def _indexGroup(self, group, guids, index):
-        for guid in guids:
-            index.setdefault(guid, set()).add(group)
-
-    _ODFields = {
-        'fullName' : {
-            'odField' : dsattributes.kDS1AttrDistinguishedName,
-            'appliesTo' : set([
-                dsattributes.kDSStdRecordTypeUsers,
-                dsattributes.kDSStdRecordTypeGroups,
-                dsattributes.kDSStdRecordTypePlaces,
-                dsattributes.kDSStdRecordTypeResources,
-            ]),
-        },
-        'firstName' : {
-            'odField' : dsattributes.kDS1AttrFirstName,
-            'appliesTo' : set([
-                dsattributes.kDSStdRecordTypeUsers,
-            ]),
-        },
-        'lastName' : {
-            'odField' : dsattributes.kDS1AttrLastName,
-            'appliesTo' : set([
-                dsattributes.kDSStdRecordTypeUsers,
-            ]),
-        },
-        'emailAddresses' : {
-            'odField' : dsattributes.kDSNAttrEMailAddress,
-            'appliesTo' : set([
-                dsattributes.kDSStdRecordTypeUsers,
-                dsattributes.kDSStdRecordTypeGroups,
-            ]),
-        },
-        'recordName' : {
-            'odField' : dsattributes.kDSNAttrRecordName,
-            'appliesTo' : set([
-                dsattributes.kDSStdRecordTypeUsers,
-                dsattributes.kDSStdRecordTypeGroups,
-                dsattributes.kDSStdRecordTypePlaces,
-                dsattributes.kDSStdRecordTypeResources,
-            ]),
-        },
-        'guid' : {
-            'odField' : dsattributes.kDS1AttrGeneratedUID,
-            'appliesTo' : set([
-                dsattributes.kDSStdRecordTypeUsers,
-                dsattributes.kDSStdRecordTypeGroups,
-                dsattributes.kDSStdRecordTypePlaces,
-                dsattributes.kDSStdRecordTypeResources,
-            ]),
-        },
-    }
-
-    _toODRecordTypes = {
-        DirectoryService.recordType_users :
-            dsattributes.kDSStdRecordTypeUsers,
-        DirectoryService.recordType_locations :
-            dsattributes.kDSStdRecordTypePlaces,
-        DirectoryService.recordType_groups :
-            dsattributes.kDSStdRecordTypeGroups,
-        DirectoryService.recordType_resources :
-            dsattributes.kDSStdRecordTypeResources,
-    }
-
-    _fromODRecordTypes = dict([(b, a) for a, b in _toODRecordTypes.iteritems()])
-
-
-    def recordsMatchingFields(self, fields, operand="or", recordType=None):
-
-        # Note that OD applies case-sensitivity globally across the entire
-        # query, not per expression, so the current code uses whatever is
-        # specified in the last field in the fields list
-
-        def collectResults(results):
-            self.log_info("Got back %d records from OD" % (len(results),))
-            for key, val in results.iteritems():
-                self.log_debug("OD result: %s %s" % (key, val))
-                try:
-                    guid = val[dsattributes.kDS1AttrGeneratedUID]
-                    record = self.recordWithGUID(guid)
-                    if record:
-                        yield record
-                except KeyError:
-                    pass
-
-        def multiQuery(directory, queries, attrs, operand):
-            results = {}
-
-            for query, recordTypes in queries.iteritems():
-                if not query:
-                    continue
-
-                expressions = []
-                for ODField, value, caseless, matchType in query:
-                    if matchType == "starts-with":
-                        comparison = dsattributes.eDSStartsWith
-                    elif matchType == "contains":
-                        comparison = dsattributes.eDSContains
-                    else:
-                        comparison = dsattributes.eDSExact
-                    expressions.append(dsquery.match(ODField, value, comparison))
-
-                complexExpression = dsquery.expression(operand, expressions).generate()
-
-                self.log_info("Calling OD: Types %s, Operand %s, Caseless %s, %s" %
-                    (recordTypes, operand, caseless, complexExpression))
-
-                results.update(
-                    opendirectory.queryRecordsWithAttributes(
-                        directory,
-                        complexExpression,
-                        caseless,
-                        recordTypes,
-                        attrs,
-                    )
-                )
-
-            return results
-
-
-        operand = (dsquery.expression.OR if operand == "or"
-            else dsquery.expression.AND)
-
-        if recordType is None:
-            # The client is looking for records in any of the four types
-            recordTypes = set(self._toODRecordTypes.values())
-        else:
-            # The client is after only one recordType
-            recordTypes = [self._toODRecordTypes[recordType]]
-
-        queries = buildQueries(recordTypes, fields, self._ODFields)
-
-        deferred = deferToThread(
-            multiQuery,
-            self.directory,
-            queries,
-            [ dsattributes.kDS1AttrGeneratedUID ],
-            operand
-        )
-        deferred.addCallback(collectResults)
-        return deferred
-
-
-    def reloadCache(self, recordType, lookup=None):
-        if lookup is not None:
-            self.log_info("Faulting record with %s %s into %s record cache" % (lookup[0], lookup[1], recordType))
-        else:
-            self.log_info("Reloading %s record cache" % (recordType,))
-
-        results = self._queryDirectory(recordType, lookup=lookup)
-
-        if lookup is None:
-            records = {}
-            guids   = {}
-            authIDs = {}
-            cuas  = {}
-
-            disabledNames   = set()
-            disabledGUIDs   = set()
-            disabledAuthIDs = set()
-            disabledCUAs    = set()
-
-            if recordType == self.recordType_groups:
-                groupsForGUID = {}
-            elif recordType in (self.recordType_resources, self.recordType_locations):
-                proxiesForGUID = {}
-                readOnlyProxiesForGUID = {}
-        else:
-            storage = self._records[recordType]
-
-            records = storage["records"]
-            guids   = storage["guids"]
-            authIDs = storage["authIDs"]
-            cuas    = storage["cuas"]
-
-            disabledNames   = storage["disabled names"]
-            disabledGUIDs   = storage["disabled guids"]
-            disabledAuthIDs = storage["disabled authIDs"]
-            disabledCUAs    = storage["disabled cuas"]
-
-            if recordType == self.recordType_groups:
-                groupsForGUID = storage["groupsForGUID"]
-            elif recordType in (self.recordType_resources, self.recordType_locations):
-                proxiesForGUID = storage["proxiesForGUID"]
-                readOnlyProxiesForGUID = storage["readOnlyProxiesForGUID"]
-
-        enabled_count = 0
-        
-        def _uniqueTupleFromAttribute(attribute):
-            if attribute:
-                if isinstance(attribute, str):
-                    return (attribute,)
-                else:
-                    s = set()
-                    return tuple([(s.add(x), x)[1] for x in attribute if x not in s])
-            else:
-                return ()
-            
-        def _setFromAttribute(attribute, lower=False):
-            if attribute:
-                if isinstance(attribute, str):
-                    return set((attribute.lower() if lower else attribute,))
-                else:
-                    return set([item.lower() if lower else item for item in attribute])
-            else:
-                return ()
-            
-        for (recordShortName, value) in results:
-
-            # Now get useful record info.
-            recordGUID           = value.get(dsattributes.kDS1AttrGeneratedUID)
-            recordShortNames     = _uniqueTupleFromAttribute(value.get(dsattributes.kDSNAttrRecordName))
-            recordAuthIDs        = _setFromAttribute(value.get(dsattributes.kDSNAttrAltSecurityIdentities))
-            recordFullName       = value.get(dsattributes.kDS1AttrDistinguishedName)
-            recordFirstName      = value.get(dsattributes.kDS1AttrFirstName)
-            recordLastName       = value.get(dsattributes.kDS1AttrLastName)
-            recordEmailAddresses = _setFromAttribute(value.get(dsattributes.kDSNAttrEMailAddress), lower=True)
-            recordNodeName       = value.get(dsattributes.kDSNAttrMetaNodeLocation)
-
-            if not recordGUID:
-                self.log_debug("Record (%s)%s in node %s has no GUID; ignoring."
-                               % (recordType, recordShortName, recordNodeName))
-                continue
-
-            if recordGUID.lower().startswith("ffffeeee-dddd-cccc-bbbb-aaaa"):
-                self.log_debug("Ignoring system record (%s)%s in node %s."
-                               % (recordType, recordShortName, recordNodeName))
-                continue
-
-            # Determine enabled state
-            if recordType == self.recordType_groups:
-                enabledForCalendaring = False
-            else:
-                if self.restrictEnabledRecords and self.restrictedGUIDs is not None:
-                    enabledForCalendaring = recordGUID in self.restrictedGUIDs
-                else:
-                    enabledForCalendaring = True
-
-            if enabledForCalendaring:
-                enabled_count += 1
-                calendarUserAddresses = self._calendarUserAddresses(recordType, value)
-            else:
-                # Some records we want to keep even though they are not enabled for calendaring.
-                # Others we discard.
-                if recordType not in (
-                    self.recordType_users,
-                    self.recordType_groups,
-                ):
-                    self.log_debug(
-                        "Record (%s) %s is not enabled for calendaring"
-                        % (recordType, recordShortName)
-                    )
-                    continue
-
-                self.log_debug(
-                    "Record (%s) %s is not enabled for calendaring but may be used in ACLs"
-                    % (recordType, recordShortName)
-                )
-                calendarUserAddresses = ()
-
-            # Special case for groups, which have members.
-            if recordType == self.recordType_groups:
-                memberGUIDs = value.get(dsattributes.kDSNAttrGroupMembers)
-                if memberGUIDs is None:
-                    memberGUIDs = ()
-                elif type(memberGUIDs) is str:
-                    memberGUIDs = (memberGUIDs,)
-                nestedGUIDs = value.get(dsattributes.kDSNAttrNestedGroups)
-                if nestedGUIDs:
-                    if type(nestedGUIDs) is str:
-                        nestedGUIDs = (nestedGUIDs,)
-                    memberGUIDs += tuple(nestedGUIDs)
-            else:
-                memberGUIDs = ()
-
-            record = OpenDirectoryRecord(
-                service               = self,
-                recordType            = recordType,
-                guid                  = recordGUID,
-                nodeName              = recordNodeName,
-                shortNames            = recordShortNames,
-                authIDs               = recordAuthIDs,
-                fullName              = recordFullName,
-                firstName             = recordFirstName,
-                lastName              = recordLastName,
-                emailAddresses        = recordEmailAddresses,
-                calendarUserAddresses = calendarUserAddresses,
-                enabledForCalendaring = enabledForCalendaring,
-                memberGUIDs           = memberGUIDs,
-            )
-
-            def disableGUID(guid, record):
-                """
-                Disable the record by removing it from all indexes.
-                """
-
-                self.log_warn("GUID %s disabled due to conflict for record: %s"
-                              % (guid, record))
-
-                disabledGUIDs.add(guid)
-                disabledNames.update(record.shortNames)
-                disabledAuthIDs.update(record.authIDs)
-                disabledCUAs.update(record.calendarUserAddresses)
-
-                if guid in guids:
-                    try:
-                        del guids[guid]
-                    except KeyError:
-                        pass
-                for shortName in record.shortNames:
-                    try:
-                        del records[shortName]
-                    except KeyError:
-                        pass
-                for authID in record.authIDs:
-                    try:
-                        del authIDs[authID]
-                    except KeyError:
-                        pass
-                for cua in record.calendarUserAddresses:
-                    try:
-                        del cuas[cua]
-                    except KeyError:
-                        pass
-
-            if record.guid in disabledGUIDs:
-                disableGUID(record.guid, record)
-            else:
-                # Check for duplicates
-                existing_record = guids.get(record.guid)
-                if existing_record is not None:
-                    if existing_record.shortNames != record.shortNames:
-                        disableGUID(record.guid, record)
-                        disableGUID(record.guid, existing_record)
-                        if existing_record.enabledForCalendaring:
-                            enabled_count -= 1
-                else:
-                    guids[record.guid] = record
-                    self.log_debug("Added record %s to OD record cache" % (record,))
-                    if record.enabledForCalendaring:
-                        enabled_count += 1
-        
-                    # Do group indexing if needed
-                    if recordType == self.recordType_groups:
-                        self._indexGroup(record, record._memberGUIDs, groupsForGUID)
-
-                    # Index non-duplicate shortNames
-                    def disableName(shortName, record):
-                        self.log_warn("Short name %s disabled due to conflict for record: %s"
-                                      % (shortName, record))
-        
-                        record.shortNames = tuple([item for item in record.shortNames if item != shortName])
-                        disabledNames.add(shortName)
-        
-                        if shortName in records:
-                            del records[shortName]
-        
-                    for shortName in tuple(record.shortNames):
-                        if shortName in disabledNames:
-                            disableName(shortName, record)
-                        else:
-                            # Check for duplicates
-                            existing_record = records.get(shortName)
-                            if existing_record is not None and existing_record != record:
-                                disableName(shortName, record)
-                                disableName(shortName, existing_record)
-                            else:
-                                records[shortName] = record
-        
-                    # Index non-duplicate authIDs
-                    def disableAuthIDs(authID, record):
-                        self.log_warn("Auth ID %s disabled due to conflict for record: %s"
-                                      % (authID, record))
-        
-                        record.authIDs.remove(authID)
-                        disabledAuthIDs.add(authID)
-        
-                        if authID in authIDs:
-                            del authIDs[authID]
-        
-                    for authID in frozenset(recordAuthIDs):
-                        if authID in disabledAuthIDs:
-                            disableAuthIDs(authID, record)
-                        else:
-                            # Check for duplicates
-                            existing_record = authIDs.get(authID)
-                            if existing_record is not None:
-                                disableAuthIDs(authID, record)
-                                disableAuthIDs(authID, existing_record)
-                            else:
-                                authIDs[authID] = record
-        
-                    # Index non-duplicate CUAs
-                    def disableCUA(cua, record):
-                        self.log_warn("CUA %s disabled due to conflict for record: %s"
-                                      % (cua, record))
-        
-                        record.calendarUserAddresses.remove(cua)
-                        disabledCUAs.add(cua)
-        
-                        if cua in cuas:
-                            del cuas[cua]
-
-                        if cua in records:
-                            del records[cua]
-        
-                    for cua in frozenset(calendarUserAddresses):
-                        if cua in disabledCUAs:
-                            disableCUA(cua, record)
-                        else:
-                            # Check for duplicates
-                            existing_record = cuas.get(cua)
-                            if existing_record is not None:
-                                disableCUA(cua, record)
-                                disableCUA(cua, existing_record)
-                            else:
-                                cuas[cua] = record
-
-        if lookup is None:
-            #
-            # Replace the entire cache
-            #
-            storage = {
-                "status"           : "new",
-                "records"          : records,
-                "guids"            : guids,
-                "authIDs"          : authIDs,
-                "cuas"             : cuas,
-                "disabled names"   : disabledNames,
-                "disabled guids"   : disabledGUIDs,
-                "disabled authIDs" : disabledAuthIDs,
-                "disabled cuas"    : disabledCUAs,
-            }
-
-            # Add group indexing if needed
-            if recordType == self.recordType_groups:
-                storage["groupsForGUID"] = groupsForGUID
-
-            # Add proxy indexing if needed
-            elif recordType in (self.recordType_resources, self.recordType_locations):
-                storage["proxiesForGUID"] = proxiesForGUID
-                storage["readOnlyProxiesForGUID"] = readOnlyProxiesForGUID
-
-            def rot():
-                storage["status"] = "stale"
-                removals = set()
-                for call in self._delayedCalls:
-                    if not call.active():
-                        removals.add(call)
-                for item in removals:
-                    self._delayedCalls.remove(item)
-
-            #
-            # Add jitter/fuzz factor to avoid stampede for large OD query
-            # Max out the jitter at 60 minutes
-            #
-            cacheTimeout = min(self.cacheTimeout, 60) * 60
-            cacheTimeout = (cacheTimeout * random()) - (cacheTimeout / 2)
-            cacheTimeout += self.cacheTimeout * 60
-            self._delayedCalls.add(callLater(cacheTimeout, rot))
-
-            self._records[recordType] = storage
-
-            self.log_info(
-                "Added %d (%d enabled) records to %s OD record cache; expires in %d seconds"
-                % (len(self._records[recordType]["guids"]), enabled_count, recordType, cacheTimeout)
-            )
-
-    def _queryDirectory(self, recordType, lookup=None):
-        attrs = [
-            dsattributes.kDS1AttrGeneratedUID,
-            dsattributes.kDSNAttrRecordName,
-            dsattributes.kDSNAttrAltSecurityIdentities,
-            dsattributes.kDS1AttrDistinguishedName,
-            dsattributes.kDS1AttrFirstName,
-            dsattributes.kDS1AttrLastName,
-            dsattributes.kDSNAttrEMailAddress,
-            dsattributes.kDSNAttrMetaNodeLocation,
-        ]
-
-        if recordType == self.recordType_users:
-            listRecordType = dsattributes.kDSStdRecordTypeUsers
-
-        elif recordType == self.recordType_groups:
-            listRecordType = dsattributes.kDSStdRecordTypeGroups
-            attrs.append(dsattributes.kDSNAttrGroupMembers)
-            attrs.append(dsattributes.kDSNAttrNestedGroups)
-
-        elif recordType == self.recordType_locations:
-            listRecordType = dsattributes.kDSStdRecordTypePlaces
-            attrs.append(dsattributes.kDSNAttrResourceInfo)
-        
-        elif recordType == self.recordType_resources:
-            listRecordType = dsattributes.kDSStdRecordTypeResources
-            attrs.append(dsattributes.kDSNAttrResourceInfo)
-        
-        else:
-            raise UnknownRecordTypeError("Unknown Open Directory record type: %s" % (recordType))
-
-        # If restricting enabled records, then make sure the restricted group member
-        # details are loaded. Do nested group expansion and include the nested groups
-        # as enabled records too.
-        if self.restrictEnabledRecords and self.restrictedGUIDs is None:
-
-            attributeToMatch = dsattributes.kDS1AttrGeneratedUID if self.restrictToGUID else dsattributes.kDSNAttrRecordName 
-            valueToMatch = self.restrictToGroup
-
-            self.log_debug("Doing restricted group membership check")
-            self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
-                self.directory,
-                attributeToMatch,
-                valueToMatch,
-                dsattributes.eDSExact,
-                False,
-                dsattributes.kDSStdRecordTypeGroups,
-                [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups,],
-            ))
-            results = opendirectory.queryRecordsWithAttribute_list(
-                self.directory,
-                attributeToMatch,
-                valueToMatch,
-                dsattributes.eDSExact,
-                False,
-                dsattributes.kDSStdRecordTypeGroups,
-                [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups,],
-            )
-    
-            if len(results) == 1:
-                members      = results[0][1].get(dsattributes.kDSNAttrGroupMembers, [])
-                nestedGroups = results[0][1].get(dsattributes.kDSNAttrNestedGroups, [])
-            else:
-                members = []
-                nestedGroups = []
-
-            self.restrictedGUIDs = set(self._expandGroupMembership(members, nestedGroups, returnGroups=True))
-            self.log_debug("Got %d restricted group members" % (len(self.restrictedGUIDs),))
-
-        query = None
-        if lookup is not None:
-            indexType, indexKey = lookup
-            origIndexKey = indexKey
-
-            if indexType == "cua":
-                # The directory doesn't contain CUAs, so we need to convert
-                # the CUA to the appropriate field name and value:
-                queryattr, indexKey = cuAddressConverter(indexKey)
-                # queryattr will be one of:
-                # guid, emailAddresses, or recordName
-                # ...which will need to be mapped to DS
-                queryattr = self._ODFields[queryattr]['odField']
-
-            else:
-                queryattr = {
-                    "shortName" : dsattributes.kDSNAttrRecordName,
-                    "guid"      : dsattributes.kDS1AttrGeneratedUID,
-                    "authID"    : dsattributes.kDSNAttrAltSecurityIdentities,
-                }.get(indexType)
-                assert queryattr is not None, "Invalid type for record faulting query"
-
-            query = dsquery.match(queryattr, indexKey, dsattributes.eDSExact)
-
-        try:
-            if query:
-                self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
-                    self.directory,
-                    query.attribute,
-                    query.value,
-                    query.matchType,
-                    False,
-                    listRecordType,
-                    attrs,
-                ))
-                results = opendirectory.queryRecordsWithAttribute_list(
-                    self.directory,
-                    query.attribute,
-                    query.value,
-                    query.matchType,
-                    False,
-                    listRecordType,
-                    attrs,
-                )
-            else:
-                self.log_debug("opendirectory.listAllRecordsWithAttributes_list(%r,%r,%r)" % (
-                    self.directory,
-                    listRecordType,
-                    attrs,
-                ))
-                results = opendirectory.listAllRecordsWithAttributes_list(
-                    self.directory,
-                    listRecordType,
-                    attrs,
-                )
-        except opendirectory.ODError, ex:
-            self.log_error("Open Directory (node=%s) error: %s" % (self.realmName, str(ex)))
-            raise
-
-        return results
-
-    def getResourceInfo(self):
-        """
-        Resource information including proxy assignments for resource and
-        locations, as well as auto-schedule settings, used to live in the
-        directory.  This method fetches old resource info for migration
-        purposes.
-        """
-        attrs = [
-            dsattributes.kDS1AttrGeneratedUID,
-            dsattributes.kDSNAttrResourceInfo,
-        ]
-
-        for recordType in (dsattributes.kDSStdRecordTypePlaces, dsattributes.kDSStdRecordTypeResources):
-            try:
-                self.log_debug("opendirectory.listAllRecordsWithAttributes_list(%r,%r,%r)" % (
-                    self.directory,
-                    recordType,
-                    attrs,
-                ))
-                results = opendirectory.listAllRecordsWithAttributes_list(
-                    self.directory,
-                    recordType,
-                    attrs,
-                )
-            except opendirectory.ODError, ex:
-                self.log_error("Open Directory (node=%s) error: %s" % (self.realmName, str(ex)))
-                raise
-
-            for (recordShortName, value) in results:
-                recordGUID = value.get(dsattributes.kDS1AttrGeneratedUID)
-                resourceInfo = value.get(dsattributes.kDSNAttrResourceInfo)
-                if resourceInfo is not None:
-                    try:
-                        autoSchedule, proxy, readOnlyProxy = self._parseResourceInfo(resourceInfo,
-                            recordGUID, recordType, recordShortName)
-                    except ValueError:
-                        continue
-                    yield recordGUID, autoSchedule, proxy, readOnlyProxy
-
-
-def buildQueries(recordTypes, fields, mapping):
-    """
-    Determine how many queries need to be performed in order to work around opendirectory
-    quirks, where searching on fields that don't apply to a given recordType returns incorrect
-    results (either none, or all records).
-    """
-
-    fieldLists = {}
-    for recordType in recordTypes:
-        fieldLists[recordType] = []
-        for field, value, caseless, matchType in fields:
-            if field in mapping:
-                if recordType in mapping[field]['appliesTo']:
-                    ODField = mapping[field]['odField']
-                    fieldLists[recordType].append((ODField, value, caseless, matchType))
-
-    queries = {}
-    for recordType, fieldList in fieldLists.iteritems():
-        key = tuple(fieldList)
-        queries.setdefault(key, []).append(recordType)
-    return queries
-
-
-class OpenDirectoryRecord(DirectoryRecord):
-    """
-    Open Directory implementation of L{IDirectoryRecord}.
-    """
-    def __init__(
-        self, service, recordType, guid, nodeName, shortNames, authIDs, fullName,
-        firstName, lastName, emailAddresses,
-        calendarUserAddresses, enabledForCalendaring,
-        memberGUIDs,
-    ):
-        super(OpenDirectoryRecord, self).__init__(
-            service               = service,
-            recordType            = recordType,
-            guid                  = guid,
-            shortNames            = shortNames,
-            authIDs               = authIDs,
-            fullName              = fullName,
-            firstName             = firstName,
-            lastName              = lastName,
-            emailAddresses        = emailAddresses,
-            calendarUserAddresses = calendarUserAddresses,
-            enabledForCalendaring = enabledForCalendaring,
-        )
-        self.nodeName = nodeName
-        self._memberGUIDs = tuple(memberGUIDs)
-
-    def __repr__(self):
-        if self.service.realmName == self.nodeName:
-            location = self.nodeName
-        else:
-            location = "%s->%s" % (self.service.realmName, self.nodeName)
-
-        return "<%s[%s@%s(%s)] %s(%s) %r>" % (
-            self.__class__.__name__,
-            self.recordType,
-            self.service.guid,
-            location,
-            self.guid,
-            ",".join(self.shortNames),
-            self.fullName
-        )
-
-    def members(self):
-        if self.recordType != self.service.recordType_groups:
-            return
-
-        for guid in self._memberGUIDs:
-            userRecord = self.service.recordWithGUID(guid)
-            if userRecord is not None:
-                yield userRecord
-
-    def groups(self):
-        return self.service.groupsForGUID(self.guid)
-
-    def verifyCredentials(self, credentials):
-        if isinstance(credentials, UsernamePassword):
-            # Check cached password
-            try:
-                if credentials.password == self.password:
-                    return True
-            except AttributeError:
-                pass
-
-            # Check with directory services
-            try:
-                if opendirectory.authenticateUserBasic(self.service.directory, self.nodeName, self.shortNames[0], credentials.password):
-                    # Cache the password to avoid future DS queries
-                    self.password = credentials.password
-                    return True
-            except opendirectory.ODError, e:
-                self.log_error("Open Directory (node=%s) error while performing basic authentication for user %s: %s"
-                            % (self.service.realmName, self.shortNames[0], e))
-
-            return False
-
-        elif isinstance(credentials, DigestedCredentials):
-            #
-            # We need a special format for the "challenge" and "response" strings passed into open directory, as it is
-            # picky about exactly what it receives.
-            #
-            try:
-                if "algorithm" not in credentials.fields:
-                    credentials.fields["algorithm"] = "md5"
-                challenge = 'Digest realm="%(realm)s", nonce="%(nonce)s", algorithm=%(algorithm)s' % credentials.fields
-                response = (
-                    'Digest username="%(username)s", '
-                    'realm="%(realm)s", '
-                    'nonce="%(nonce)s", '
-                    'uri="%(uri)s", '
-                    'response="%(response)s",'
-                    'algorithm=%(algorithm)s'
-                ) % credentials.fields
-            except KeyError, e:
-                self.log_error(
-                    "Open Directory (node=%s) error while performing digest authentication for user %s: "
-                    "missing digest response field: %s in: %s"
-                    % (self.service.realmName, self.shortNames[0], e, credentials.fields)
-                )
-                return False
-
-            try:
-                if self.digestcache[credentials.fields["uri"]] == response:
-                    return True
-            except (AttributeError, KeyError):
-                pass
-
-            try:
-                if opendirectory.authenticateUserDigest(
-                    self.service.directory,
-                    self.nodeName,
-                    self.shortNames[0],
-                    challenge,
-                    response,
-                    credentials.originalMethod if credentials.originalMethod else credentials.method
-                ):
-                    try:
-                        cache = self.digestcache
-                    except AttributeError:
-                        cache = self.digestcache = {}
-
-                    cache[credentials.fields["uri"]] = response
-
-                    return True
-                else:
-                    self.log_debug(
-"""Open Directory digest authentication failed with:
-    Nodename:  %s
-    Username:  %s
-    Challenge: %s
-    Response:  %s
-    Method:    %s
-""" % (self.nodeName, self.shortNames[0], challenge, response, credentials.originalMethod if credentials.originalMethod else credentials.method))
-
-            except opendirectory.ODError, e:
-                self.log_error(
-                    "Open Directory (node=%s) error while performing digest authentication for user %s: %s"
-                    % (self.service.realmName, self.shortNames[0], e)
-                )
-                return False
-
-            return False
-
-        return super(OpenDirectoryRecord, self).verifyCredentials(credentials)
-
-class OpenDirectoryInitError(DirectoryError):
-    """
-    OpenDirectory initialization error.
-    """

Deleted: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldxmlfile.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldxmlfile.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldxmlfile.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -1,144 +0,0 @@
-##
-# Copyright (c) 2006-2009 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.
-##
-
-"""
-XML based user/group/resource directory service implementation.
-"""
-
-__all__ = [
-    "XMLDirectoryService",
-]
-
-from time import time
-
-from twisted.cred.credentials import UsernamePassword
-from twisted.web2.auth.digest import DigestedCredentials
-from twisted.python.filepath import FilePath
-
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.xmlaccountsparser import XMLAccountsParser
-
-class XMLDirectoryService(DirectoryService):
-    """
-    XML based implementation of L{IDirectoryService}.
-    """
-    baseGUID = "9CA8DEC5-5A17-43A9-84A8-BE77C1FB9172"
-
-    realmName = None
-
-    def __repr__(self):
-        return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.xmlFile)
-
-    def __init__(self, xmlFile, alwaysStat=False):
-        super(XMLDirectoryService, self).__init__()
-
-        if type(xmlFile) is str:
-            xmlFile = FilePath(xmlFile)
-
-        self.xmlFile = xmlFile
-        self._fileInfo = None
-        self._lastCheck = 0
-        self._alwaysStat = alwaysStat
-        self._accounts()
-
-    def recordTypes(self):
-        recordTypes = (
-            DirectoryService.recordType_users,
-            DirectoryService.recordType_groups,
-            DirectoryService.recordType_locations,
-            DirectoryService.recordType_resources
-        )
-        return recordTypes
-
-    def listRecords(self, recordType):
-        for _ignore_entryShortName, xmlPrincipal in self._entriesForRecordType(recordType):
-            yield XMLDirectoryRecord(
-                service       = self,
-                recordType    = recordType,
-                shortNames    = tuple(xmlPrincipal.shortNames),
-                xmlPrincipal  = xmlPrincipal,
-            )
-
-    def recordWithShortName(self, recordType, shortName):
-        for _ignore_entryShortName, xmlPrincipal in self._entriesForRecordType(recordType):
-            if shortName in xmlPrincipal.shortNames:
-                return XMLDirectoryRecord(
-                    service       = self,
-                    recordType    = recordType,
-                    shortNames    = tuple(xmlPrincipal.shortNames),
-                    xmlPrincipal  = xmlPrincipal,
-                )
-
-        return None
-
-    def _entriesForRecordType(self, recordType):
-        try:
-            for shortName, entry in sorted(self._accounts()[recordType].iteritems(), key=lambda x: x[0]):
-                yield shortName, entry
-        except KeyError:
-            return
-
-    def _accounts(self):
-        currentTime = time()
-        if self._alwaysStat or currentTime - self._lastCheck > 60:
-            self.xmlFile.restat()
-            self._lastCheck = currentTime
-            fileInfo = (self.xmlFile.getmtime(), self.xmlFile.getsize())
-            if fileInfo != self._fileInfo:
-                parser = XMLAccountsParser(self.xmlFile)
-                self._parsedAccounts = parser.items
-                self.realmName = parser.realm
-                self._fileInfo = fileInfo
-        return self._parsedAccounts
-
-
-class XMLDirectoryRecord(DirectoryRecord):
-    """
-    XML based implementation implementation of L{IDirectoryRecord}.
-    """
-    def __init__(self, service, recordType, shortNames, xmlPrincipal):
-        super(XMLDirectoryRecord, self).__init__(
-            service               = service,
-            recordType            = recordType,
-            guid                  = xmlPrincipal.guid,
-            shortNames            = shortNames,
-            fullName              = xmlPrincipal.fullName,
-            firstName             = xmlPrincipal.firstName,
-            lastName              = xmlPrincipal.lastName,
-            emailAddresses        = xmlPrincipal.emailAddresses,
-            calendarUserAddresses = xmlPrincipal.calendarUserAddresses,
-            enabledForCalendaring = xmlPrincipal.enabledForCalendaring,
-        )
-
-        self.password          = xmlPrincipal.password
-        self._members          = xmlPrincipal.members
-        self._groups           = xmlPrincipal.groups
-
-    def members(self):
-        for recordType, shortName in self._members:
-            yield self.service.recordWithShortName(recordType, shortName)
-
-    def groups(self):
-        for shortName in self._groups:
-            yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName)
-
-    def verifyCredentials(self, credentials):
-        if isinstance(credentials, UsernamePassword):
-            return credentials.password == self.password
-        if isinstance(credentials, DigestedCredentials):
-            return credentials.checkPassword(self.password)
-
-        return super(XMLDirectoryRecord, self).verifyCredentials(credentials)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -74,7 +74,7 @@
 
 class PermissionsMixIn (ReadOnlyResourceMixIn):
     def defaultAccessControlList(self):
-        return authReadACL
+        return succeed(authReadACL)
 
     @inlineCallbacks
     def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
@@ -87,7 +87,7 @@
         else:
             # ...otherwise permissions are fixed, and are not subject to
             # inheritance rules, etc.
-            returnValue(self.defaultAccessControlList())
+            returnValue((yield self.defaultAccessControlList()))
 
 
 
@@ -146,11 +146,12 @@
     def __repr__(self):
         return "<%s: %s %s>" % (self.__class__.__name__, self.directory, self._url)
 
+    @inlineCallbacks
     def locateChild(self, req, segments):
-        child = self.getChild(segments[0])
+        child = (yield self.getChild(segments[0]))
         if child is not None:
-            return (child, segments[1:])
-        return (None, ())
+            returnValue( (child, segments[1:]) )
+        returnValue( (None, ()) )
 
     def deadProperties(self):
         if not hasattr(self, "_dead_properties"):
@@ -158,34 +159,38 @@
         return self._dead_properties
 
     def etag(self):
-        return None
+        return succeed(None)
 
+    @inlineCallbacks
     def principalForShortName(self, recordType, name):
-        return self.principalForRecord(self.directory.recordWithShortName(recordType, name))
+        returnValue((yield self.principalForRecord((yield self.directory.recordWithShortName(recordType, name)))))
 
+    # Deferred
     def principalForUser(self, user):
         return self.principalForShortName(DirectoryService.recordType_users, user)
 
+    @inlineCallbacks
     def principalForAuthID(self, user):
         # Basic/Digest creds -> just lookup user name
         if isinstance(user, UsernamePassword) or isinstance(user, DigestedCredentials):
-            return self.principalForUser(user.username)
+            returnValue((yield self.principalForUser(user.username)))
         elif isinstance(user, NegotiateCredentials):
             authID = "Kerberos:%s" % (user.principal,)
-            principal = self.principalForRecord(self.directory.recordWithAuthID(authID))
+            principal = (yield self.principalForRecord((yield self.directory.recordWithAuthID(authID))))
             if principal:
-                return principal
+                returnValue(principal)
             elif user.username:
-                return self.principalForUser(user.username)
+                returnValue((yield self.principalForUser(user.username)))
         
-        return None
+        returnValue(None)
 
     def principalForUID(self, uid):
         raise NotImplementedError("Subclass must implement principalForUID()")
 
+    # Deferred
     def principalForRecord(self, record):
         if record is None:
-            return None
+            return succeed(None)
         return self.principalForUID(record.uid)
 
     def principalForCalendarUserAddress(self, address):
@@ -263,9 +268,13 @@
 
         self.putChild(uidsResourceName, DirectoryPrincipalUIDProvisioningResource(self))
 
+    @inlineCallbacks
     def principalForUID(self, uid):
-        return self.getChild(uidsResourceName).getChild(uid)
+        child = (yield self.getChild(uidsResourceName))
+        child = (yield child.getChild(uid))
+        returnValue(child)
 
+    @inlineCallbacks
     def _principalForURI(self, uri):
         scheme, netloc, path, _ignore_params, _ignore_query, _ignore_fragment = urlparse(uri)
 
@@ -286,51 +295,52 @@
                 port = int(netloc[1])
 
             if host != config.ServerHostName:
-                return None
+                returnValue(None)
 
             if port != {
                 "http" : config.HTTPPort,
                 "https": config.SSLPort,
             }[scheme]:
-                return None
+                returnValue(None)
 
         elif scheme == "urn":
             if path.startswith("uuid:"):
-                return self.principalForUID(path[5:])
+                returnValue((yield self.principalForUID(path[5:])))
             else:
-                return None
+                returnValue(None)
         else:
-            return None
+            returnValue(None)
 
         if not path.startswith(self._url):
-            return None
+            returnValue(None)
 
         path = path[len(self._url) - 1:]
 
         segments = [unquote(s) for s in path.rstrip("/").split("/")]
         if segments[0] == "" and len(segments) == 3:
-            typeResource = self.getChild(segments[1])
+            typeResource = (yield self.getChild(segments[1]))
             if typeResource is not None:
-                principalResource = typeResource.getChild(segments[2])
+                principalResource = (yield typeResource.getChild(segments[2]))
                 if principalResource:
-                    return principalResource
+                    returnValue(principalResource)
 
-        return None
+        returnValue(None)
 
+    @inlineCallbacks
     def principalForCalendarUserAddress(self, address):
         # First see if the address is a principal URI
-        principal = self._principalForURI(address)
+        principal = (yield self._principalForURI(address))
         if principal:
             if isinstance(principal, DirectoryCalendarPrincipalResource):
-                return principal
+                returnValue(principal)
         else:
             # Next try looking it up in the directory
-            record = self.directory.recordWithCalendarUserAddress(address)
+            record = (yield self.directory.recordWithCalendarUserAddress(address))
             if record is not None:
-                return self.principalForRecord(record)
+                returnValue((yield self.principalForRecord(record)))
 
         log.debug("No principal for calendar user address: %r" % (address,))
-        return None
+        returnValue(None)
 
 
     ##
@@ -343,9 +353,9 @@
 
     def getChild(self, name):
         if name == "":
-            return self
+            return succeed(self)
         else:
-            return self.putChildren.get(name, None)
+            return succeed(self.putChildren.get(name, None))
 
     def listChildren(self):
         return succeed(self.directory.recordTypes())
@@ -377,9 +387,11 @@
         self.recordType = recordType
         self.parent = parent
 
+    # Deferred
     def principalForUID(self, uid):
         return self.parent.principalForUID(uid)
 
+    # Deferred
     def principalForCalendarUserAddress(self, address):
         return self.parent.principalForCalendarUserAddress(address)
 
@@ -391,9 +403,10 @@
         log.err("Attempt to create clone %r of resource %r" % (path, self))
         raise HTTPError(responsecode.NOT_FOUND)
 
+    # Deferred
     def getChild(self, name):
         if name == "":
-            return self
+            return succeed(self)
         else:
             return self.principalForShortName(self.recordType, name)
 
@@ -436,9 +449,11 @@
 
         self.parent = parent
 
+    # Deferred
     def principalForUID(self, uid):
         return self.parent.principalForUID(uid)
 
+    # Deferred
     def principalForCalendarUserAddress(self, address):
         return self.parent.principalForCalendarUserAddress(address)
 
@@ -450,9 +465,10 @@
         log.err("Attempt to create clone %r of resource %r" % (path, self))
         raise HTTPError(responsecode.NOT_FOUND)
 
+    @inlineCallbacks
     def getChild(self, name):
         if name == "":
-            return self
+            returnValue(self)
 
         if "#" in name:
             # This UID belongs to a sub-principal
@@ -461,11 +477,11 @@
             primaryUID = name
             subType = None
 
-        record = self.directory.recordWithUID(primaryUID)
+        record = (yield self.directory.recordWithUID(primaryUID))
 
         if record is None:
             log.err("No principal found for UID: %s" % (name,))
-            return None
+            returnValue(None)
 
         if record.enabledForCalendaring:
             primaryPrincipal = DirectoryCalendarPrincipalResource(self, record)
@@ -473,9 +489,9 @@
             primaryPrincipal = DirectoryPrincipalResource(self, record)
 
         if subType is None:
-            return primaryPrincipal
+            returnValue(primaryPrincipal)
         else:
-            return primaryPrincipal.getChild(subType)
+            returnValue((yield primaryPrincipal.getChild(subType)))
 
     def listChildren(self):
         # Not a listable collection
@@ -568,7 +584,7 @@
         return self._dead_properties
 
     def etag(self):
-        return None
+        return succeed(None)
 
     ##
     # HTTP
@@ -667,7 +683,7 @@
         proxyFors = set()
 
         if resolve_memberships:
-            memberships = self._getRelatives("groups", infinity=True)
+            memberships = (yield self._getRelatives("groups", infinity=True))
             for membership in memberships:
                 results = (yield membership.proxyFor(read_write, False))
                 proxyFors.update(results)
@@ -677,7 +693,7 @@
             proxies = []
             memberships = (yield self._calendar_user_proxy_index().getMemberships(self.principalUID()))
             for uid in memberships:
-                subprincipal = self.parent.principalForUID(uid)
+                subprincipal = (yield self.parent.principalForUID(uid))
                 if subprincipal:
                     if subprincipal.isProxyType(read_write):
                         proxies.append(subprincipal.parent)
@@ -688,6 +704,7 @@
 
         returnValue(proxyFors)
 
+    @inlineCallbacks
     def _getRelatives(self, method, record=None, relatives=None, records=None, proxy=None, infinity=False):
         if record is None:
             record = self.record
@@ -698,41 +715,43 @@
 
         if record not in records:
             records.add(record)
-            for relative in getattr(record, method)():
+            for relative in (yield getattr(record, method)()):
                 if relative not in records:
-                    found = self.parent.principalForRecord(relative)
+                    found = (yield self.parent.principalForRecord(relative))
                     if found is None:
                         log.err("No principal found for directory record: %r" % (relative,))
                     else:
                         if proxy:
                             if proxy == "read-write":
-                                found = found.getChild("calendar-proxy-write")
+                                found = (yield found.getChild("calendar-proxy-write"))
                             else:
-                                found = found.getChild("calendar-proxy-read")
+                                found = (yield found.getChild("calendar-proxy-read"))
                         relatives.add(found)
 
                     if infinity:
-                        self._getRelatives(method, relative, relatives, records,
+                        yield self._getRelatives(method, relative, relatives, records,
                             infinity=infinity)
 
-        return relatives
+        returnValue(relatives)
 
+    # Deferred
     def groupMembers(self):
-        return succeed(self._getRelatives("members"))
+        return self._getRelatives("members")
 
+    # Deferred
     def expandedGroupMembers(self):
-        return succeed(self._getRelatives("members", infinity=True))
+        return self._getRelatives("members", infinity=True)
 
     @inlineCallbacks
     def groupMemberships(self, infinity=False):
-        groups = self._getRelatives("groups", infinity=infinity)
+        groups = (yield self._getRelatives("groups", infinity=infinity))
 
         if config.EnableProxyPrincipals:
             # Get proxy group UIDs and map to principal resources
             proxies = []
             memberships = (yield self._calendar_user_proxy_index().getMemberships(self.principalUID()))
             for uid in memberships:
-                subprincipal = self.parent.principalForUID(uid)
+                subprincipal = (yield self.parent.principalForUID(uid))
                 if subprincipal:
                     proxies.append(subprincipal)
                 else:
@@ -757,7 +776,7 @@
     ##
 
     def setAutoSchedule(self, autoSchedule):
-        self._resource_info_index().setAutoSchedule(self.record.guid, autoSchedule)
+        return self._resource_info_index().setAutoSchedule(self.record.guid, autoSchedule)
 
     @inlineCallbacks
     def getAutoSchedule(self):
@@ -798,17 +817,18 @@
         log.err("Attempt to create clone %r of resource %r" % (path, self))
         raise HTTPError(responsecode.NOT_FOUND)
 
+    @inlineCallbacks
     def locateChild(self, req, segments):
-        child = self.getChild(segments[0])
+        child = (yield self.getChild(segments[0]))
         if child is not None:
-            return (child, segments[1:])
-        return (None, ())
+            returnValue((child, segments[1:]))
+        returnValue((None, ()))
 
     def getChild(self, name):
         if name == "":
-            return self
+            return succeed(self)
 
-        return None
+        return succeed(None)
 
     def listChildren(self):
         return succeed(())
@@ -934,12 +954,12 @@
 
     def getChild(self, name):
         if name == "":
-            return self
+            return succeed(self)
 
         if config.EnableProxyPrincipals and name in ("calendar-proxy-read", "calendar-proxy-write"):
-            return CalendarUserProxyPrincipalResource(self, name)
+            return succeed(CalendarUserProxyPrincipalResource(self, name))
         else:
-            return None
+            return succeed(None)
 
     def listChildren(self):
         if config.EnableProxyPrincipals:

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/resource.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/resource.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -20,7 +20,7 @@
 
 __all__ = ["AutoProvisioningResourceMixIn"]
 
-from twisted.internet.defer import maybeDeferred
+from twisted.internet.defer import maybeDeferred, succeed
 
 class AutoProvisioningResourceMixIn (object):
     """
@@ -36,7 +36,7 @@
         already provisioned (eg. the backing store exists).
         @return: a deferred or None.
         """
-        return None
+        return succeed(None)
 
     def provisionChild(self, name):
         """
@@ -48,7 +48,7 @@
         @return: the newly created (optionally deferred) child, or None of no resource
             is bound as a child of this resource with the given C{name}.
         """
-        return None
+        return succeed(None)
 
     def locateChild(self, request, segments):
         """

Deleted: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sqldb.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sqldb.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sqldb.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -1,368 +0,0 @@
-##
-# Copyright (c) 2006-2009 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.
-##
-
-"""
-SQL (sqlite) based user/group/resource directory service implementation.
-"""
-
-"""
-SCHEMA:
-
-User Database:
-
-ROW: RECORD_TYPE, SHORT_NAME (unique), PASSWORD, NAME
-
-Group Database:
-
-ROW: SHORT_NAME, MEMBER_SHORT_NAME
-
-CUAddress database:
-
-ROW: ADDRESS (unqiue), SHORT_NAME
-
-"""
-
-__all__ = [
-    "SQLDirectoryService",
-]
-
-from twisted.cred.credentials import UsernamePassword
-from twisted.python.filepath import FilePath
-
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.xmlaccountsparser import XMLAccountsParser
-from twistedcaldav.sql import AbstractSQLDatabase
-from twistedcaldav.sql import db_prefix
-
-import os
-
-class SQLDirectoryManager(AbstractSQLDatabase):
-    """
-    House keeping operations on the SQL DB, including loading from XML file,
-    and record dumping. This can be used as a standalong DB management tool.
-    """
-    dbType = "DIRECTORYSERVICE"
-    dbFilename = db_prefix + "accounts"
-    dbFormatVersion = "3"
-
-    def __init__(self, path):
-        path = os.path.join(path, SQLDirectoryManager.dbFilename)
-        super(SQLDirectoryManager, self).__init__(path, True)
-
-    def loadFromXML(self, xmlFile):
-        parser = XMLAccountsParser(xmlFile)
-       
-        # Totally wipe existing DB and start from scratch
-        if os.path.exists(self.dbpath):
-            os.remove(self.dbpath)
-
-        self._db_execute("insert into SERVICE (REALM) values (:1)", parser.realm)
-
-        # Now add records to db
-        for item in parser.items.values():
-            for entry in item.itervalues():
-                self._add_to_db(entry)
-        self._db_commit()
-
-    def getRealm(self):
-        for realm in self._db_execute("select REALM from SERVICE"):
-            return realm[0].decode("utf-8")
-        else:
-            return ""
-
-    def listRecords(self, recordType):
-        # Get each account record
-        for shortName, guid, password, name in self._db_execute(
-            """
-            select SHORT_NAME, GUID, PASSWORD, NAME
-              from ACCOUNTS
-             where RECORD_TYPE = :1
-            """, recordType
-        ):
-            # See if we have members
-            members = self.members(shortName)
-                
-            # See if we are a member of any groups
-            groups = self.groups(shortName)
-                
-            # Get calendar user addresses
-            calendarUserAddresses = self.calendarUserAddresses(shortName)
-            
-            yield shortName, guid, password, name, members, groups, calendarUserAddresses
-
-    def getRecord(self, recordType, shortName):
-        # Get individual account record
-        for shortName, guid, password, name in self._db_execute(
-            """
-            select SHORT_NAME, GUID, PASSWORD, NAME
-              from ACCOUNTS
-             where RECORD_TYPE = :1
-               and SHORT_NAME  = :2
-            """, recordType, shortName
-        ):
-            break
-        else:
-            return None
-        
-        # See if we have members
-        members = self.members(shortName)
-            
-        # See if we are a member of any groups
-        groups = self.groups(shortName)
-            
-        # Get calendar user addresses
-        calendarUserAddresses = self.calendarUserAddresses(shortName)
-        
-        return shortName, guid, password, name, members, groups, calendarUserAddresses
-            
-    def members(self, shortName):
-        members = set()
-        for member in self._db_execute(
-            """
-            select MEMBER_RECORD_TYPE, MEMBER_SHORT_NAME
-              from GROUPS
-             where SHORT_NAME = :1
-            """, shortName
-        ):
-            members.add(tuple(member))
-        return members
-
-    def groups(self, shortName):
-        groups = set()
-        for (name,) in self._db_execute(
-            """
-            select SHORT_NAME
-              from GROUPS
-             where MEMBER_SHORT_NAME = :1
-            """, shortName
-        ):
-            groups.add(name)
-        return groups
-
-    def calendarUserAddresses(self, shortName):
-        calendarUserAddresses = set()
-        for (address,) in self._db_execute(
-            """
-            select ADDRESS
-              from ADDRESSES
-             where SHORT_NAME = :1
-            """, shortName
-        ):
-            calendarUserAddresses.add(address)
-        return calendarUserAddresses
-
-    def _add_to_db(self, record):
-        # Do regular account entry
-        recordType = record.recordType
-        shortName = record.shortNames[0]
-        guid = record.guid
-        password = record.password
-        name = record.fullName
-
-        self._db_execute(
-            """
-            insert into ACCOUNTS (RECORD_TYPE, SHORT_NAME, GUID, PASSWORD, NAME)
-            values (:1, :2, :3, :4, :5)
-            """, recordType, shortName, guid, password, name
-        )
-        
-        # Check for members
-        for memberRecordType, memberShortName in record.members:
-            self._db_execute(
-                """
-                insert into GROUPS (SHORT_NAME, MEMBER_RECORD_TYPE, MEMBER_SHORT_NAME)
-                values (:1, :2, :3)
-                """, shortName, memberRecordType, memberShortName
-            )
-                
-        # CUAddress
-        for cuaddr in record.calendarUserAddresses:
-            self._db_execute(
-                """
-                insert into ADDRESSES (ADDRESS, SHORT_NAME)
-                values (:1, :2)
-                """, cuaddr, shortName
-            )
-       
-    def _delete_from_db(self, shortName):
-        """
-        Deletes the specified entry from all dbs.
-        @param name: the name of the resource to delete.
-        @param shortName: the short name of the resource to delete.
-        """
-        self._db_execute("delete from ACCOUNTS  where SHORT_NAME        = :1", shortName)
-        self._db_execute("delete from GROUPS    where SHORT_NAME        = :1", shortName)
-        self._db_execute("delete from GROUPS    where MEMBER_SHORT_NAME = :1", shortName)
-        self._db_execute("delete from ADDRESSES where SHORT_NAME        = :1", shortName)
-    
-    def _db_version(self):
-        """
-        @return: the schema version assigned to this index.
-        """
-        return SQLDirectoryManager.dbFormatVersion
-        
-    def _db_type(self):
-        """
-        @return: the collection type assigned to this index.
-        """
-        return SQLDirectoryManager.dbType
-        
-    def _db_init_data_tables(self, q):
-        """
-        Initialise the underlying database tables.
-        @param q:           a database cursor to use.
-        """
-        #
-        # SERVICE table
-        #
-        q.execute("create table SERVICE (REALM text)")
-
-        #
-        # ACCOUNTS table
-        #
-        q.execute(
-            """
-            create table ACCOUNTS (
-                RECORD_TYPE  text,
-                SHORT_NAME   text,
-                GUID         text,
-                PASSWORD     text,
-                NAME         text
-            )
-            """
-        )
-
-        #
-        # GROUPS table
-        #
-        q.execute(
-            """
-            create table GROUPS (
-                SHORT_NAME          text,
-                MEMBER_RECORD_TYPE  text,
-                MEMBER_SHORT_NAME   text
-            )
-            """
-        )
-
-        #
-        # ADDRESSES table
-        #
-        q.execute(
-            """
-            create table ADDRESSES (
-                ADDRESS     text unique,
-                SHORT_NAME  text
-            )
-            """
-        )
-
-class SQLDirectoryService(DirectoryService):
-    """
-    XML based implementation of L{IDirectoryService}.
-    """
-    baseGUID = "8256E464-35E0-4DBB-A99C-F0E30C231675"
-    realmName = None
-
-    def __repr__(self):
-        return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.manager.dbpath)
-
-    def __init__(self, dbParentPath, xmlFile=None):
-        super(SQLDirectoryService, self).__init__()
-
-        if type(dbParentPath) is str:
-            dbParentPath = FilePath(dbParentPath)
-            
-        self.manager = SQLDirectoryManager(dbParentPath.path)
-        if xmlFile:
-            self.manager.loadFromXML(xmlFile)
-        self.realmName = self.manager.getRealm()
-
-    def recordTypes(self):
-        recordTypes = (
-            DirectoryService.recordType_users,
-            DirectoryService.recordType_groups,
-            DirectoryService.recordType_locations,
-            DirectoryService.recordType_resources,
-        )
-        return recordTypes
-
-    def listRecords(self, recordType):
-        for result in self.manager.listRecords(recordType):
-            yield SQLDirectoryRecord(
-                service               = self,
-                recordType            = recordType,
-                shortName             = result[0],
-                guid                  = result[1],
-                password              = result[2],
-                name                  = result[3],
-                members               = result[4],
-                groups                = result[5],
-                calendarUserAddresses = result[6],
-            )
-
-    def recordWithShortName(self, recordType, shortName):
-        result = self.manager.getRecord(recordType, shortName)
-        if result:
-            return SQLDirectoryRecord(
-                service               = self,
-                recordType            = recordType,
-                shortName             = result[0],
-                guid                  = result[1],
-                password              = result[2],
-                name                  = result[3],
-                members               = result[4],
-                groups                = result[5],
-                calendarUserAddresses = result[6],
-            )
-
-        return None
-
-class SQLDirectoryRecord(DirectoryRecord):
-    """
-    XML based implementation implementation of L{IDirectoryRecord}.
-    """
-    def __init__(self, service, recordType, shortName, guid, password, name, members, groups, calendarUserAddresses):
-        super(SQLDirectoryRecord, self).__init__(
-            service               = service,
-            recordType            = recordType,
-            guid                  = guid,
-            shortNames            = (shortName,),
-            fullName              = name,
-            calendarUserAddresses = calendarUserAddresses,
-        )
-
-        self.password = password
-        self._members = members
-        self._groups  = groups
-
-    def members(self):
-        for recordType, shortName in self._members:
-            yield self.service.recordWithShortName(recordType, shortName)
-
-    def groups(self):
-        for shortName in self._groups:
-            yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName)
-
-    def verifyCredentials(self, credentials):
-        if isinstance(credentials, UsernamePassword):
-            return credentials.password == self.password
-
-        return super(SQLDirectoryRecord, self).verifyCredentials(credentials)
-
-if __name__ == '__main__':
-    mgr = SQLDirectoryManager("./")
-    mgr.loadFromXML("test/accounts.xml")

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sudo.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sudo.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sudo.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -26,6 +26,7 @@
 from twisted.python.filepath import FilePath
 from twisted.cred.credentials import IUsernamePassword, IUsernameHashedPassword
 from twisted.cred.error import UnauthorizedLogin
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 
 from twext.python.plistlib import readPlist
 
@@ -93,8 +94,9 @@
 
         for entry in self._accounts()['users']:
             if entry['username'] == shortName:
-                return self._recordForEntry(entry)
+                return succeed(self._recordForEntry(entry))
 
+    @inlineCallbacks
     def requestAvatarId(self, credentials):
         # FIXME: ?
         # We were checking if principal is enabled; seems unnecessary in current
@@ -105,11 +107,11 @@
             raise UnauthorizedLogin("No such user: %s" % (credentials.credentials.username,))
         sudouser = credentials.authnPrincipal.record
 
-        if credentials.authnPrincipal.record.verifyCredentials(credentials.credentials):
-            return (
+        if (yield credentials.authnPrincipal.record.verifyCredentials(credentials.credentials)):
+            returnValue( (
                 credentials.authnPrincipal.principalURL(),
                 credentials.authzPrincipal.principalURL(),
-                )
+                ) )
         else:
             raise UnauthorizedLogin(
                 "Incorrect credentials for %s" % (sudouser,))
@@ -134,8 +136,8 @@
 
     def verifyCredentials(self, credentials):
         if IUsernamePassword.providedBy(credentials):
-            return credentials.checkPassword(self.password)
+            return succeed(credentials.checkPassword(self.password))
         elif IUsernameHashedPassword.providedBy(credentials):
-            return credentials.checkPassword(self.password)
+            return succeed(credentials.checkPassword(self.password))
 
         return super(SudoDirectoryRecord, self).verifyCredentials(credentials)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_cachedirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_cachedirectory.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_cachedirectory.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -14,6 +14,7 @@
 # limitations under the License.
 ##
 
+from twisted.internet.defer import inlineCallbacks
 from twistedcaldav.directory.cachingdirectory import CachingDirectoryService,\
     CachingDirectoryRecord, DictRecordTypeCache
 from twistedcaldav.test.util import TestCase
@@ -161,10 +162,11 @@
         self.verifyRecords(DirectoryService.recordType_resources, set())
         self.verifyRecords(DirectoryService.recordType_locations, set())
     
+    @inlineCallbacks
     def test_cacheoneguid(self):
         self.dummyRecords()
 
-        self.assertTrue(self.service.recordWithGUID(self.guidForShortName("user01")) is not None)
+        self.assertTrue((yield self.service.recordWithGUID(self.guidForShortName("user01"))) is not None)
         self.assertTrue(self.service.queried)
         self.verifyRecords(DirectoryService.recordType_users, set((
             self.guidForShortName("user01"),
@@ -175,16 +177,17 @@
 
         # Make sure it really is cached and won't cause another query
         self.service.queried = False
-        self.assertTrue(self.service.recordWithGUID(self.guidForShortName("user01")) is not None)
+        self.assertTrue((yield self.service.recordWithGUID(self.guidForShortName("user01"))) is not None)
         self.assertFalse(self.service.queried)
         
+    @inlineCallbacks
     def test_cacheoneshortname(self):
         self.dummyRecords()
 
-        self.assertTrue(self.service.recordWithShortName(
+        self.assertTrue((yield self.service.recordWithShortName(
             DirectoryService.recordType_users,
             "user02"
-        ) is not None)
+        )) is not None)
         self.assertTrue(self.service.queried)
         self.verifyRecords(DirectoryService.recordType_users, set((
             self.guidForShortName("user02"),
@@ -195,18 +198,19 @@
 
         # Make sure it really is cached and won't cause another query
         self.service.queried = False
-        self.assertTrue(self.service.recordWithShortName(
+        self.assertTrue((yield self.service.recordWithShortName(
             DirectoryService.recordType_users,
             "user02"
-        ) is not None)
+        )) is not None)
         self.assertFalse(self.service.queried)
 
+    @inlineCallbacks
     def test_cacheoneemail(self):
         self.dummyRecords()
 
-        self.assertTrue(self.service.recordWithCalendarUserAddress(
+        self.assertTrue((yield self.service.recordWithCalendarUserAddress(
             "mailto:user03 at example.com"
-        ) is not None)
+        )) is not None)
         self.assertTrue(self.service.queried)
         self.verifyRecords(DirectoryService.recordType_users, set((
             self.guidForShortName("user03"),
@@ -217,17 +221,18 @@
 
         # Make sure it really is cached and won't cause another query
         self.service.queried = False
-        self.assertTrue(self.service.recordWithCalendarUserAddress(
+        self.assertTrue((yield self.service.recordWithCalendarUserAddress(
             "mailto:user03 at example.com"
-        ) is not None)
+        )) is not None)
         self.assertFalse(self.service.queried)
 
+    @inlineCallbacks
     def test_cacheoneauthid(self):
         self.dummyRecords()
 
-        self.assertTrue(self.service.recordWithAuthID(
+        self.assertTrue((yield self.service.recordWithAuthID(
             "Kerberos:user03 at example.com"
-        ) is not None)
+        )) is not None)
         self.assertTrue(self.service.queried)
         self.verifyRecords(DirectoryService.recordType_users, set((
             self.guidForShortName("user03"),
@@ -238,7 +243,7 @@
 
         # Make sure it really is cached and won't cause another query
         self.service.queried = False
-        self.assertTrue(self.service.recordWithAuthID(
+        self.assertTrue((yield self.service.recordWithAuthID(
             "Kerberos:user03 at example.com"
-        ) is not None)
+        )) is not None)
         self.assertFalse(self.service.queried)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_calendar.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_calendar.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_calendar.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -32,6 +32,7 @@
     """
     Directory service provisioned principals.
     """
+    @inlineCallbacks
     def setUp(self):
         super(ProvisionedCalendars, self).setUp()
         
@@ -48,18 +49,20 @@
 
         provisioningResource = DirectoryPrincipalProvisioningResource(url, self.directoryService)
 
-        self.site.resource.putChild("principals", provisioningResource)
+        yield self.site.resource.putChild("principals", provisioningResource)
 
-        self.setupCalendars()
+        yield self.setupCalendars()
 
         self.site.resource.setAccessControlList(davxml.ACL())
 
+    @inlineCallbacks
     def setupCalendars(self):
-        calendarCollection = CalendarHomeProvisioningFile(
+        calendarCollection = (yield CalendarHomeProvisioningFile.fetch(
+            None,
             os.path.join(self.docroot, "calendars"),
             self.directoryService,
             "/calendars/"
-        )
+        ))
         self.site.resource.putChild("calendars", calendarCollection)
 
     def test_NonExistentCalendarHome(self):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_guidchange.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_guidchange.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_guidchange.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -19,6 +19,7 @@
 
 import os
 
+from twisted.internet.defer import inlineCallbacks
 from twisted.web2.dav import davxml
 from twisted.web2.dav.resource import AccessDeniedError
 from twisted.web2.test.test_server import SimpleRequest
@@ -76,6 +77,7 @@
 
         homeResource = "/calendars/users/cdaboo/"
         
+        @inlineCallbacks
         def privs1(result):
             # Change GUID in record
             fd = open(self.xmlfile, "w")
@@ -85,13 +87,13 @@
 
             # Force re-read of records (not sure why _fileInfo has to be wiped here...)
             self.directoryService._fileInfo = (0, 0)
-            self.directoryService.recordWithShortName(DirectoryService.recordType_users, "cdaboo")
+            yield self.directoryService.recordWithShortName(DirectoryService.recordType_users, "cdaboo")
 
             # Now force the calendar home resource to be reset
             self.resetCalendars()
             
             # Make sure new user cannot access old user's calendar home
-            return self._checkPrivileges(None, homeResource, davxml.HRef("/principals/__uids__/" + newUID + "/"), davxml.Write, False)
+            returnValue((yield self._checkPrivileges(None, homeResource, davxml.HRef("/principals/__uids__/" + newUID + "/"), davxml.Write, False)))
             
         # Make sure current user has access to their calendar home
         d = self._checkPrivileges(None, homeResource, davxml.HRef("/principals/__uids__/" + oldUID + "/"), davxml.Write, True)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_opendirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_opendirectory.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_opendirectory.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -20,6 +20,7 @@
     pass
 else:
     import twisted.web2.auth.digest
+    from twisted.internet.defer import inlineCallbacks
     import twistedcaldav.directory.test.util
     from twistedcaldav.directory.directory import DirectoryService
     from twistedcaldav.directory.appleopendirectory import OpenDirectoryRecord
@@ -78,6 +79,7 @@
             )
             self.assertEquals(record.fullName, "")
 
+        @inlineCallbacks
         def test_invalidODDigest(self):
             record = OpenDirectoryRecord(
                 service               = self.service(),
@@ -98,7 +100,7 @@
             digestFields = {}
             digested = twisted.web2.auth.digest.DigestedCredentials("user", "GET", "example.com", digestFields, None)
 
-            self.assertFalse(record.verifyCredentials(digested))
+            self.assertFalse((yield record.verifyCredentials(digested)))
 
         def test_validODDigest(self):
             record = OpenDirectoryRecord(
@@ -146,6 +148,7 @@
 
             self.assertTrue(record.verifyCredentials(digested))
 
+        @inlineCallbacks
         def test_queryDirectorySingleGUID(self):
             """ Test for lookup on existing and non-existing GUIDs """
 
@@ -165,11 +168,12 @@
                 return results
 
             recordTypes = [DirectoryService.recordType_users, DirectoryService.recordType_groups, DirectoryService.recordType_locations, DirectoryService.recordType_resources]
-            self.service().queryDirectory(recordTypes, self.service().INDEX_TYPE_GUID, "1234567890", lookupMethod=lookupMethod)
-            self.assertTrue(self.service().recordWithGUID("1234567890"))
-            self.assertFalse(self.service().recordWithGUID("987654321"))
+            yield self.service().queryDirectory(recordTypes, self.service().INDEX_TYPE_GUID, "1234567890", lookupMethod=lookupMethod)
+            self.assertTrue((yield self.service().recordWithGUID("1234567890")))
+            self.assertFalse((yield self.service().recordWithGUID("987654321")))
 
 
+        @inlineCallbacks
         def test_queryDirectoryDuplicateGUIDs(self):
             """ Test for lookup on duplicate GUIDs, ensuring they don't get
                 faulted in """
@@ -195,5 +199,5 @@
                 return results
 
             recordTypes = [DirectoryService.recordType_users, DirectoryService.recordType_groups, DirectoryService.recordType_locations, DirectoryService.recordType_resources]
-            self.service().queryDirectory(recordTypes, self.service().INDEX_TYPE_GUID, "1234567890", lookupMethod=lookupMethod)
-            self.assertFalse(self.service().recordWithGUID("1234567890"))
+            yield self.service().queryDirectory(recordTypes, self.service().INDEX_TYPE_GUID, "1234567890", lookupMethod=lookupMethod)
+            self.assertFalse((yield self.service().recordWithGUID("1234567890")))

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -17,7 +17,7 @@
 import os
 
 from twisted.cred.credentials import UsernamePassword
-from twisted.internet.defer import inlineCallbacks, gatherResults
+from twisted.internet.defer import inlineCallbacks, gatherResults, returnValue
 from twisted.web2.dav import davxml
 from twisted.web2.dav.fileop import rmdir
 from twisted.web2.dav.resource import AccessDeniedError
@@ -81,6 +81,7 @@
 
             self.principalRootResources[directory.__class__.__name__] = provisioningResource
 
+    @inlineCallbacks
     def test_hierarchy(self):
         """
         DirectoryPrincipalProvisioningResource.listChildren(),
@@ -105,59 +106,58 @@
             principalCollections = provisioningResource.principalCollections()
             self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
 
-            d = provisioningResource.listChildren()
-            def _gotProvisioningChildren(children):
-                recordTypes = set(children)
-                self.assertEquals(recordTypes, set(directory.recordTypes()))
+            children = (yield provisioningResource.listChildren())
+            recordTypes = set(children)
+            self.assertEquals(recordTypes, set(directory.recordTypes()))
 
-                for recordType in recordTypes:
-                    #print "   -> %s" % (recordType,)
-                    typeResource = provisioningResource.getChild(recordType)
-                    self.failUnless(isinstance(typeResource, DirectoryPrincipalTypeProvisioningResource))
+            for recordType in recordTypes:
+                #print "   -> %s" % (recordType,)
+                typeResource = (yield provisioningResource.getChild(recordType))
+                self.failUnless(isinstance(typeResource, DirectoryPrincipalTypeProvisioningResource))
 
-                    typeURL = provisioningURL + recordType + "/"
-                    self.assertEquals(typeURL, typeResource.principalCollectionURL())
+                typeURL = provisioningURL + recordType + "/"
+                self.assertEquals(typeURL, typeResource.principalCollectionURL())
 
-                    principalCollections = typeResource.principalCollections()
-                    self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
-                    d = typeResource.listChildren()
-                    def _gotTypeChildren(children):
-                        shortNames = set(children)
-                        self.assertEquals(shortNames, set(r.shortNames[0] for r in directory.listRecords(recordType)))
+                principalCollections = typeResource.principalCollections()
+                self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
+                shortNames = set((yield typeResource.listChildren()))
+                self.assertEquals(shortNames, set(r.shortNames[0] for r in directory.listRecords(recordType)))
 
-                        for shortName in shortNames:
-                            #print "     -> %s" % (shortName,)
-                            recordResource = typeResource.getChild(shortName)
-                            self.failUnless(isinstance(recordResource, DirectoryPrincipalResource))
+                for shortName in shortNames:
+                    #print "     -> %s" % (shortName,)
+                    recordResource = (yield typeResource.getChild(shortName))
+                    self.failUnless(isinstance(recordResource, DirectoryPrincipalResource))
 
-                            recordURL = typeURL + shortName + "/"
-                            self.assertIn(recordURL, (recordResource.principalURL(),) + tuple(recordResource.alternateURIs()))
+                    recordURL = typeURL + shortName + "/"
+                    self.assertIn(recordURL, (recordResource.principalURL(),) + tuple(recordResource.alternateURIs()))
 
-                            principalCollections = recordResource.principalCollections()
-                            self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
+                    principalCollections = recordResource.principalCollections()
+                    self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
                     
-            return d.addCallback(_gotProvisioningChildren)
 
+    @inlineCallbacks
     def test_allRecords(self):
         """
         Test of a test routine...
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             self.assertEquals(recordResource.record, record)
 
     ##
     # DirectoryPrincipalProvisioningResource
     ##
 
+    @inlineCallbacks
     def test_principalForShortName(self):
         """
         DirectoryPrincipalProvisioningResource.principalForShortName()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
-            principal = provisioningResource.principalForShortName(recordType, record.shortNames[0])
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+            principal = (yield provisioningResource.principalForShortName(recordType, record.shortNames[0]))
             self.failIf(principal is None)
             self.assertEquals(record, principal.record)
 
+    @inlineCallbacks
     def test_principalForUser(self):
         """
         DirectoryPrincipalProvisioningResource.principalForUser()
@@ -166,10 +166,11 @@
             provisioningResource = self.principalRootResources[directory.__class__.__name__]
 
             for user in directory.listRecords(DirectoryService.recordType_users):
-                userResource = provisioningResource.principalForUser(user.shortNames[0])
+                userResource = (yield provisioningResource.principalForUser(user.shortNames[0]))
                 self.failIf(userResource is None)
                 self.assertEquals(user, userResource.record)
 
+    @inlineCallbacks
     def test_principalForAuthID(self):
         """
         DirectoryPrincipalProvisioningResource.principalForAuthID()
@@ -179,33 +180,36 @@
 
             for user in directory.listRecords(DirectoryService.recordType_users):
                 creds = UsernamePassword(user.shortNames[0], "bogus")
-                userResource = provisioningResource.principalForAuthID(creds)
+                userResource = (yield provisioningResource.principalForAuthID(creds))
                 self.failIf(userResource is None)
                 self.assertEquals(user, userResource.record)
 
+    @inlineCallbacks
     def test_principalForUID(self):
         """
         DirectoryPrincipalProvisioningResource.principalForUID()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
-            principal = provisioningResource.principalForUID(record.uid)
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+            principal = (yield provisioningResource.principalForUID(record.uid))
             self.failIf(principal is None)
             self.assertEquals(record, principal.record)
 
+    @inlineCallbacks
     def test_principalForRecord(self):
         """
         DirectoryPrincipalProvisioningResource.principalForRecord()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
-            principal = provisioningResource.principalForRecord(record)
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+            principal = (yield provisioningResource.principalForRecord(record))
             self.failIf(principal is None)
             self.assertEquals(record, principal.record)
 
+    @inlineCallbacks
     def test_principalForCalendarUserAddress(self):
         """
         DirectoryPrincipalProvisioningResource.principalForCalendarUserAddress()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             principalURL = recordResource.principalURL()
             if principalURL.endswith("/"):
                 alternateURL = principalURL[:-1]
@@ -213,7 +217,7 @@
                 alternateURL = principalURL + "/"
 
             for address in tuple(record.calendarUserAddresses) + (principalURL, alternateURL):
-                principal = provisioningResource.principalForCalendarUserAddress(address)
+                principal = (yield provisioningResource.principalForCalendarUserAddress(address))
                 if record.enabledForCalendaring:
                     self.failIf(principal is None)
                     self.assertEquals(record, principal.record)
@@ -221,17 +225,18 @@
                     self.failIf(principal is not None)
 
         # Explicitly check the disabled record
-        self.failIf(provisioningResource.principalForCalendarUserAddress("mailto:nocalendar at example.com") is not None)
-        self.failIf(provisioningResource.principalForCalendarUserAddress("urn:uuid:543D28BA-F74F-4D5F-9243-B3E3A61171E5") is not None)
-        self.failIf(provisioningResource.principalForCalendarUserAddress("/principals/users/nocalendar/") is not None)
-        self.failIf(provisioningResource.principalForCalendarUserAddress("/principals/__uids__/543D28BA-F74F-4D5F-9243-B3E3A61171E5/") is not None)
+        self.failIf((yield provisioningResource.principalForCalendarUserAddress("mailto:nocalendar at example.com")) is not None)
+        self.failIf((yield provisioningResource.principalForCalendarUserAddress("urn:uuid:543D28BA-F74F-4D5F-9243-B3E3A61171E5")) is not None)
+        self.failIf((yield provisioningResource.principalForCalendarUserAddress("/principals/users/nocalendar/")) is not None)
+        self.failIf((yield provisioningResource.principalForCalendarUserAddress("/principals/__uids__/543D28BA-F74F-4D5F-9243-B3E3A61171E5/")) is not None)
 
+    @inlineCallbacks
     def test_enabledForCalendaring(self):
         """
         DirectoryPrincipalProvisioningResource.principalForCalendarUserAddress()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
-            principal = provisioningResource.principalForRecord(record)
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+            principal = (yield provisioningResource.principalForRecord(record))
             self.failIf(principal is None)
             if record.enabledForCalendaring:
                 self.assertTrue(isinstance(principal, DirectoryCalendarPrincipalResource))
@@ -239,6 +244,7 @@
                 self.assertTrue(isinstance(principal, DirectoryPrincipalResource))
                 self.assertFalse(isinstance(principal, DirectoryCalendarPrincipalResource))
 
+    @inlineCallbacks
     def test_enabledAsOrganizer(self):
         """
         DirectoryPrincipalProvisioningResource.principalForCalendarUserAddress()
@@ -247,10 +253,10 @@
         ok_types = (
             DirectoryService.recordType_users,
         )
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             
             if record.enabledForCalendaring:
-                principal = provisioningResource.principalForRecord(record)
+                principal = (yield provisioningResource.principalForRecord(record))
                 self.failIf(principal is None)
                 self.assertEqual(principal.enabledAsOrganizer(), recordType in ok_types)
 
@@ -263,10 +269,10 @@
             DirectoryService.recordType_locations,
             DirectoryService.recordType_resources,
         )
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             
             if record.enabledForCalendaring:
-                principal = provisioningResource.principalForRecord(record)
+                principal = (yield provisioningResource.principalForRecord(record))
                 self.failIf(principal is None)
                 self.assertEqual(principal.enabledAsOrganizer(), recordType in ok_types)
 
@@ -276,20 +282,22 @@
     # DirectoryPrincipalResource
     ##
 
+    @inlineCallbacks
     def test_cacheNotifier(self):
         """
         Each DirectoryPrincipalResource should have a cacheNotifier attribute
         that is an instance of XattrCacheChangeNotifier
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             self.failUnless(isinstance(recordResource.cacheNotifier,
                                        DisabledCacheNotifier))
 
+    @inlineCallbacks
     def test_displayName(self):
         """
         DirectoryPrincipalResource.displayName()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             self.failUnless(recordResource.displayName())
 
     @inlineCallbacks
@@ -297,24 +305,25 @@
         """
         DirectoryPrincipalResource.groupMembers()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             members = yield recordResource.groupMembers()
-            self.failUnless(set(record.members()).issubset(set(r.record for r in members)))
+            self.failUnless(set((yield record.members())).issubset(set(r.record for r in members)))
 
     @inlineCallbacks
     def test_groupMemberships(self):
         """
         DirectoryPrincipalResource.groupMemberships()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             memberships = yield recordResource.groupMemberships()
-            self.failUnless(set(record.groups()).issubset(set(r.record for r in memberships if hasattr(r, "record"))))
+            self.failUnless(set((yield record.groups())).issubset(set(r.record for r in memberships if hasattr(r, "record"))))
 
+    @inlineCallbacks
     def test_principalUID(self):
         """
         DirectoryPrincipalResource.principalUID()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             self.assertEquals(record.guid, recordResource.principalUID())
 
     @inlineCallbacks
@@ -322,7 +331,7 @@
         """
         DirectoryPrincipalResource.calendarUserAddresses()
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             if record.enabledForCalendaring:
                 self.failUnless(
                     (
@@ -331,6 +340,7 @@
                     ).issubset(set((yield recordResource.calendarUserAddresses())))
                 )
 
+    @inlineCallbacks
     def test_calendarHomeURLs(self):
         """
         DirectoryPrincipalResource.calendarHomeURLs(),
@@ -339,13 +349,12 @@
         """
         ds = []
         # No calendar home provisioner should result in no calendar homes.
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             if record.enabledForCalendaring:
-                d = recordResource.calendarHomeURLs()
-                d.addCallback(lambda u: self.assertEqual(len(u), 0))
-                ds.append(d)
-                ds.append(recordResource.scheduleInboxURL().addCallback(self.failIf))
-                ds.append(recordResource.scheduleOutboxURL().addCallback(self.failIf))
+                urls = (yield recordResource.calendarHomeURLs())
+                self.assertEqual(len(urls), 0)
+                self.failIf((yield recordResource.scheduleInboxURL()))
+                self.failIf((yield recordResource.scheduleOutboxURL()))
 
         # Need to create a calendar home provisioner for each service.
         calendarRootResources = {}
@@ -358,46 +367,50 @@
                 rmdir(path)
             os.mkdir(path)
 
-            provisioningResource = CalendarHomeProvisioningFile(path, directory, url)
+            provisioningResource = (yield CalendarHomeProvisioningFile.fetch(
+                None, path, directory, url))
 
             calendarRootResources[directory.__class__.__name__] = provisioningResource
 
         # Calendar home provisioners should result in calendar homes.
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
             if record.enabledForCalendaring:
-                d = gatherResults([recordResource.calendarHomeURLs(),
-                                  recordResource.scheduleInboxURL(),
-                                  recordResource.scheduleOutboxURL()])
-                def _gotURLs(homeURLs, inboxURL, outboxURL):
-                    calendarRootURL = calendarRootResources[record.service.__class__.__name__].url()
+                homeURLs = tuple((yield recordResource.calendarHomeURLs()))
+                self.failUnless(homeURLs)
 
-                    self.failUnless(inboxURL)
-                    self.failUnless(outboxURL)
+                calendarRootURL = calendarRootResources[record.service.__class__.__name__].url()
 
-                    for homeURL in homeURLs:
-                        self.failUnless(homeURL.startswith(calendarRootURL))
+                inboxURL = (yield recordResource.scheduleInboxURL())
+                outboxURL = (yield recordResource.scheduleOutboxURL())
 
-                        if inboxURL and inboxURL.startswith(homeURL):
-                            self.failUnless(len(inboxURL) > len(homeURL))
-                            self.failUnless(inboxURL.endswith("/"))
-                            inboxURL = None
+                self.failUnless(inboxURL)
+                self.failUnless(outboxURL)
 
-                        if outboxURL and outboxURL.startswith(homeURL):
-                            self.failUnless(len(outboxURL) > len(homeURL))
-                            self.failUnless(outboxURL.endswith("/"))
-                            outboxURL = None
+                for homeURL in homeURLs:
+                    self.failUnless(homeURL.startswith(calendarRootURL))
 
-                    self.failIf(inboxURL)
-                    self.failIf(outboxURL)
-        return gatherResults(ds)
+                    if inboxURL and inboxURL.startswith(homeURL):
+                        self.failUnless(len(inboxURL) > len(homeURL))
+                        self.failUnless(inboxURL.endswith("/"))
+                        inboxURL = None
 
+                    if outboxURL and outboxURL.startswith(homeURL):
+                        self.failUnless(len(outboxURL) > len(homeURL))
+                        self.failUnless(outboxURL.endswith("/"))
+                        outboxURL = None
+
+                self.failIf(inboxURL)
+                self.failIf(outboxURL)
+
+
+
     @inlineCallbacks
     def test_defaultAccessControlList_principals(self):
         """
         Default access controls for principals.
         """
-        for provisioningResource, recordType, recordResource, record in self._allRecords():
-            for args in _authReadOnlyPrivileges(self, recordResource, recordResource.principalURL()):
+        for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+            for args in (yield _authReadOnlyPrivileges(self, recordResource, recordResource.principalURL())):
                 yield self._checkPrivileges(*args)
 
     @inlineCallbacks
@@ -409,14 +422,14 @@
             #print "\n -> %s" % (directory.__class__.__name__,)
             provisioningResource = self.principalRootResources[directory.__class__.__name__]
 
-            for args in _authReadOnlyPrivileges(self, provisioningResource, provisioningResource.principalCollectionURL()):
+            for args in (yield _authReadOnlyPrivileges(self, provisioningResource, provisioningResource.principalCollectionURL())):
                 yield self._checkPrivileges(*args)
             children = yield provisioningResource.listChildren()
             for recordType in children:
                 #print "   -> %s" % (recordType,)
-                typeResource = provisioningResource.getChild(recordType)
+                typeResource = (yield provisioningResource.getChild(recordType))
 
-                for args in _authReadOnlyPrivileges(self, typeResource, typeResource.principalCollectionURL()):
+                for args in (yield _authReadOnlyPrivileges(self, typeResource, typeResource.principalCollectionURL())):
                     yield self._checkPrivileges(*args)
 
     def test_propertyToField(self):
@@ -455,6 +468,7 @@
                 (field, converted)
             )
 
+    @inlineCallbacks
     def _allRecords(self):
         """
         @return: an iterable of tuples
@@ -465,12 +479,14 @@
             C{record} is the directory service record
             for each record in each directory in C{directoryServices}.
         """
+        results = []
         for directory in self.directoryServices:
             provisioningResource = self.principalRootResources[directory.__class__.__name__]
             for recordType in directory.recordTypes():
                 for record in directory.listRecords(recordType):
-                    recordResource = provisioningResource.principalForRecord(record)
-                    yield provisioningResource, recordType, recordResource, record
+                    recordResource = (yield provisioningResource.principalForRecord(record))
+                    results.append((provisioningResource, recordType, recordResource, record))
+        returnValue(results)
 
     def _checkPrivileges(self, resource, url, principal, privilege, allowed):
         request = SimpleRequest(self.site, "GET", "/")
@@ -497,9 +513,10 @@
         d.addCallback(gotResource)
         return d
 
+ at inlineCallbacks
 def _authReadOnlyPrivileges(self, resource, url):
     items = []
-    for provisioningResource, recordType, recordResource, record in self._allRecords():
+    for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
         if recordResource == resource:
             items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Read()  , True ))
             items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Write() , True ))
@@ -509,5 +526,7 @@
     items.append(( davxml.Unauthenticated() , davxml.Read()  , False ))
     items.append(( davxml.Unauthenticated() , davxml.Write() , False ))
             
+    results = []
     for principal, privilege, allowed in items:
-        yield resource, url, principal, privilege, allowed
+        results.append((resource, url, principal, privilege, allowed))
+    returnValue(results)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_proxyprincipalmembers.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_proxyprincipalmembers.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_proxyprincipalmembers.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -52,42 +52,38 @@
         provisioningResource = self.principalRootResources[self.directoryService.__class__.__name__]
         return provisioningResource.principalForShortName(type, name)
 
+    @inlineCallbacks
     def _groupMembersTest(self, recordType, recordName, subPrincipalName, expectedMembers):
-        def gotMembers(members):
-            memberNames = set([p.displayName() for p in members])
-            self.assertEquals(memberNames, set(expectedMembers))
 
-        principal = self._getPrincipalByShortName(recordType, recordName)
+        principal = (yield self._getPrincipalByShortName(recordType, recordName))
         if subPrincipalName is not None:
-            principal = principal.getChild(subPrincipalName)
+            principal = (yield principal.getChild(subPrincipalName))
 
-        d = principal.expandedGroupMembers()
-        d.addCallback(gotMembers)
-        return d
+        members = (yield principal.expandedGroupMembers())
+        memberNames = set([p.displayName() for p in members])
+        self.assertEquals(memberNames, set(expectedMembers))
 
+    @inlineCallbacks
     def _groupMembershipsTest(self, recordType, recordName, subPrincipalName, expectedMemberships):
-        def gotMemberships(memberships):
-            uids = set([p.principalUID() for p in memberships])
-            self.assertEquals(uids, set(expectedMemberships))
 
-        principal = self._getPrincipalByShortName(recordType, recordName)
+        principal = (yield self._getPrincipalByShortName(recordType, recordName))
         if subPrincipalName is not None:
-            principal = principal.getChild(subPrincipalName)
+            principal = (yield principal.getChild(subPrincipalName))
 
-        d = principal.groupMemberships()
-        d.addCallback(gotMemberships)
-        return d
+        memberships = (yield principal.groupMemberships())
+        uids = set([p.principalUID() for p in memberships])
+        self.assertEquals(uids, set(expectedMemberships))
     
     @inlineCallbacks
     def _addProxy(self, principal, subPrincipalName, proxyPrincipal):
 
         if isinstance(principal, tuple):
-            principal = self._getPrincipalByShortName(principal[0], principal[1])
-        principal = principal.getChild(subPrincipalName)
+            principal = (yield self._getPrincipalByShortName(principal[0], principal[1]))
+        principal = (yield principal.getChild(subPrincipalName))
         members = (yield principal.groupMembers())
 
         if isinstance(proxyPrincipal, tuple):
-            proxyPrincipal = self._getPrincipalByShortName(proxyPrincipal[0], proxyPrincipal[1])
+            proxyPrincipal = (yield self._getPrincipalByShortName(proxyPrincipal[0], proxyPrincipal[1]))
         members.add(proxyPrincipal)
         
         principal.setGroupMemberSetPrincipals(members)
@@ -95,11 +91,11 @@
     @inlineCallbacks
     def _removeProxy(self, recordType, recordName, subPrincipalName, proxyRecordType, proxyRecordName):
 
-        principal = self._getPrincipalByShortName(recordType, recordName)
-        principal = principal.getChild(subPrincipalName)
+        principal = (yield self._getPrincipalByShortName(recordType, recordName))
+        principal = (yield principal.getChild(subPrincipalName))
         members = (yield principal.groupMembers())
 
-        proxyPrincipal = self._getPrincipalByShortName(proxyRecordType, proxyRecordName)
+        proxyPrincipal = (yield self._getPrincipalByShortName(proxyRecordType, proxyRecordName))
         for p in members:
             if p.principalUID() == proxyPrincipal.principalUID():
                 members.remove(p)
@@ -107,16 +103,17 @@
         
         principal.setGroupMemberSetPrincipals(members)
 
+    @inlineCallbacks
     def _clearProxy(self, principal, subPrincipalName):
 
         if isinstance(principal, tuple):
-            principal = self._getPrincipalByShortName(principal[0], principal[1])
-        principal = principal.getChild(subPrincipalName)
+            principal = (yield self._getPrincipalByShortName(principal[0], principal[1]))
+        principal = (yield principal.getChild(subPrincipalName))
         principal.setGroupMemberSetPrincipals(set())
 
     @inlineCallbacks
     def _proxyForTest(self, recordType, recordName, expectedProxies, read_write):
-        principal = self._getPrincipalByShortName(recordType, recordName)
+        principal = (yield self._getPrincipalByShortName(recordType, recordName))
         proxies = (yield principal.proxyFor(read_write))
         proxies = set([principal.displayName() for principal in proxies])
         self.assertEquals(proxies, set(expectedProxies))
@@ -193,53 +190,46 @@
 
         return DeferredList(ds)
 
+    @inlineCallbacks
     def test_groupMembersProxyMissingUser(self):
         """
         DirectoryPrincipalResource.expandedGroupMembers()
         """
-        proxy = self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo")
-        proxyGroup = proxy.getChild("calendar-proxy-write")
+        proxy = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo"))
+        proxyGroup = (yield proxy.getChild("calendar-proxy-write"))
 
-        def gotMembers(members):
-            members.add("12345")
-            return proxyGroup._index().setGroupMembers("%s#calendar-proxy-write" % (proxy.principalUID(),), members)
 
-        def check(_):
-            return self._groupMembersTest(
-                DirectoryService.recordType_users, "cdaboo", "calendar-proxy-write",
-                (),
-            )
 
         # Setup the fake entry in the DB
-        d = proxyGroup._index().getMembers("%s#calendar-proxy-write" % (proxy.principalUID(),))
-        d.addCallback(gotMembers)
-        d.addCallback(check)
-        return d
+        members = (yield proxyGroup._index().getMembers("%s#calendar-proxy-write" % (proxy.principalUID(),)))
+        members.add("12345")
+        proxyGroup._index().setGroupMembers("%s#calendar-proxy-write" % (proxy.principalUID(),), members)
+        self._groupMembersTest(
+            DirectoryService.recordType_users, "cdaboo", "calendar-proxy-write",
+            (),
+        )
 
+
+    @inlineCallbacks
     def test_groupMembershipsMissingUser(self):
         """
         DirectoryPrincipalResource.expandedGroupMembers()
         """
         # Setup the fake entry in the DB
         fake_uid = "12345"
-        proxy = self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo")
-        proxyGroup = proxy.getChild("calendar-proxy-write")
+        proxy = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo"))
+        proxyGroup = (yield proxy.getChild("calendar-proxy-write"))
 
-        def gotMembers(members):
-            members.add("%s#calendar-proxy-write" % (proxy.principalUID(),))
-            return proxyGroup._index().setGroupMembers("%s#calendar-proxy-write" % (fake_uid,), members)
 
-        def check(_):
-            return self._groupMembershipsTest(
-                DirectoryService.recordType_users, "cdaboo", "calendar-proxy-write",
-                (),
-            )
+        members = (yield proxyGroup._index().getMembers("%s#calendar-proxy-write" % (fake_uid,)))
+        members.add("%s#calendar-proxy-write" % (proxy.principalUID(),))
+        proxyGroup._index().setGroupMembers("%s#calendar-proxy-write" % (fake_uid,), members)
+        self._groupMembershipsTest(
+            DirectoryService.recordType_users, "cdaboo", "calendar-proxy-write",
+            (),
+        )
 
-        d = proxyGroup._index().getMembers("%s#calendar-proxy-write" % (fake_uid,))
-        d.addCallback(gotMembers)
-        d.addCallback(check)
-        return d
-
+    @inlineCallbacks
     def test_setGroupMemberSet(self):
         class StubMemberDB(object):
             def __init__(self):
@@ -252,10 +242,9 @@
                 return self.members
 
 
-        user = self._getPrincipalByShortName(self.directoryService.recordType_users,
-                                           "cdaboo")
+        user = (yield self._getPrincipalByShortName(self.directoryService.recordType_users, "cdaboo"))
 
-        proxyGroup = user.getChild("calendar-proxy-write")
+        proxyGroup = (yield user.getChild("calendar-proxy-write"))
 
         memberdb = StubMemberDB()
 
@@ -275,15 +264,16 @@
                  "8B4288F6-CC82-491D-8EF9-642EF4F3E7D0"]))
 
 
+    @inlineCallbacks
     def test_setGroupMemberSetNotifiesPrincipalCaches(self):
         class StubCacheNotifier(object):
             changedCount = 0
             def changed(self):
                 self.changedCount += 1
 
-        user = self._getPrincipalByShortName(self.directoryService.recordType_users, "cdaboo")
+        user = (yield self._getPrincipalByShortName(self.directoryService.recordType_users, "cdaboo"))
 
-        proxyGroup = user.getChild("calendar-proxy-write")
+        proxyGroup = (yield user.getChild("calendar-proxy-write"))
 
         notifier = StubCacheNotifier()
 
@@ -367,8 +357,8 @@
 
         # Set up the in-memory (non-null) memcacher:
         config.ProcessType = "Single"
-        principal = self._getPrincipalByShortName(
-            DirectoryService.recordType_users, "wsanchez")
+        principal = (yield self._getPrincipalByShortName(
+            DirectoryService.recordType_users, "wsanchez"))
         db = principal._calendar_user_proxy_index()
 
         # Set the clock to the epoch:
@@ -379,13 +369,13 @@
         for doMembershipFirst in (True, False):
             for proxyType in ("calendar-proxy-read", "calendar-proxy-write"):
 
-                principal = self._getPrincipalByShortName(DirectoryService.recordType_users, "wsanchez")
-                proxyGroup = principal.getChild(proxyType)
+                principal = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "wsanchez"))
+                proxyGroup = (yield principal.getChild(proxyType))
 
-                testPrincipal = self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo")
+                testPrincipal = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo"))
 
-                fakePrincipal = self._getPrincipalByShortName(DirectoryService.recordType_users, "dreid")
-                fakeProxyGroup = fakePrincipal.getChild(proxyType)
+                fakePrincipal = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "dreid"))
+                fakeProxyGroup = (yield fakePrincipal.getChild(proxyType))
 
                 yield self._addProxy(
                     principal,
@@ -420,10 +410,10 @@
 
                 # Remove the dreid user from the directory service
 
-                delRec = self.directoryService.recordWithShortName(
-                    DirectoryService.recordType_users, "dreid")
+                delRec = (yield self.directoryService.recordWithShortName(
+                    DirectoryService.recordType_users, "dreid"))
                 for cache in self.directoryService._recordCaches.itervalues():
-                   cache.removeRecord(delRec)
+                   yield cache.removeRecord(delRec)
                 del self.directoryService._accounts()[
                     DirectoryService.recordType_users]["dreid"]
 
@@ -463,7 +453,7 @@
                     # Restore removed user
                     parser = XMLAccountsParser(self.directoryService.xmlFile)
                     self.directoryService._parsedAccounts = parser.items
-                    self.directoryService.recordWithShortName(
+                    yield self.directoryService.recordWithShortName(
                         DirectoryService.recordType_users, "dreid")
 
                     # Trigger the proxy DB clean up, which will actually
@@ -476,10 +466,10 @@
                     self.assertEquals(result, None)
 
                     # Remove the dreid user from the directory service
-                    delRec = self.directoryService.recordWithShortName(
-                        DirectoryService.recordType_users, "dreid")
+                    delRec = (yield self.directoryService.recordWithShortName(
+                        DirectoryService.recordType_users, "dreid"))
                     for cache in self.directoryService._recordCaches.itervalues():
-                       cache.removeRecord(delRec)
+                       yield cache.removeRecord(delRec)
                     del self.directoryService._accounts()[
                         DirectoryService.recordType_users]["dreid"]
 

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_sudo.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_sudo.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_sudo.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -16,6 +16,7 @@
 import os
 
 from twisted.python.filepath import FilePath
+from twisted.internet.defer import inlineCallbacks
 
 import twistedcaldav.directory.test.util
 from twistedcaldav.directory.sudo import SudoDirectoryService
@@ -57,19 +58,21 @@
             self.assertEqual(self.sudoers[record.shortNames[0]]['password'],
                              record.password)
 
+    @inlineCallbacks
     def test_recordWithShortName(self):
         service = self.service()
 
-        record = service.recordWithShortName(self.recordType, 'alice')
+        record = (yield service.recordWithShortName(self.recordType, 'alice'))
         self.assertEquals(record.password, 'alice')
 
-        record = service.recordWithShortName(self.recordType, 'bob')
+        record = (yield service.recordWithShortName(self.recordType, 'bob'))
         self.failIf(record)
 
+    @inlineCallbacks
     def test_calendaringDisabled(self):
         service = self.service()
 
-        record = service.recordWithShortName(self.recordType, 'alice')
+        record = (yield service.recordWithShortName(self.recordType, 'alice'))
 
         self.failIf(record.enabledForCalendaring,
                     "sudoers should have enabledForCalendaring=False")

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_xmlfile.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_xmlfile.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_xmlfile.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -99,6 +99,7 @@
     def service(self):
         return XMLDirectoryService({'xmlFile' : self.xmlFile()}, alwaysStat=True)
 
+    @inlineCallbacks
     def test_changedXML(self):
         service = self.service()
 
@@ -123,7 +124,7 @@
         ):
             # Fault records in
             for name in expectedRecords:
-                service.recordWithShortName(recordType, name)
+                yield service.recordWithShortName(recordType, name)
 
             self.assertEquals(
                 set(r.shortNames[0] for r in service.listRecords(recordType)),
@@ -156,16 +157,17 @@
         ):
             # Fault records in
             for name in expectedRecords:
-                service.recordWithShortName(recordType, name)
+                yield service.recordWithShortName(recordType, name)
 
             self.assertEquals(
                 set(r.shortNames[0] for r in service.listRecords(recordType)),
                 set(expectedRecords)
             )
         resourceInfoDatabase = ResourceInfoDatabase(config.DataRoot)
-        self.assertTrue((yield resourceInfoDatabase.getAutoSchedule(service.recordWithShortName(DirectoryService.recordType_locations, "my office").guid)))
+        self.assertTrue((yield resourceInfoDatabase.getAutoSchedule((yield service.recordWithShortName(DirectoryService.recordType_locations, "my office")).guid)))
 
 
+    @inlineCallbacks
     def test_okDisableCalendar(self):
         service = self.service()
 
@@ -195,7 +197,7 @@
         ):
             # Fault records in
             for name in expectedRecords:
-                service.recordWithShortName(recordType, name)
+                yield service.recordWithShortName(recordType, name)
 
             self.assertEquals(
                 set(r.shortNames[0] for r in service.listRecords(recordType)),
@@ -203,8 +205,8 @@
             )
 
         # All groups are disabled
-        self.assertFalse(service.recordWithShortName(DirectoryService.recordType_groups, "enabled").enabledForCalendaring)
-        self.assertFalse(service.recordWithShortName(DirectoryService.recordType_groups, "disabled").enabledForCalendaring)
+        self.assertFalse((yield service.recordWithShortName(DirectoryService.recordType_groups, "enabled")).enabledForCalendaring)
+        self.assertFalse((yield service.recordWithShortName(DirectoryService.recordType_groups, "disabled")).enabledForCalendaring)
 
     @inlineCallbacks
     def test_okProxies(self):
@@ -241,7 +243,7 @@
         ):
             # Fault records in
             for name in expectedRecords:
-                service.recordWithShortName(recordType, name)
+                yield service.recordWithShortName(recordType, name)
 
             self.assertEquals(
                 set(r.shortNames[0] for r in service.listRecords(recordType)),

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/util.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/util.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/util.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -14,6 +14,7 @@
 # limitations under the License.
 ##
 
+from twisted.internet.defer import inlineCallbacks
 from twisted.trial.unittest import SkipTest
 from twisted.cred.credentials import UsernamePassword
 from twisted.web2.auth.digest import DigestedCredentials, calcResponse, calcHA1
@@ -65,6 +66,7 @@
 
         self.assertEquals(set(self.service().recordTypes()), self.recordTypes)
 
+    @inlineCallbacks
     def test_recordWithShortName(self):
         """
         IDirectoryService.recordWithShortName()
@@ -80,17 +82,18 @@
 
             service = self.service()
             for shortName, info in data.iteritems():
-                record = service.recordWithShortName(info.get("prefix", "") + recordType, shortName)
+                record = (yield service.recordWithShortName(info.get("prefix", "") + recordType, shortName))
                 self.failUnless(record, "No record (%s)%s" % (info.get("prefix", "") + recordType, shortName))
                 self.compare(record, shortName, data[shortName])
 
             for prefix in self.recordTypePrefixes:
                 try:
-                    record = service.recordWithShortName(prefix + recordType, "IDunnoWhoThisIsIReallyDont")
+                    record = (yield service.recordWithShortName(prefix + recordType, "IDunnoWhoThisIsIReallyDont"))
                 except UnknownRecordTypeError:
                     continue
                 self.assertEquals(record, None)
 
+    @inlineCallbacks
     def test_recordWithUID(self):
         service = self.service()
         record = None
@@ -98,19 +101,20 @@
         for shortName, what in self.allEntries():
             guid = what["guid"]
             if guid is not None:
-                record = service.recordWithUID(guid)
+                record = (yield service.recordWithUID(guid))
                 self.compare(record, shortName, what)
 
         if record is None:
             raise SkipTest("No GUIDs provided to test")
 
+    @inlineCallbacks
     def test_recordWithCalendarUserAddress(self):
         service = self.service()
         record = None
 
         for shortName, what in self.allEntries():
             for address in what["addresses"]:
-                record = service.recordWithCalendarUserAddress(address)
+                record = (yield service.recordWithCalendarUserAddress(address))
                 self.compare(record, shortName, what)
 
         if record is None:
@@ -126,7 +130,7 @@
         service = self.service()
         for group, info in self.groups.iteritems():
             prefix = info.get("prefix", "")
-            groupRecord = service.recordWithShortName(prefix + DirectoryService.recordType_groups, group)
+            groupRecord = (yield service.recordWithShortName(prefix + DirectoryService.recordType_groups, group))
             result = set((m.recordType, prefix + m.shortNames[0]) for m in groupRecord.members())
             expected = set(self.groups[group]["members"])
             self.assertEquals(
@@ -150,7 +154,7 @@
             service = self.service()
             for shortName, info in data.iteritems():
                 prefix = info.get("prefix", "")
-                record = service.recordWithShortName(prefix + recordType, shortName)
+                record = (yield service.recordWithShortName(prefix + recordType, shortName))
                 result = set(prefix + g.shortNames[0] for g in record.groups())
                 expected = set(g for g in self.groups if (record.recordType, shortName) in self.groups[g]["members"])
                 self.assertEquals(
@@ -261,6 +265,7 @@
     """
     Tests a directory implementation with basic auth.
     """
+    @inlineCallbacks
     def test_verifyCredentials_basic(self):
         """
         IDirectoryRecord.verifyCredentials() with basic
@@ -270,8 +275,8 @@
 
         service = self.service()
         for user in self.users:
-            userRecord = service.recordWithShortName(DirectoryService.recordType_users, user)
-            self.failUnless(userRecord.verifyCredentials(UsernamePassword(user, self.users[user]["password"])))
+            userRecord = (yield service.recordWithShortName(DirectoryService.recordType_users, user))
+            self.failUnless((yield userRecord.verifyCredentials(UsernamePassword(user, self.users[user]["password"]))))
 
 # authRequest = {
 #    username="username",
@@ -290,6 +295,7 @@
     """
     Tests a directory implementation with digest auth.
     """
+    @inlineCallbacks
     def test_verifyCredentials_digest(self):
         """
         IDirectoryRecord.verifyCredentials() with digest
@@ -300,7 +306,7 @@
         service = self.service()
         for user in self.users:
             for good in (True, True, False, False, True):
-                userRecord = service.recordWithShortName(DirectoryService.recordType_users, user)
+                userRecord = (yield service.recordWithShortName(DirectoryService.recordType_users, user))
 
                 # I'm glad this is so simple...
                 response = calcResponse(
@@ -342,6 +348,6 @@
                 )
 
                 if good:
-                    self.failUnless(userRecord.verifyCredentials(credentials))
+                    self.failUnless((yield userRecord.verifyCredentials(credentials)))
                 else:
-                    self.failIf(userRecord.verifyCredentials(credentials))
+                    self.failIf((yield userRecord.verifyCredentials(credentials)))

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/wiki.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/wiki.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/wiki.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -75,10 +75,10 @@
             record = self.byShortName[shortName]
             self.log_info("Returning existing wiki record with UID %s" %
                 (record.uid,))
-            return record
+            return succeed(record)
 
         record = self._addRecord(shortName)
-        return record
+        return succeed(record)
 
     def recordWithUID(self, uid):
 
@@ -86,14 +86,14 @@
             record = self.byUID[uid]
             self.log_info("Returning existing wiki record with UID %s" %
                 (record.uid,))
-            return record
+            return succeed(record)
 
         if uid.startswith(self.UIDPrefix):
             shortName = uid[len(self.UIDPrefix):]
             record = self._addRecord(shortName)
-            return record
+            return succeed(record)
         else:
-            return None
+            return succeed(None)
 
     def _addRecord(self, shortName):
 

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/xmlfile.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/xmlfile.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -28,6 +28,7 @@
 from twisted.cred.credentials import UsernamePassword
 from twisted.web2.auth.digest import DigestedCredentials
 from twisted.python.filepath import FilePath
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 
 from twistedcaldav.directory.directory import DirectoryService
 from twistedcaldav.directory.cachingdirectory import CachingDirectoryService,\
@@ -96,7 +97,10 @@
                     )
                     self.recordCacheForType(recordType).addRecord(record,
                         indexType, indexKey)
+
+        return succeed(None)
             
+    @inlineCallbacks
     def recordsMatchingFields(self, fields, operand="or", recordType=None):
         # Default, brute force method search of underlying XML data
 
@@ -155,15 +159,17 @@
         else:
             recordTypes = (recordType,)
 
+        results = []
         for recordType in recordTypes:
             for xmlPrincipal in self._accounts()[recordType].itervalues():
                 if xmlPrincipalMatches(xmlPrincipal):
-                    
                     # Load/cache record from its GUID
-                    record = self.recordWithGUID(xmlPrincipal.guid)
+                    record = (yield self.recordWithGUID(xmlPrincipal.guid))
                     if record:
-                        yield record
+                        results.append(record)
 
+        returnValue(results)
+
     def _accounts(self):
         currentTime = time()
         if self._alwaysStat or currentTime - self._lastCheck > 60:
@@ -199,18 +205,26 @@
         self._members          = xmlPrincipal.members
         self._groups           = xmlPrincipal.groups
 
+    @inlineCallbacks
     def members(self):
+        results = []
         for recordType, shortName in self._members:
-            yield self.service.recordWithShortName(recordType, shortName)
+            record = (yield self.service.recordWithShortName(recordType, shortName))
+            results.append(record)
+        returnValue(results)
 
+    @inlineCallbacks
     def groups(self):
+        results = []
         for shortName in self._groups:
-            yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName)
+            record = (yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName))
+            results.append(record)
+        returnValue(results)
 
     def verifyCredentials(self, credentials):
         if isinstance(credentials, UsernamePassword):
-            return credentials.password == self.password
+            return succeed(credentials.password == self.password)
         if isinstance(credentials, DigestedCredentials):
-            return credentials.checkPassword(self.password)
+            return succeed(credentials.checkPassword(self.password))
 
         return super(XMLDirectoryRecord, self).verifyCredentials(credentials)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -163,6 +163,7 @@
             request.authzUser = davxml.Principal(davxml.Unauthenticated())
             returnValue((request.authnUser, request.authzUser,))
 
+    @inlineCallbacks
     def principalsForAuthID(self, request, creds):
         """
         Return authentication and authorization prinicipal identifiers
@@ -180,17 +181,17 @@
             HTTPError(responsecode.FORBIDDEN) if the principal isn't
             found.
         """
-        authnPrincipal = self.findPrincipalForAuthID(creds)
+        authnPrincipal = (yield self.findPrincipalForAuthID(creds))
 
         if authnPrincipal is None:
             log.info("Could not find the principal resource for user id: %s"
                      % (creds.username,))
             raise HTTPError(responsecode.FORBIDDEN)
 
-        d = self.authorizationPrincipal(request, creds.username, authnPrincipal)
-        d.addCallback(lambda authzPrincipal: (authnPrincipal, authzPrincipal))
-        return d
+        authzPrincipal = (yield self.authorizationPrincipal(request, creds.username, authnPrincipal))
+        returnValue((authnPrincipal, authzPrincipal))
 
+    @inlineCallbacks
     def findPrincipalForAuthID(self, creds):
         """
         Return an authentication and authorization principal
@@ -198,20 +199,20 @@
         Check for sudo users before regular users.
         """
         if type(creds) is str:
-            return super(SudoSACLMixin, self).findPrincipalForAuthID(creds)
+            returnValue((yield super(SudoSACLMixin, self).findPrincipalForAuthID(creds)))
 
         for collection in self.principalCollections():
-            principal = collection.principalForShortName(
+            principal = (yield collection.principalForShortName(
                 SudoDirectoryService.recordType_sudoers, 
-                creds.username)
+                creds.username))
             if principal is not None:
-                return principal
+                returnValue(principal)
 
         for collection in self.principalCollections():
-            principal = collection.principalForAuthID(creds)
+            principal = (yield collection.principalForAuthID(creds))
             if principal is not None:
-                return principal
-        return None
+                returnValue(principal)
+        returnValue(None)
 
     @inlineCallbacks
     def authorizationPrincipal(self, request, authID, authnPrincipal):
@@ -238,31 +239,33 @@
             # Substitute the authz value for principal look up
             authz = authz[0]
 
+        @inlineCallbacks
         def getPrincipalForType(type, name):
             for collection in self.principalCollections():
-                principal = collection.principalForShortName(type, name)
+                principal = (yield collection.principalForShortName(type, name))
                 if principal:
-                    return principal
+                    returnValue(principal)
 
+        @inlineCallbacks
         def isSudoUser(authzID):
-            if getPrincipalForType(SudoDirectoryService.recordType_sudoers, authzID):
-                return True
-            return False
+            if (yield getPrincipalForType(SudoDirectoryService.recordType_sudoers, authzID)):
+                returnValue(True)
+            returnValue(False)
 
         if (
             hasattr(authnPrincipal, "record") and
             authnPrincipal.record.recordType == SudoDirectoryService.recordType_sudoers
         ):
             if authz:
-                if isSudoUser(authz):
+                if (yield isSudoUser(authz)):
                     log.info("Cannot proxy as another proxy: user %r as user %r"
                              % (authID, authz))
                     raise HTTPError(responsecode.FORBIDDEN)
                 else:
-                    authzPrincipal = getPrincipalForType(DirectoryService.recordType_users, authz)
+                    authzPrincipal = (yield getPrincipalForType(DirectoryService.recordType_users, authz))
 
                     if not authzPrincipal:
-                        authzPrincipal = self.findPrincipalForAuthID(authz)
+                        authzPrincipal = (yield self.findPrincipalForAuthID(authz))
 
                     if authzPrincipal is not None:
                         log.info("Allow proxy: user %r as %r"
@@ -436,7 +439,7 @@
                 operand=operand, cuType=cuType))
 
             for record in records:
-                resource = principalCollection.principalForRecord(record)
+                resource = (yield principalCollection.principalForRecord(record))
                 matchingResources.append(resource)
 
                 # We've determined this is a matching resource
@@ -1076,7 +1079,7 @@
     ):
         # Permissions here are fixed, and are not subject to                    
         # inheritance rules, etc.                                               
-        return succeed(self.defaultAccessControlList())
+        return self.defaultAccessControlList()
 
 class PropertyNotFoundError (HTTPError):
     def __init__(self, qname):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -93,7 +93,7 @@
                     davxml.Protected(),
                 ),
             )
-        return davxml.ACL(*aces)
+        return succeed(davxml.ACL(*aces))
 
     def resourceType(self):
         return succeed(davxml.ResourceType.freebusyurl)
@@ -199,7 +199,7 @@
         # TODO: We should probably verify that the actual time-range is within sensible bounds (e.g. not too far in the past or future and not too long)
         
         # Now lookup the principal details for the targeted user
-        principal = self.parent.principalForRecord()
+        principal = (yield self.parent.principalForRecord())
         
         # Pick the first mailto cu address or the first other type
         cuaddr = None
@@ -211,7 +211,7 @@
                 break
 
         # Get inbox details
-        inboxURL = yield principal.scheduleInboxURL(request)
+        inboxURL = (yield principal.scheduleInboxURL(request))
         if inboxURL is None:
             raise HTTPError(StatusResponse(responsecode.INTERNAL_SERVER_ERROR, "No schedule inbox URL for principal: %s" % (principal,)))
         try:

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -846,7 +846,7 @@
             C{resource.isPseudoCalendarCollection()} returns C{True}.)
         """
         # MOR: isCalendarCollection( ) is now deferred.  What to do here?
-        assert resource.isPseudoCalendarCollection() and not resource.isCalendarCollection(), "non-calendar collection resource %s has no index." % (resource,)
+        # assert resource.isPseudoCalendarCollection() and not resource.isCalendarCollection(), "non-calendar collection resource %s has no index." % (resource,)
         super(IndexSchedule, self).__init__(resource)
 
     def reserveUID(self, uid): #@UnusedVariable

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -196,14 +196,15 @@
         self.parent = parent
 
 
+    @inlineCallbacks
     def accessControlList(self, request, inheritance=True,
         expanding=False, inherited_aces=None):
 
         if not hasattr(self, "iMIPACL"):
 
             for principalCollection in self.principalCollections():
-                principal = principalCollection.principalForShortName("users",
-                    config.Scheduling.iMIP.Username)
+                principal = (yield principalCollection.principalForShortName("users",
+                    config.Scheduling.iMIP.Username))
                 if principal is not None:
                     break
             else:
@@ -222,7 +223,7 @@
                 ),
             )
 
-        return succeed(self.iMIPACL)
+        returnValue(self.iMIPACL)
 
     def resourceType(self):
         return succeed(davxml.ResourceType.ischeduleinbox)
@@ -280,13 +281,15 @@
         )
         if config.Scheduling.CalDAV.OldDraftCompatibility:
             privs += (davxml.Privilege(caldavxml.Schedule()),)
-        return davxml.ACL(
-            # DAV:Read, CalDAV:schedule-deliver for all principals (includes anonymous)
-            davxml.ACE(
-                davxml.Principal(davxml.All()),
-                davxml.Grant(*privs),
-                davxml.Protected(),
-            ),
+        return succeed(
+            davxml.ACL(
+                # DAV:Read, CalDAV:schedule-deliver for all principals (includes anonymous)
+                davxml.ACE(
+                    davxml.Principal(davxml.All()),
+                    davxml.Grant(*privs),
+                    davxml.Protected(),
+                ),
+            )
         )
 
     def supportedPrivileges(self, request):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -253,9 +253,9 @@
                 access = None
 
             if calendar:
-                propvalue = yield property.elementFromCalendarWithAccessRestrictions(calendar, access, timezone)
+                propvalue = (yield property.elementFromCalendarWithAccessRestrictions(calendar, access, timezone))
             else:
-                propvalue = yield property.elementFromResourceWithAccessRestrictions(resource, access, timezone)
+                propvalue = (yield property.elementFromResourceWithAccessRestrictions(resource, access, timezone))
             if propvalue is None:
                 raise ValueError("Invalid CalDAV:calendar-data for request: %r" % (property,))
             properties_by_status[responsecode.OK].append(propvalue)
@@ -318,7 +318,7 @@
             returnValue(matchtotal)
 
     # May need organizer principal
-    organizer_principal = calresource.principalForCalendarUserAddress(organizer) if organizer else None
+    organizer_principal = (yield calresource.principalForCalendarUserAddress(organizer)) if organizer else None
     organizer_uid = organizer_principal.principalUID() if organizer_principal else ""
 
     #
@@ -352,9 +352,9 @@
     filteredaces = (yield calresource.inheritedACEsforChildren(request))
 
     try:
-        resources = yield calresource.index().indexedSearch(filter, fbtype=True)
+        resources = (yield calresource.index().indexedSearch(filter, fbtype=True))
     except IndexedSearchException:
-        resources = yield calresource.index().bruteForceSearch()
+        resources = (yield calresource.index().bruteForceSearch())
 
     # We care about separate instances for VEVENTs only
     aggregated_resources = {}
@@ -387,7 +387,7 @@
                 if excludeuid:
                     # See if we have a UID match
                     if (excludeuid == uid):
-                        test_principal = calresource.principalForCalendarUserAddress(test_organizer) if test_organizer else None
+                        test_principal = (yield calresource.principalForCalendarUserAddress(test_organizer)) if test_organizer else None
                         test_uid = test_principal.principalUID() if test_principal else ""
 
                         # Check that ORGANIZER's match (security requirement)
@@ -417,7 +417,7 @@
                     fbinfo[fbtype_index_mapper.get(fbtype, 0)].append(clipped)
                 
         else:
-            calendar = yield calresource.iCalendar(name)
+            calendar = (yield calresource.iCalendar(name))
             
             # The calendar may come back as None if the resource is being changed, or was deleted
             # between our initial index query and getting here. For now we will ignore this error, but in
@@ -431,7 +431,7 @@
                 # See if we have a UID match
                 if (excludeuid == uid):
                     test_organizer = calendar.getOrganizer()
-                    test_principal = calresource.principalForCalendarUserAddress(test_organizer) if test_organizer else None
+                    test_principal = (yield calresource.principalForCalendarUserAddress(test_organizer)) if test_organizer else None
                     test_uid = test_principal.principalUID() if test_principal else ""
     
                     # Check that ORGANIZER's match (security requirement)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -138,7 +138,7 @@
             for href in resources:
                 resource_uri = str(href)
                 name = unquote(resource_uri[resource_uri.rfind("/") + 1:])
-                if not self._isChildURI(request, resource_uri) or self.getChild(name) is None:
+                if not self._isChildURI(request, resource_uri) or (yield self.getChild(name)) is None:
                     responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.NOT_FOUND)))
                 else:
                     valid_names.append(name)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -262,7 +262,7 @@
                     fbset = (yield principal.calendarFreeBusyURIs(request))
                     url = (yield self.canonicalURL(request))
                     opaque = url in fbset
-                    (yield self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()) if opaque else caldavxml.Transparent()))
+                    yield self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque() if opaque else caldavxml.Transparent()))
 
         result = (yield super(CalDAVResource, self).readProperty(property, request))
         returnValue(result)
@@ -671,6 +671,7 @@
         """
         return self.iCalendar(name).addCallback(caldavxml.CalendarData.fromCalendar)
 
+    # Deferred
     def iCalendarAddressDoNormalization(self, ical):
         """
         Normalize calendar user addresses in the supplied iCalendar object into their
@@ -680,24 +681,26 @@
         @type ical: L{Component}
         """
 
+        @inlineCallbacks
         def lookupFunction(cuaddr):
-            principal = self.principalForCalendarUserAddress(cuaddr)
+            principal = (yield self.principalForCalendarUserAddress(cuaddr))
             if principal is None:
-                return (None, None, None)
+                returnValue((None, None, None))
             else:
-                return (principal.record.fullName.decode("utf-8"),
+                returnValue((principal.record.fullName.decode("utf-8"),
                     principal.record.guid,
-                    principal.record.calendarUserAddresses)
+                    principal.record.calendarUserAddresses))
 
-        ical.normalizeCalendarUserAddresses(lookupFunction)
+        return ical.normalizeCalendarUserAddresses(lookupFunction)
 
 
+    @inlineCallbacks
     def principalForCalendarUserAddress(self, address):
         for principalCollection in self.principalCollections():
-            principal = principalCollection.principalForCalendarUserAddress(address)
+            principal = (yield principalCollection.principalForCalendarUserAddress(address))
             if principal is not None:
-                return principal
-        return None
+                returnValue(principal)
+        returnValue(None)
 
     def supportedReports(self):
         result = super(CalDAVResource, self).supportedReports()
@@ -794,7 +797,7 @@
         return succeed(False)
 
     def principalForCalendarUserAddress(self, address):
-        return None
+        return succeed(None)
 
     def supportedReports(self):
         """

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -98,12 +98,14 @@
         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),
-            ),
+        return succeed(
+            davxml.ACL(
+                # CalDAV:schedule-deliver for any authenticated user
+                davxml.ACE(
+                    davxml.Principal(davxml.Authenticated()),
+                    davxml.Grant(*privs),
+                ),
+            )
         )
 
     @inlineCallbacks
@@ -221,7 +223,7 @@
         defaultCalendarURL = (yield joinURL(calendarHomeURL, "calendar"))
         defaultCalendar = (yield request.locateResource(defaultCalendarURL))
         if defaultCalendar is None or not defaultCalendar.exists():
-            self.parent.provisionDefaultCalendars()
+            yield self.parent.provisionDefaultCalendars()
         else:
             yield self.writeDeadProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(defaultCalendarURL)))
         returnValue(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(defaultCalendarURL)))
@@ -233,9 +235,10 @@
     Extends L{DAVResource} to provide CalDAV functionality.
     """
 
+    @inlineCallbacks
     def defaultAccessControlList(self):
         if config.EnableProxyPrincipals:
-            myPrincipal = self.parent.principalForRecord()
+            myPrincipal = (yield self.parent.principalForRecord())
     
             privs = (
                 davxml.Privilege(caldavxml.ScheduleSend()),
@@ -243,16 +246,16 @@
             if config.Scheduling.CalDAV.OldDraftCompatibility:
                 privs += (davxml.Privilege(caldavxml.Schedule()),)
     
-            return davxml.ACL(
+            returnValue(davxml.ACL(
                 # CalDAV:schedule for associated write proxies
                 davxml.ACE(
                     davxml.Principal(davxml.HRef(joinURL(myPrincipal.principalURL(), "calendar-proxy-write"))),
                     davxml.Grant(*privs),
                     davxml.Protected(),
                 ),
-            )
+            ))
         else:
-            return super(ScheduleOutboxResource, self).defaultAccessControlList()
+            returnValue((yield super(ScheduleOutboxResource, self).defaultAccessControlList()))
 
     def resourceType(self):
         return succeed(davxml.ResourceType.scheduleOutbox)
@@ -302,13 +305,15 @@
         if config.Scheduling.CalDAV.OldDraftCompatibility:
             privs += (davxml.Privilege(caldavxml.Schedule()),)
 
-        return davxml.ACL(
-            # DAV:Read, CalDAV:schedule-deliver for all principals (includes anonymous)
-            davxml.ACE(
-                davxml.Principal(davxml.All()),
-                davxml.Grant(*privs),
-                davxml.Protected(),
-            ),
+        return succeed(
+            davxml.ACL(
+                # DAV:Read, CalDAV:schedule-deliver for all principals (includes anonymous)
+                davxml.ACE(
+                    davxml.Principal(davxml.All()),
+                    davxml.Grant(*privs),
+                    davxml.Protected(),
+                ),
+            )
         )
 
     def resourceType(self):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -192,7 +192,7 @@
                 except ValueError:
                     # We have different ORGANIZERs in the same iCalendar object - this is an error
                     returnValue(False)
-                organizerPrincipal = resource.principalForCalendarUserAddress(organizer) if organizer else None
+                organizerPrincipal = (yield resource.principalForCalendarUserAddress(organizer)) if organizer else None
                 yield resource.writeDeadProperty(TwistedSchedulingObjectResource("true" if organizerPrincipal != None else "false"))
                 log.debug("Implicit - checked scheduling object resource state for UID: '%s', result: %s" % (
                     calendar.resourceUID(),
@@ -274,7 +274,7 @@
         
         # Get some useful information from the calendar
         yield self.extractCalendarData()
-        self.organizerPrincipal = self.resource.principalForCalendarUserAddress(self.organizer)
+        self.organizerPrincipal = (yield self.resource.principalForCalendarUserAddress(self.organizer))
         self.organizerAddress = (yield addressmapping.mapper.getCalendarUser(self.organizer, self.organizerPrincipal))
 
         # Originator is the organizer in this case
@@ -418,7 +418,7 @@
             returnValue(False)
         
         # Organizer must map to a valid principal
-        self.organizerPrincipal = self.resource.principalForCalendarUserAddress(self.organizer)
+        self.organizerPrincipal = (yield self.resource.principalForCalendarUserAddress(self.organizer))
         self.organizerAddress = (yield addressmapping.mapper.getCalendarUser(self.organizer, self.organizerPrincipal))
         if not self.organizerPrincipal:
             returnValue(False)
@@ -429,21 +429,22 @@
 
         returnValue(True)
 
+    @inlineCallbacks
     def isAttendeeScheduling(self):
         
         # First must have organizer property
         if not self.organizer:
-            return False
+            returnValue(False)
         
         # Check to see whether any attendee is the owner
         for attendee in self.attendees:
-            attendeePrincipal = self.resource.principalForCalendarUserAddress(attendee)
+            attendeePrincipal = (yield self.resource.principalForCalendarUserAddress(attendee))
             if attendeePrincipal and attendeePrincipal.principalURL() == str(self.calendar_owner):
                 self.attendee = attendee
                 self.attendeePrincipal = attendeePrincipal
-                return True
+                returnValue(True)
         
-        return False
+        returnValue(False)
 
     @inlineCallbacks
     def doAccessControl(self, principal, is_organizer):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -436,20 +436,21 @@
             log.err("Unauthenticated originators not allowed: %s" % (self.originator,))
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
 
+    @inlineCallbacks
     def checkOriginator(self):
         """
         Check the validity of the Originator header. Extract the corresponding principal.
         """
     
         # Verify that Originator is a valid calendar user
-        originatorPrincipal = self.resource.principalForCalendarUserAddress(self.originator)
+        originatorPrincipal = (yield self.resource.principalForCalendarUserAddress(self.originator))
         if originatorPrincipal is None:
             # Local requests MUST have a principal.
             log.err("Could not find principal for originator: %s" % (self.originator,))
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
         else:
             # Must have a valid Inbox.
-            inboxURL = originatorPrincipal.scheduleInboxURL()
+            inboxURL = (yield originatorPrincipal.scheduleInboxURL())
             if inboxURL is None:
                 log.err("Could not find inbox for originator: %s" % (self.originator,))
                 raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
@@ -474,7 +475,7 @@
         results = []
         for recipient in self.recipients:
             # Get the principal resource for this recipient
-            principal = self.resource.principalForCalendarUserAddress(recipient)
+            principal = (yield self.resource.principalForCalendarUserAddress(recipient))
             
             # If no principal we may have a remote recipient but we should check whether
             # the address is one that ought to be on our server and treat that as a missing
@@ -487,7 +488,7 @@
             else:
                 # Map recipient to their inbox
                 inbox = None
-                inboxURL = yield principal.scheduleInboxURL()
+                inboxURL = (yield principal.scheduleInboxURL())
                 if inboxURL:
                     inbox = (yield self.request.locateResource(inboxURL))
 
@@ -508,7 +509,7 @@
         # Verify that the ORGANIZER's cu address maps to a valid user
         organizer = self.calendar.getOrganizer()
         if organizer:
-            organizerPrincipal = yield self.resource.principalForCalendarUserAddress(organizer)
+            organizerPrincipal = (yield self.resource.principalForCalendarUserAddress(organizer))
             if organizerPrincipal:
                 outboxURL = organizerPrincipal.scheduleOutboxURL()
                 if outboxURL:
@@ -547,6 +548,7 @@
         if self.doingPOST:
             return self.organizer.principal.scheduleOutboxURL().addCallback(_checkoutboxurl) 
 
+    @inlineCallbacks
     def checkAttendeeAsOriginator(self):
         """
         Check the validity of the ATTENDEE value as this is the originator of the iTIP message.
@@ -559,22 +561,20 @@
         # Must have only one
         if len(attendees) != 1:
             log.err("Wrong number of ATTENDEEs in calendar data: %s" % (self.calendar,))
-            return fail(HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed"))))
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
         attendee = attendees[0]
     
         # Attendee's Outbox MUST be the request URI
-        attendeePrincipal = self.resource.principalForCalendarUserAddress(attendee)
+        attendeePrincipal = (yield self.resource.principalForCalendarUserAddress(attendee))
         if attendeePrincipal:
-            d = attendeePrincipal.scheduleOutboxURL()
-            def _gotOutboxURL(outboxURL):
-                if self.doingPOST and outboxURL != self.request.uri:
-                    log.err("ATTENDEE in calendar data does not match owner of Outbox: %s" % (self.calendar,))
-                    raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
+            outboxURL = (yield attendeePrincipal.scheduleOutboxURL())
+            if self.doingPOST and outboxURL != self.request.uri:
+                log.err("ATTENDEE in calendar data does not match owner of Outbox: %s" % (self.calendar,))
+                raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
 
-            return d.addCallback(_gotOutboxURL)
         else:
             log.err("Unknown ATTENDEE in calendar data: %s" % (self.calendar,))
-            return fail(HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed"))))
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
     
 
     def securityChecks(self):
@@ -635,7 +635,7 @@
         """
     
         # For remote requests we do not allow the originator to be a local user or one within our domain.
-        originatorPrincipal = self.resource.principalForCalendarUserAddress(self.originator)
+        originatorPrincipal = (yield self.resource.principalForCalendarUserAddress(self.originator))
         localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(self.originator))
         if originatorPrincipal or localUser:
             log.err("Cannot use originator that is on this server: %s" % (self.originator,))
@@ -696,7 +696,7 @@
         results = []
         for recipient in self.recipients:
             # Get the principal resource for this recipient
-            principal = self.resource.principalForCalendarUserAddress(recipient)
+            principal = (yield self.resource.principalForCalendarUserAddress(recipient))
             
             # If no principal we may have a remote recipient but we should check whether
             # the address is one that ought to be on our server and treat that as a missing
@@ -711,7 +711,7 @@
             else:
                 # Map recipient to their inbox
                 inbox = None
-                inboxURL = yield principal.scheduleInboxURL()
+                inboxURL = (yield principal.scheduleInboxURL())
                 if inboxURL:
                     inbox = (yield self.request.locateResource(inboxURL))
 
@@ -738,7 +738,7 @@
         # Verify that the ORGANIZER's cu address does not map to a valid user
         organizer = self.calendar.getOrganizer()
         if organizer:
-            organizerPrincipal = self.resource.principalForCalendarUserAddress(organizer)
+            organizerPrincipal = (yield self.resource.principalForCalendarUserAddress(organizer))
             if organizerPrincipal:
                 log.err("Invalid ORGANIZER in calendar data: %s" % (self.calendar,))
                 raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
@@ -770,7 +770,7 @@
         attendee = attendees[0]
     
         # Attendee cannot be local.
-        attendeePrincipal = self.resource.principalForCalendarUserAddress(attendee)
+        attendeePrincipal = (yield self.resource.principalForCalendarUserAddress(attendee))
         if attendeePrincipal:
             log.err("Invalid ATTENDEE in calendar data: %s" % (self.calendar,))
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
@@ -865,7 +865,7 @@
         """
     
         # For remote requests we do not allow the originator to be a local user or one within our domain.
-        originatorPrincipal = self.resource.principalForCalendarUserAddress(self.originator)
+        originatorPrincipal = (yield self.resource.principalForCalendarUserAddress(self.originator))
         localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(self.originator))
         if originatorPrincipal or localUser:
             log.err("Cannot use originator that is on this server: %s" % (self.originator,))
@@ -883,7 +883,7 @@
         results = []
         for recipient in self.recipients:
             # Get the principal resource for this recipient
-            principal = self.resource.principalForCalendarUserAddress(recipient)
+            principal = (yield self.resource.principalForCalendarUserAddress(recipient))
             
             # If no principal we may have a remote recipient but we should check whether
             # the address is one that ought to be on our server and treat that as a missing
@@ -898,7 +898,7 @@
             else:
                 # Map recipient to their inbox
                 inbox = None
-                inboxURL = yield principal.scheduleInboxURL()
+                inboxURL = (yield principal.scheduleInboxURL())
                 if inboxURL:
                     inbox = (yield self.request.locateResource(inboxURL))
 

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -97,7 +97,7 @@
         return succeed(cls(path, *args, **kwargs))
 
     def __repr__(self):
-        # MOR: I don't think we can defer __repr__ even though isCalendarCollection( ) now is
+        # MOR: I don't think we can defer __repr__, can we? Problem is, isCalendarCollection( ) now is deferred
         if False and self.isCalendarCollection():
             return "<%s (calendar collection): %s>" % (self.__class__.__name__, self.fp.path)
         else:
@@ -555,11 +555,10 @@
 
 class AutoProvisioningFileMixIn (AutoProvisioningResourceMixIn):
 
+    @inlineCallbacks
     def provision(self):
-        # MOR: Double check this:
-        d = self.provisionFile()
-        d.addCallback(super(AutoProvisioningFileMixIn, self).provision)
-        return d
+        yield self.provisionFile()
+        returnValue((yield super(AutoProvisioningFileMixIn, self).provision()))
 
     @inlineCallbacks
     def provisionFile(self, request=None):
@@ -644,7 +643,7 @@
 
     @inlineCallbacks
     def provisionChild(self, name):
-        record = self.directory.recordWithUID(name)
+        record = (yield self.directory.recordWithUID(name))
 
         if record is None:
             log.msg("No directory record with GUID %r" % (name,))
@@ -668,7 +667,7 @@
                 # Pre 2.0: All in one directory
                 self.fp.child(name),
                 # Pre 1.2: In types hierarchy instead of the GUID hierarchy
-                (yield self.parent.getChild(record.recordType).fp.child(record.shortNames[0])),
+                (yield (yield self.parent.getChild(record.recordType)).fp.child(record.shortNames[0])),
             ):
                 if oldPath.exists():
                     # The child exists at an old location.  Move to new location.

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_mkcalendar.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_mkcalendar.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_mkcalendar.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -92,7 +92,7 @@
                 (davxml.DisplayName.qname(), "Lisa's Events"),
                 (caldavxml.CalendarDescription.qname(), "Calendar restricted to events."),
             ):
-                stored = yield resource.readProperty(qname, None)
+                stored = (yield resource.readProperty(qname, None))
                 stored = str(stored)
                 if stored != value:
                     self.fail("MKCALENDAR failed to set property %s: %s != %s"

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -62,15 +62,17 @@
         self.cache = {}
 
     def defaultAccessControlList(self):
-        return davxml.ACL(
-            # DAV:Read for all principals (includes anonymous)
-            davxml.ACE(
-                davxml.Principal(davxml.All()),
-                davxml.Grant(
-                    davxml.Privilege(davxml.Read()),
+        return succeed(
+            davxml.ACL(
+                # DAV:Read for all principals (includes anonymous)
+                davxml.ACE(
+                    davxml.Principal(davxml.All()),
+                    davxml.Grant(
+                        davxml.Privilege(davxml.Read()),
+                    ),
+                    davxml.Protected(),
                 ),
-                davxml.Protected(),
-            ),
+            )
         )
 
     def resourceType(self):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/upgrade.py	2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/upgrade.py	2009-09-03 17:58:15 UTC (rev 4524)
@@ -86,24 +86,25 @@
     def normalizeCUAddrs(data, directory):
         cal = Component.fromString(data)
 
+        @inlineCallbacks
         def lookupFunction(cuaddr):
             try:
-                principal = directory.principalForCalendarUserAddress(cuaddr)
+                principal = (yield directory.principalForCalendarUserAddress(cuaddr))
             except Exception, e:
                 log.debug("Lookup of %s failed: %s" % (cuaddr, e))
                 principal = None
 
             if principal is None:
-                return (None, None, None)
+                returnValue((None, None, None))
             else:
-                return (principal.record.fullName.decode("utf-8"),
+                returnValue((principal.record.fullName.decode("utf-8"),
                     principal.record.guid,
-                    principal.record.calendarUserAddresses)
+                    principal.record.calendarUserAddresses))
 
-        cal.normalizeCalendarUserAddresses(lookupFunction)
+        yield cal.normalizeCalendarUserAddresses(lookupFunction)
 
         newData = str(cal)
-        return newData, not newData == data
+        returnValue((newData, not newData == data))
 
 
     def upgradeCalendarCollection(calPath, directory):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090903/b2bebadd/attachment-0001.html>


More information about the calendarserver-changes mailing list