[CalendarServer-changes] [5469] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Apr 12 13:22:36 PDT 2010


Revision: 5469
          http://trac.macosforge.org/projects/calendarserver/changeset/5469
Author:   cdaboo at apple.com
Date:     2010-04-12 13:22:32 -0700 (Mon, 12 Apr 2010)
Log Message:
-----------
Remove "search" and "searchall" address books, and find-shared REPORT. Fix up xmpp notifications
for address books.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
    CalendarServer/trunk/calendarserver/tap/util.py
    CalendarServer/trunk/conf/carddavd-apple.plist
    CalendarServer/trunk/conf/carddavd-test.plist
    CalendarServer/trunk/twistedcaldav/directory/addressbook.py
    CalendarServer/trunk/twistedcaldav/directory/principal.py
    CalendarServer/trunk/twistedcaldav/directorybackedaddressbook.py
    CalendarServer/trunk/twistedcaldav/resource.py
    CalendarServer/trunk/twistedcaldav/static.py
    CalendarServer/trunk/twistedcaldav/stdconfig.py
    CalendarServer/trunk/twistedcaldav/test/util.py

Removed Paths:
-------------
    CalendarServer/trunk/twistedcaldav/report_addressbook_findshared.py

Modified: CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/test/test_caldav.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/calendarserver/tap/test/test_caldav.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -291,6 +291,7 @@
         self.config.SSLCertificate = pemFile
         self.config.Memcached.Pools.Default.ClientEnabled = False
         self.config.Memcached.Pools.Default.ServerEnabled = False
+        self.config.DirectoryAddressBook.Enabled = False
 
         self.config.SudoersFile = ""
 

Modified: CalendarServer/trunk/calendarserver/tap/util.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/util.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/calendarserver/tap/util.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -268,34 +268,22 @@
 
     principalCollection = principalResourceClass("/principals/", directory)
 
-    log.info("Setting up calendar collection: %r" % (calendarResourceClass,))
+    if config.EnableCalDAV:
+        log.info("Setting up calendar collection: %r" % (calendarResourceClass,))
+        calendarCollection = calendarResourceClass(
+            os.path.join(config.DocumentRoot, "calendars"),
+            directory, "/calendars/",
+        )
 
-    calendarCollection = calendarResourceClass(
-        os.path.join(config.DocumentRoot, "calendars"),
-        directory, "/calendars/",
-    )
-
-    log.info("Setting up root resource: %r" % (rootResourceClass,))
-
-    root = rootResourceClass(
-        config.DocumentRoot,
-        principalCollections=(principalCollection,),
-    )
-
     if config.EnableCardDAV:
-        root.saclService = "addressbook" # XXX this needs to be dealt with
-                                         # differently if caldav and carddav
-                                         # are going to be in the same process
         log.info("Setting up address book collection: %r" % (addressBookResourceClass,))
-
         addressBookCollection = addressBookResourceClass(
             os.path.join(config.DocumentRoot, "addressbooks"),
             directory, "/addressbooks/"
         )
 
         directoryPath = os.path.join(config.DocumentRoot, "directory")
-        doBacking = config.DirectoryAddressBook and config.EnableSearchAddressBook
-        if doBacking:
+        if config.DirectoryAddressBook.Enabled:
             log.info("Setting up directory address book: %r" % (directoryBackedAddressBookResourceClass,))
 
             directoryBackedAddressBookCollection = directoryBackedAddressBookResourceClass(
@@ -315,13 +303,26 @@
                 if e.errno != errno.ENOENT:
                     log.error("Could not delete: %s : %r" %  (directoryPath, e,))
 
+    log.info("Setting up root resource: %r" % (rootResourceClass,))
+
+    root = rootResourceClass(
+        config.DocumentRoot,
+        principalCollections=(principalCollection,),
+    )
+
+    if config.EnableCardDAV and not config.EnableCalDAV:
+        # TODO need a better way to do this when both services are enabled
+        root.saclService = "addressbook"
+
+
+    root.putChild("principals", principalCollection)
+    if config.EnableCalDAV:
+        root.putChild("calendars", calendarCollection)
+    if config.EnableCardDAV:
         root.putChild('addressbooks', addressBookCollection)
-        if doBacking:
+        if config.DirectoryAddressBook.Enabled:
             root.putChild('directory', directoryBackedAddressBookCollection)
 
-    root.putChild("principals", principalCollection)
-    root.putChild("calendars", calendarCollection)
-
     # /.well-known
     if config.EnableWellKnown:
         log.info("Setting up .well-known collection resource")

Modified: CalendarServer/trunk/conf/carddavd-apple.plist
===================================================================
--- CalendarServer/trunk/conf/carddavd-apple.plist	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/conf/carddavd-apple.plist	2010-04-12 20:22:32 UTC (rev 5469)
@@ -16,7 +16,7 @@
     limitations under the License.
   -->
 
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
   <dict>
 
@@ -40,18 +40,6 @@
     <key>EnableCalDAV</key>
     <false/>
 
-    <key>ConfigRoot</key>
-    <string>/etc/carddavd</string>
-
-    <key>LogRoot</key>
-    <string>/var/log/carddavd</string>
-
-    <key>PIDFile</key>
-    <string>carddavd.pid</string>
-
-    <key>GlobalStatsSocket</key>
-    <string>carddavd-stats.sock</string>
-
     <key>ControlSocket</key>
     <string>carddavd.sock</string>
 
@@ -113,10 +101,6 @@
     <key>ConfigRoot</key>
     <string>/etc/carddavd</string>
 
-    <!-- Log root -->
-    <key>LogRoot</key>
-    <string>/var/log/carddavd</string>
-
     <!-- Run root -->
     <key>RunRoot</key>
     <string>/var/run</string>
@@ -133,7 +117,12 @@
        -->
     </dict>
 
-    <!-- User quota (in bytes) -->
+
+    <!--
+        Quotas and limits
+      -->
+
+    <!-- User quota (in bytes) [0 = no quota] -->
     <key>UserQuota</key>
     <integer>104857600</integer><!-- 100Mb -->
 
@@ -198,80 +187,8 @@
       </dict>
     </dict>
 
-    <!--
-        Augment service
 
-        Augments for the directory service records to add calendar specific attributes.
-
-        A variety of augment services are available for use.
-        When using a partitioned server, a service that can be accessed from each host will be needed.
-      -->
-
-    <!-- XML File Augment Service -->
-    <key>AugmentService</key>
-    <dict>
-      <key>type</key>
-      <string>twistedcaldav.directory.augment.AugmentXMLDB</string>
-      
-      <key>params</key>
-      <dict>
-        <key>xmlFiles</key>
-        <array>
-	      <string>augments.xml</string>
-        </array>
-      </dict>
-    </dict>
-    
-    <!-- Sqlite Augment Service -->
     <!--
-    <key>AugmentService</key>
-    <dict>
-      <key>type</key>
-      <string>twistedcaldav.directory.augment.AugmentSqliteDB</string>
-      
-      <key>params</key>
-      <dict>
-        <key>dbpath</key>
-        <string>augments.sqlite</string>
-      </dict>
-    </dict>
-     -->
-
-    <!-- PostgreSQL Augment Service -->
-    <!--
-    <key>AugmentService</key>
-    <dict>
-      <key>type</key>
-      <string>twistedcaldav.directory.augment.AugmentPostgreSQLDB</string>
-      
-      <key>params</key>
-      <dict>
-        <key>host</key>
-        <string>localhost</string>
-        <key>database</key>
-        <string>augments</string>
-      </dict>
-    </dict>
-     -->
-
-    <!-- PostgreSQL ProxyDB Service -->
-    <!--
-    <key>ProxyDBService</key>
-    <dict>
-      <key>type</key>
-      <string>twistedcaldav.directory.calendaruserproxy.ProxyPostgreSQLDB</string>
-      
-      <key>params</key>
-      <dict>
-        <key>host</key>
-        <string>localhost</string>
-        <key>database</key>
-        <string>proxies</string>
-      </dict>
-    </dict>
-     -->
-
-    <!--
         Special principals
 
         These principals are granted special access and/or perform
@@ -290,10 +207,6 @@
       <!-- <string>/principals/__uids__/983C8238-FB6B-4D92-9242-89C0A39E5F81/</string> -->
     </array>
 
-    <!-- Principals that can pose as other principals -->
-    <key>SudoersFile</key>
-    <string>sudoers.plist</string>
-
     <!-- Create "proxy access" principals -->
     <key>EnableProxyPrincipals</key>
     <true/>
@@ -368,6 +281,10 @@
         Logging
       -->
 
+    <!-- Log root -->
+    <key>LogRoot</key>
+    <string>/var/log/carddavd</string>
+
     <!-- Apache-style access log -->
     <key>AccessLogFile</key>
     <string>access.log</string>
@@ -439,7 +356,6 @@
         </dict>
     </dict>
 
-
     <!--
         Notifications
       -->
@@ -450,6 +366,10 @@
       <key>CoalesceSeconds</key>
       <integer>3</integer>
 
+      <!-- Client service port different from caldav -->
+      <key>InternalNotificationPort</key>
+      <integer>62311</integer>
+
       <key>Services</key>
       <dict>
         <key>XMPPNotifier</key>
@@ -568,7 +488,7 @@
     <key>FreeBusyURL</key>
     <dict>
       <key>Enabled</key>
-      <true/>
+      <false/>
       <key>TimePeriod</key>
       <integer>14</integer>
       <key>AnonymousAccess</key>
@@ -582,15 +502,15 @@
 
     <!-- Calendar Drop Box -->
     <key>EnableDropBox</key>
-    <true/>
+    <false/>
 
     <!-- Private Events -->
     <key>EnablePrivateEvents</key>
-    <true/>
+    <false/>
 
     <!-- Timezone Service -->
     <key>EnableTimezoneService</key>
-    <true/>
+    <false/>
 
 
     <!--
@@ -607,6 +527,9 @@
 
     <key>DirectoryAddressBook</key>
     <dict>
+    	<key>Enabled</key>
+    	<true/>
+
         <key>type</key>
         <string>twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService</string>
       
@@ -711,13 +634,6 @@
     <!--  allow unauthenticated users to access the directory address book -->
     <key>AnonymousDirectoryAddressBookAccess</key>
     <false/>
-    
-    <!--  enable search address book in user's home -->
-    <key>EnableSearchAddressBook</key>
-    <false/>
-    
-    <!--  enable find share report -->
-    <key>EnableFindSharedReport</key>
-    <false/>
+
   </dict>
 </plist>

Modified: CalendarServer/trunk/conf/carddavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/carddavd-test.plist	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/conf/carddavd-test.plist	2010-04-12 20:22:32 UTC (rev 5469)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <!--
-    Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+    Copyright (c) 2006-2010 Apple Inc. All rights reserved.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
     limitations under the License.
   -->
 
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
   <dict>
 
@@ -34,6 +34,9 @@
     <key>ServerHostName</key>
     <string></string> <!-- The hostname clients use when connecting -->
 
+    <key>EnableCalDAV</key>
+    <false/>
+
     <key>EnableCardDAV</key>
     <true/>
 
@@ -46,10 +49,11 @@
     <key>SSLPort</key>
     <integer>8843</integer>
 
-    <!-- Redirect non-SSL ports to an SSL port -->
+    <!-- Redirect non-SSL ports to an SSL port (if configured for SSL) -->
     <key>RedirectHTTPToHTTPS</key>
     <false/>
 
+
     <!--
         Network address configuration information
 
@@ -75,13 +79,14 @@
     <!--
         Data Store
       -->
+
     <!-- Server root -->
     <key>ServerRoot</key>
-    <string>data</string>
+    <string>./data</string>
 
     <!-- Data root -->
     <key>DataRoot</key>
-    <string>Data/</string>
+    <string>Data</string>
 
     <!-- Document root -->
     <key>DocumentRoot</key>
@@ -91,13 +96,9 @@
     <key>ConfigRoot</key>
     <string>./conf</string>
 
-    <!-- Log root -->
-    <key>LogRoot</key>
-    <string>Logs</string>
-
     <!-- Run root -->
     <key>RunRoot</key>
-    <string>Run</string>
+    <string>Logs</string>
 
     <!-- Child aliases -->
     <key>Aliases</key>
@@ -111,7 +112,12 @@
        -->
     </dict>
 
-    <!-- User quota (in bytes) -->
+
+    <!--
+        Quotas and limits
+      -->
+
+    <!-- User quota (in bytes) [0 = no quota] -->
     <key>UserQuota</key>
     <integer>104857600</integer><!-- 100Mb -->
 
@@ -129,12 +135,6 @@
     <key>MaxInstancesForRRULE</key>
     <integer>400</integer>
 
-    <!-- Disable resource service. -->
-    <key>ResourceService</key>
-    <dict>
-      <key>Enabled</key>
-      <false/>
-    </dict>
 
     <!--
         Directory service
@@ -144,6 +144,7 @@
 
         A variety of directory services are available for use.
       -->
+
     <!-- XML File Directory Service -->
     <key>DirectoryService</key>
     <dict>
@@ -174,15 +175,21 @@
     </dict>
     -->
 
-    <!--
-        Augment service
+    <!-- Resource and Location Service -->
+    <key>ResourceService</key>
+    <dict>
+      <key>Enabled</key>
+      <false/>
+      <key>type</key>
+      <string>twistedcaldav.directory.xmlfile.XMLDirectoryService</string>
+      
+      <key>params</key>
+      <dict>
+        <key>xmlFile</key>
+        <string>./conf/auth/resources-test.xml</string>
+      </dict>
+    </dict>
 
-        Augments for the directory service records to add calendar specific attributes.
-
-        A variety of augment services are available for use.
-        When using a partitioned server, a service that can be accessed from each host will be needed.
-      -->
-
     <!-- XML File Augment Service -->
     <key>AugmentService</key>
     <dict>
@@ -197,7 +204,7 @@
         </array>
       </dict>
     </dict>
-    
+
     <!-- Sqlite Augment Service -->
     <!--
     <key>AugmentService</key>
@@ -208,7 +215,7 @@
       <key>params</key>
       <dict>
         <key>dbpath</key>
-        <string>/etc/carddavd/augments.sqlite</string>
+        <string>./conf/auth/augments.sqlite</string>
       </dict>
     </dict>
      -->
@@ -260,9 +267,10 @@
     </dict>
      -->
 
-	<key>ProxyLoadFromFile</key>
+    <key>ProxyLoadFromFile</key>
     <string>./conf/auth/proxies-test.xml</string>
 
+
     <!--
         Special principals
 
@@ -284,7 +292,7 @@
 
     <!-- Principals that can pose as other principals -->
     <key>SudoersFile</key>
-    <string>./conf/sudoers.plist</string>
+    <string>sudoers.plist</string>
 
     <!-- Create "proxy access" principals -->
     <key>EnableProxyPrincipals</key>
@@ -343,7 +351,7 @@
       <key>Kerberos</key>
       <dict>
         <key>Enabled</key>
-        <false/>
+        <true/>
         <key>ServicePrincipal</key>
         <string></string>
       </dict>
@@ -370,13 +378,15 @@
         Logging
       -->
 
+    <!-- Log root -->
+    <key>LogRoot</key>
+    <string>Logs</string>
+
     <!-- Apache-style access log -->
     <key>AccessLogFile</key>
     <string>access.log</string>
     <key>RotateAccessLog</key>
     <false/>
-    <key>MoreAccessLogData</key>
-    <true/>
 
     <!-- Server activity log -->
     <key>ErrorLogFile</key>
@@ -428,6 +438,7 @@
       <key>HTTP</key>
       <false/>
     </dict>
+
     <!-- Enable accounting for specific principals -->
     <key>AccountingPrincipals</key>
     <array>
@@ -486,7 +497,7 @@
       <string>localhost</string>
 
       <key>InternalNotificationPort</key>
-      <integer>62309</integer>
+      <integer>62311</integer>
 
       <key>Services</key>
       <dict>
@@ -587,7 +598,7 @@
         <array>
         </array>
         <key>Servers</key>
-        <string>./conf/servertoserver-test.xml</string>
+        <string>servertoserver-test.xml</string>
       </dict>
 
       <!-- iMIP protocol options -->
@@ -637,16 +648,16 @@
         </array>
       </dict>
 
-	  <!-- General options for scheduling -->
-	  <key>Options</key>
-	  <dict>
+      <!-- General options for scheduling -->
+      <key>Options</key>
+      <dict>
         <key>AllowGroupAsOrganizer</key>
         <false/>
         <key>AllowLocationAsOrganizer</key>
         <false/>
         <key>AllowResourceAsOrganizer</key>
         <false/>
-       </dict>
+      </dict>
 
     </dict>
 
@@ -658,7 +669,7 @@
     <key>FreeBusyURL</key>
     <dict>
       <key>Enabled</key>
-      <true/>
+      <false/>
       <key>TimePeriod</key>
       <integer>14</integer>
       <key>AnonymousAccess</key>
@@ -672,16 +683,36 @@
 
     <!-- Calendar Drop Box -->
     <key>EnableDropBox</key>
-    <true/>
+    <false/>
 
     <!-- Private Events -->
     <key>EnablePrivateEvents</key>
-    <true/>
+    <false/>
 
     <!-- Timezone Service -->
     <key>EnableTimezoneService</key>
-    <true/>
+    <false/>
 
+    <!-- Shared Calendars & Address Books -->
+    <key>Sharing</key>
+    <dict>
+      <key>Enabled</key>
+      <true/>
+      <key>AllowExternalUsers</key>
+      <false/>
+      <key>Calendars</key>
+      <dict>
+    	<key>Enabled</key>
+    	<false/>
+    	<key>AllowScheduling</key>
+    	<false/>
+      </dict>
+      <key>AddressBooks</key>
+      <dict>
+    	<key>Enabled</key>
+    	<true/>
+      </dict>
+    </dict>
 
     <!--
         Miscellaneous items
@@ -703,8 +734,7 @@
     <key>HTTPRetryAfter</key>
     <integer>180</integer>
 
-    <!-- A unix socket used for communication between the child and master processes.
-         An empty value tells the server to use a tcp socket instead. -->
+    <!-- For child-master IPC. [empty = use tcp] -->
     <key>ControlSocket</key>
     <string>carddavd.sock</string>
 
@@ -755,8 +785,12 @@
     <key>DirectoryAddressBook</key>
     <dict>
 
+      <key>Enabled</key>
+      <true/>
+
       <key>type</key>
       <string>twistedcaldav.directory.xmlfile.XMLDirectoryService</string>
+
       <key>params</key>
       <dict>
         <key>xmlFile</key>
@@ -767,18 +801,6 @@
     <!--  allow unauthenticated users to access the directory address book -->
     <key>AnonymousDirectoryAddressBookAccess</key>
     <false/>
-    
-    <!--  enable search address book in user's home -->
-    <key>EnableSearchAddressBook</key>
-    <true/>
-    
-    <!--  enable searchall address book in user's home -->
-    <key>EnableSearchAllAddressBook</key>
-    <true/>
-    
-    <!--  enable find share report -->
-    <key>EnableFindSharedReport</key>
-    <true/>
 
-    </dict>
+  </dict>
 </plist>

Modified: CalendarServer/trunk/twistedcaldav/directory/addressbook.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/addressbook.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/twistedcaldav/directory/addressbook.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2006-2010 Apple Inc. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -27,23 +27,24 @@
     "DirectoryAddressBookHomeResource",
 ]
 
-from twisted.internet.defer import succeed
+from twext.python.log import Logger
 from twext.web2 import responsecode
 from twext.web2.dav import davxml
-from twext.web2.http import HTTPError
+from twext.web2.dav.resource import TwistedACLInheritable
 from twext.web2.dav.util import joinURL
-from twext.web2.dav.resource import TwistedACLInheritable, TwistedQuotaRootProperty
+from twext.web2.http import HTTPError
 
+from twisted.internet.defer import succeed
+
 from twistedcaldav.config import config
-from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource
-from twistedcaldav.resource import CalDAVResource, SearchAddressBookResource, SearchAllAddressBookResource, CalDAVComplianceMixIn
 from twistedcaldav.directory.idirectory import IDirectoryService
 from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn
+from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource
+from twistedcaldav.notifications import NotificationCollectionResource
+from twistedcaldav.resource import CalDAVResource, CalDAVComplianceMixIn
 
-from twistedcaldav.directory.directory import DirectoryService
+log = Logger()
 
-from twistedcaldav.report_addressbook_findshared import getReadWriteSharedAddressBookGroups, getReadOnlySharedAddressBookGroups, getWritersGroupForSharedAddressBookGroup
-
 # Use __underbars__ convention to avoid conflicts with directory resource types.
 uidsResourceName = "__uids__"
 
@@ -57,11 +58,7 @@
     def defaultAccessControlList(self):
         return config.ProvisioningResourceACL
 
-    def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
-        # Permissions here are fixed, and are not subject to inherritance rules, etc.
-        return succeed(self.defaultAccessControlList())
 
-
 class DirectoryAddressBookHomeProvisioningResource (DirectoryAddressBookProvisioningResource):
     """
     Resource which provisions address book home collections as needed.    
@@ -178,6 +175,9 @@
             # Not a listable collection
             raise HTTPError(responsecode.FORBIDDEN)
 
+    def createSimilarFile(self, path):
+        raise HTTPError(responsecode.NOT_FOUND)
+
     ##
     # DAV
     ##
@@ -185,9 +185,6 @@
     def isCollection(self):
         return True
 
-    def http_COPY(self, request):
-        return responsecode.FORBIDDEN
-
     ##
     # ACL
     ##
@@ -263,40 +260,50 @@
 
         self.record = record
         self.parent = parent
-        
-        # Cache children which must be of a specific type
+
         childlist = ()
-        if config.EnableSearchAddressBook and config.DirectoryAddressBook:
-            childlist += (("search" , SearchAddressBookResource ), )
-        if config.EnableSearchAllAddressBook:
-            childlist += (("searchall" , SearchAllAddressBookResource ),)
-        
+        if config.Sharing.Enabled and config.Sharing.Calendars.Enabled:
+            childlist += (
+                ("notification", NotificationCollectionResource),
+            )
         for name, cls in childlist:
             child = self.provisionChild(name)
-            assert isinstance(child, cls), "Child %r not a %s: %r" % (name, cls.__name__, child)
+            assert isinstance(child, cls), "Child %r is not a %s: %r" % (name, cls.__name__, child)
             self.putChild(name, child)
 
-
     def provisionDefaultAddressBooks(self):
-        self.provision()
 
-        childName = "addressbook"
-        child = self.provisionChild(childName)
-        assert isinstance(child, CalDAVResource), "Child %r is not a %s: %r" % (childName, CalDAVResource.__name__, child) #@UndefinedVariable
+        # Disable notifications during provisioning
+        if hasattr(self, "clientNotifier"):
+            self.clientNotifier.disableNotify()
 
-        return child.createAddressBookCollection()
+        try:
+            self.provision()
+    
+            childName = "addressbook"
+            child = self.provisionChild(childName)
+            assert isinstance(child, CalDAVResource), "Child %r is not a %s: %r" % (childName, CalDAVResource.__name__, child) #@UndefinedVariable
 
+            d = child.createAddressBookCollection()
+        except:
+            # We want to make sure to re-enable notifications, so do so
+            # if there is an immediate exception above, or via errback, below
+            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()")
 
     def url(self):
-        return joinURL(self.parent.url(), self.record.guid)
-        ##
-        ## While the underlying primary location is GUID-based, we want
-        ## the canonical user-facing location to be recordType &
-        ## shortName-based, because that's friendlier.
-        ##
-        #return joinURL(self.parent.parent.getChild(self.record.recordType).url(), self.record.shortName)
+        return joinURL(self.parent.url(), self.record.uid, "/")
 
     def canonicalURL(self, request):
         return succeed(self.url())
@@ -307,6 +314,9 @@
     def isCollection(self):
         return True
 
+    def http_COPY(self, request):
+        return responsecode.FORBIDDEN
+
     ##
     # ACL
     ##
@@ -314,108 +324,25 @@
     def owner(self, request):
         return succeed(davxml.HRef(self.principalForRecord().principalURL()))
 
-    def _determineGroupAccessMode(self):
-        """
-        Determines whether this record (assumed to be a group) is provisioned in the list of read-write address books or read-only address books
-        Returns:
-            "ReadWrite", "ReadOnly" or None
-        """
-        
-        members = getReadWriteSharedAddressBookGroups(self.record.service)      # list of members of the "ab_readwrite" group
-        if self.record in members:                                              # membership must be explicit in the "ab_readwrite" group - no membership expansion is done
-            return "ReadWrite"
-
-        members = getReadOnlySharedAddressBookGroups(self.record.service)       # list of members of the "ab_readonly" group
-        if self.record in members:                                              # membership must be explicit in the "ab_readonly" group - no membership expansion is done
-            return "ReadOnly"
-            
-        return None
-    
-    def _getWritersURL(self):
-        """
-           Looks for a "-writers" group, and if found, extract the principal URL to it
-        """
-
-        writerRecord = getWritersGroupForSharedAddressBookGroup(self.record)
-        if writerRecord == None:
-            return None
-        
-        
-        # TO-DO: Need better way to build the principal URL to the "-writers" group
-        #principalURL = "/principals/__uids__/%s/" % writerRecord.guid
-        
-        principalURL = None
-        for principalCollection in self.principalCollections():     # based on principalForCalendarUserAddress in resource.CalDAVResource
-            groups = principalCollection.getChild(DirectoryService.recordType_groups)       # get only the "groups" collection within the parent collection
-            if groups:
-                p = groups.principalForRecord(writerRecord)
-                if p is not None:
-                    principalURL = p.principalURL()
-                    break
-        
-        return principalURL
-        
     def ownerPrincipal(self, request):
         return succeed(self.principalForRecord())
 
+    def resourceOwnerPrincipal(self, request):
+        return succeed(self.principalForRecord())
+
     def defaultAccessControlList(self):
         myPrincipal = self.principalForRecord()
-        
-        if self.record.recordType != DirectoryService.recordType_groups:
-            # Original ACE logic
-            aces = (
-                # DAV:read access for authenticated users.
-                davxml.ACE(
-                    davxml.Principal(davxml.Authenticated()),
-                    davxml.Grant(
-                        davxml.Privilege(davxml.Read()),
-                        davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
-                    ),
-                ),
-                # Inheritable DAV:all access for the resource's associated principal.
-                davxml.ACE(
-                    davxml.Principal(davxml.HRef(myPrincipal.principalURL())),
-                    davxml.Grant(davxml.Privilege(davxml.All())),
-                    davxml.Protected(),
-                    TwistedACLInheritable(),
-                ),
-            )
-        else:
-            # Determine access for this group (members are read-write or members are read-only)
-            accMode = self._determineGroupAccessMode()
-                        
-            aces = ()
-                 
-            if accMode == "ReadWrite":
-                aces += (davxml.ACE(
-                    davxml.Principal(davxml.HRef(myPrincipal.principalURL())),
-                    davxml.Grant(davxml.Privilege(davxml.All())),
-                    davxml.Protected(),
-                    TwistedACLInheritable(),
-                ), )            
-            elif accMode == "ReadOnly":
-                aces += (davxml.ACE(
-                    davxml.Principal(davxml.HRef(myPrincipal.principalURL())),
-                    davxml.Grant(
-                        davxml.Privilege(davxml.Read()),
-                        davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
-                    ),
-                    davxml.Protected(),
-                    TwistedACLInheritable(),
-                ), )          
-                
-                # Look for a "-writers" group and add those members with read-write access
-                writerURL = self._getWritersURL()
-                if writerURL:
-                    aces += (davxml.ACE(
-                        davxml.Principal(davxml.HRef(writerURL)),
-                        davxml.Grant(davxml.Privilege(davxml.All())),
-                        davxml.Protected(),
-                        TwistedACLInheritable(),
-                    ), )            
-            else:
-                pass
 
+        aces = (
+            # Inheritable DAV:all access for the resource's associated principal.
+            davxml.ACE(
+                davxml.Principal(davxml.HRef(myPrincipal.principalURL())),
+                davxml.Grant(davxml.Privilege(davxml.All())),
+                davxml.Protected(),
+                TwistedACLInheritable(),
+            ),
+        )
+
         # Give read access to config.ReadPrincipals
         aces += config.ReadACEs
 
@@ -442,14 +369,11 @@
         """
         @return: a C{True} if this resource has quota root, C{False} otherwise.
         """
-        return self.hasDeadProperty(TwistedQuotaRootProperty) or config.UserQuota > 0
+        return config.UserQuota != 0
     
     def quotaRoot(self, request):
         """
         @return: a C{int} containing the maximum allowed bytes if this collection
             is quota-controlled, or C{None} if not quota controlled.
         """
-        if self.hasDeadProperty(TwistedQuotaRootProperty):
-            return int(str(self.readDeadProperty(TwistedQuotaRootProperty)))
-        else:
-            return config.UserQuota if config.UserQuota > 0 else None
+        return config.UserQuota if config.UserQuota != 0 else None

Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/principal.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -48,8 +48,6 @@
 from twext.web2.dav.util import joinURL
 from twext.web2.dav.noneprops import NonePropertyStore
 
-from twistedcaldav import carddavxml
-
 from twext.python.log import Logger
 
 from twistedcaldav.authkerb import NegotiateCredentials
@@ -915,7 +913,7 @@
             return None
 
     def addressBookHomeURLs(self):
-        home = self._addressBookHome()
+        home = self.addressBookHome()
         if home is None:
             return ()
         else:
@@ -945,7 +943,7 @@
         else:
             return None
 
-    def _addressBookHome(self):
+    def addressBookHome(self):
         # FIXME: self.record.service.addressBookHomesCollection smells like a hack
         # See AddressBookHomeProvisioningFile.__init__()
         service = self.record.service
@@ -954,13 +952,6 @@
         else:
             return None
 
-    def supportedReports(self):            # Method added for AddressBook find-shared report support
-        result = super(DirectoryCalendarPrincipalResource, self).supportedReports()
-        if config.EnableCardDAV and config.EnableFindSharedReport:
-            result.append(davxml.Report(carddavxml.AddressBookFindShared(),)) 
-        return result
-
-
     ##
     # Static
     ##

Modified: CalendarServer/trunk/twistedcaldav/directorybackedaddressbook.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directorybackedaddressbook.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/twistedcaldav/directorybackedaddressbook.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -56,13 +56,13 @@
         
     def provisionDirectory(self):
         if self.directory is None:
-            directoryClass = namedClass(config.DirectoryAddressBook["type"])
+            directoryClass = namedClass(config.DirectoryAddressBook.type)
         
             log.info("Configuring: %s:%r"
-                 % (config.DirectoryAddressBook["type"], config.DirectoryAddressBook["params"]))
+                 % (config.DirectoryAddressBook.type, config.DirectoryAddressBook.params))
         
             #add self as "directoryBackedAddressBook" parameter
-            params = config.DirectoryAddressBook["params"].copy()
+            params = config.DirectoryAddressBook.params.copy()
             params["directoryBackedAddressBook"] = self
 
             self.directory = directoryClass(params)

Deleted: CalendarServer/trunk/twistedcaldav/report_addressbook_findshared.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/report_addressbook_findshared.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/twistedcaldav/report_addressbook_findshared.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -1,485 +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.
-##
-
-"""
-AddressBook Server "Find Shared" Address Books report
-Based on addressbook-query report in report_addressbook_query.py
-"""
-
-__all__ = [
-    "http___addressbookserver_org_ns__addressbook_findshared",
-    "getReadWriteSharedAddressBookGroups",
-    "getReadOnlySharedAddressBookGroups",
-    "getWritersGroupForSharedAddressBookGroup",
-]
-
-from twext.python.plistlib import readPlist
-#import traceback
-
-import opendirectory
-import dsattributes
-
-from twisted.internet.defer import inlineCallbacks, returnValue
-
-from twext.python.log import Logger
-from twext.python.filepath import CachingFilePath as FilePath
-from twext.web2 import responsecode
-from twext.web2.dav import davxml
-from twext.web2.dav.http import MultiStatusResponse
-from twext.web2.dav.util import joinURL
-from twext.web2.http import HTTPError, StatusResponse
-
-from twistedcaldav import customxml
-from twistedcaldav.carddavxml import addressbookserver_namespace, carddav_namespace
-from twistedcaldav.config import config
-from twistedcaldav.stdconfig import DEFAULT_CONFIG_FILE as defaultConfigFile
-from twistedcaldav.customxml import calendarserver_namespace
-from twistedcaldav.directory.appleopendirectory import OpenDirectoryRecord
-from twistedcaldav.resource import isAddressBookCollectionResource
-
-from twistedcaldav.directory.directory import DirectoryService
-
-log = Logger()
-
-gLogLocal = 0       # Poor mans logging control for this file only
-
-
-class AddressBookAccessMode (davxml.WebDAVTextElement):
-    """
-    Access Mode XML element for Address Book "Find Shared" report
-    """
-    name = "current-addressbook-access-mode"
-    namespace = addressbookserver_namespace
-    protected = True
-    
-
-class AddressBookGroupAddressBookInfo (davxml.WebDAVElement):
-    name = "addressbook-info"
-    namespace = addressbookserver_namespace
-    protected = True
-
-    allowed_children = { (davxml.dav_namespace, "href"): (0, None),
-                         (calendarserver_namespace, "getctag"): (0, None),
-                         (davxml.dav_namespace, "displayname"): (0, None),
-                       }
-    
-class AddressBookGroupAddressBooks (davxml.WebDAVElement):
-    """
-    The list (hrefs) of address books contained within a group principal
-    """
-    # Code based on CalendarHomeSet()
-    
-    name = "current-addressbooks-set"
-    namespace = addressbookserver_namespace
-    protected = True
-    
-    allowed_children = { (AddressBookGroupAddressBookInfo.namespace, AddressBookGroupAddressBookInfo.name): (0, None),
-                       }
-    
-    _sharedABFileInfo = None
-    _sharedABDict = None
-    
-
-def getABSharedFileAsDictionary():
-
-    try:
-    # get file path
-        sharedABFilePath = "SharedAddressBooks.plist"
-        if config._configFile:
-            configFilePath = config._configFile
-        else:
-            configFilePath = defaultConfigFile
-        sharedABFilePath = configFilePath[:configFilePath.rfind("/")+1] + sharedABFilePath
-    
-        sharedABFile = FilePath(sharedABFilePath)
-        sharedABFile.restat()
-        fileInfo  = (sharedABFile.getmtime(), sharedABFile.getsize())
-        if fileInfo != AddressBookGroupAddressBooks._sharedABFileInfo:
-            AddressBookGroupAddressBooks._sharedABFileInfo = fileInfo
-            AddressBookGroupAddressBooks._sharedABDict = readPlist(sharedABFilePath)
-            
-            
-    except Exception, e:
-        log.msg("getABSharedFileAsDictionary(): could not read or decode %s: %r" % (sharedABFilePath, e,))
-        AddressBookGroupAddressBooks._sharedABDict = None
-    
-    return AddressBookGroupAddressBooks._sharedABDict
-        
-
-def reloadRecordFromDS(record):
-    # Cause the record to be re-read from DS by forcing a cache reload on it
-    if record == None:
-        return
-        
-    log.debug("(Shared Address Book) Reloading record from DS: %s (%s)" % (record.shortNames[0], record.guid));
-    guid = record.guid
-    service = record.service
-    service.reloadCache(record.recordType, lookup=["guid", guid], logIt=False)
-    record = service.recordWithUID(guid)               # reacquire record after cache reload
-    return record
-
-
-def reloadGroupMembersFromDS(groupRecord):
-    # This routine is mainly for purposes of adding the "-writers" group to an ACL.  If the -writers group contains any nested groups, then
-    # make sure that the memberships of those nested groups is up to date
-    # Assumes that groupRecord itself is already current
-    if groupRecord == None:
-        return
-    
-    log.debug("(Shared Address Book) Reloading members from DS for record: %s (%s)" % (groupRecord.shortNames[0], groupRecord.guid));
-    
-    visitedGroups = []
-    for m in groupRecord.members():
-        if m.recordType == DirectoryService.recordType_groups:      # only care about refreshing group members - I hope
-            if m.guid in visitedGroups:
-                continue
-            visitedGroups.append(m.guid)
-            m = reloadRecordFromDS(m)                   # refresh the member group
-            reloadGroupMembersFromDS(m)                 # and any of it's children
-
-    log.debug("(Shared Address Book) Completed reload of members from DS for record: %s (%s)" % (groupRecord.shortNames[0], groupRecord.guid));
-    
-    
-def getSharedAddressBookSpecialGroup(service, wantGroupName):
-    # Used to find the "ab_readwrite", "ab_readonly" or "xx-writers" groups in the /Local/ node
- 
-    # Read these directory from DS because DSLocal recrods are not in principals
- 
-    # We now intentionally force the read to go to DS to make sure we don't have stale data (esp. between processes)
-    log.debug("(Shared Address Book) Querying DS for provisioning group: %s" % wantGroupName);
-
-    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 ()
-
-    record = None
-    attrs = [
-        dsattributes.kDS1AttrGeneratedUID,
-        dsattributes.kDSNAttrRecordName,
-        dsattributes.kDS1AttrDistinguishedName,
-        dsattributes.kDSNAttrGroupMembers,
-        dsattributes.kDSNAttrNestedGroups,
-        dsattributes.kDSNAttrMetaNodeLocation,
-    ]
-
-    try:
-        localNodeDirectory = opendirectory.odInit("/Local/Default")
-        
-        log.debug(
-            "(Shared Address Book) opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
-                "/Local/Default",
-                dsattributes.kDSNAttrRecordName,
-                wantGroupName,
-                dsattributes.eDSExact,
-                False,
-                dsattributes.kDSStdRecordTypeGroups,
-                attrs,
-            )
-        )
-        results = opendirectory.queryRecordsWithAttribute_list(
-            localNodeDirectory,
-            dsattributes.kDSNAttrRecordName,
-            wantGroupName,
-            dsattributes.eDSExact,
-            False,
-            dsattributes.kDSStdRecordTypeGroups,
-            attrs,
-        )
-    
-        log.debug("(Shared Address Book) results= %r" % (results,))
-
-        if len(results) > 0:
-
-            recordShortName, value = results[0] #@UnusedVariable
-
-            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)
-
-            record = OpenDirectoryRecord(
-                service               = service,
-                recordType            = DirectoryService.recordType_groups,
-                guid                  = value.get(dsattributes.kDS1AttrGeneratedUID),
-                nodeName              = value.get(dsattributes.kDSNAttrMetaNodeLocation),
-                shortNames            = _uniqueTupleFromAttribute(value.get(dsattributes.kDSNAttrRecordName)),
-                authIDs               = (),
-                fullName              = value.get(dsattributes.kDS1AttrDistinguishedName),
-                firstName             = None,
-                lastName              = None,
-                emailAddresses        = (),
-                calendarUserAddresses = (),
-                autoSchedule          = False,
-                enabledForCalendaring = False,
-                memberGUIDs           = memberGUIDs,
-                proxyGUIDs            = (),
-                readOnlyProxyGUIDs    = (),
-            )
-            
-    except opendirectory.ODError, e:
-        #traceback.print_exc()
-        log.err("Open Directory (node=%s) error: %s" % ("/Local/Default", str(e,)))
-    except Exception, e:
-        #traceback.print_exc()
-        log.err("Exception while qerying DS for provisioning group: %s: r" % (wantGroupName, e,))
-    
-    log.debug("(Shared Address Book) record= %r" % (record,))
-    return record
-    
-                
-    
-def getSharedAddressBookGroups(service, masterGroupName):
-    record = getSharedAddressBookSpecialGroup(service, masterGroupName)
-    if record == None:
-        return []  # don't return None since callers expect to be able to iterate the results
-    
-    return record.members()
-    
-
-def getReadWriteSharedAddressBookGroups(service):
-    return getSharedAddressBookGroups(service, "com.apple.addressbookserver.sharedABs.readwrite")
-
-
-def getReadOnlySharedAddressBookGroups(service):
-    return getSharedAddressBookGroups(service, "com.apple.addressbookserver.sharedABs.readonly")
-
-
-def getWritersGroupForSharedAddressBookGroup(groupRecord):
-    # Find the "-writers" record object for a given group record
-    # Do not just call:
-    #       writerRecord = self.record.service.recordWithShortName(DirectoryService.recordType_groups, writerRecName)
-    # because that will cause the DS cache to fault looking for the record name if it doesn't exist
-    writerRecName = "com.apple.addressbookserver.sharedABs.writers." + groupRecord.shortNames[0]
-    
-    writersRec = getSharedAddressBookSpecialGroup(groupRecord.service, writerRecName)
-    reloadGroupMembersFromDS(writersRec)        # Make sure all group memberships are up to date
-    
-    return writersRec
-
-    
-def groupRecordContainsMember(aGroup, wantMember):
-    # Does recursive search of aGroup's members, looking for wantMember
-    # Caller is responsible for insuring that "aGroup" is current before calling this routine; we'll make sure to re-read any nested groups
-    
-    if aGroup == None or wantMember == None:
-        return False
-        
-    visitedGroups = []
-    for m in aGroup.members():
-        isGroup = m.recordType == DirectoryService.recordType_groups
-        if isGroup:
-            if m.guid in visitedGroups:
-                continue
-            visitedGroups.append(m.guid)
-        
-        if m.guid == wantMember.guid:
-            return True
-        
-        if isGroup:
-            # Reread the nested group information to make sure it's membership is current
-            m = reloadRecordFromDS(m)
-            if groupRecordContainsMember(m, wantMember):
-                return True
-        
-    return False
-
-    
-def findPrincipalForRecord(rec, principalCollections):
-    for pc in principalCollections:
-        recs = pc.getChild(rec.recordType)
-        if recs:
-            p = recs.principalForRecord(rec)
-            if p:
-                return p
-  
-    return None
-    
-    
-def userIsAddressBookGroupWriter(userRecord, groupRecord):
-    # Check to see if the user is a member of the "-writers" record (if one exists)
-            
-    # Now go after the actual -writer record and insure that one exists in the local node
-    writerRecord = getWritersGroupForSharedAddressBookGroup(groupRecord)
-    if not writerRecord:
-        return False
-        
-    # Check to see if the user is a member of the "-writers" record  
-    return groupRecordContainsMember(writerRecord, userRecord)      # RECURSIVE search!
-    
-
-def filterGroupsForMember(groupList, wantMember):
-    # Check to see which groups in "groupList" wantMember is a member of (recursively)
-    # Will only return the top level groups from groupList, not the actual group that the user is a member of
-    
-    list = []
-    for g in groupList:
-        # "g" could conceivably be a user record but then g.members() will return [] so it shouldn't be necessary to preflight
-        if groupRecordContainsMember(g, wantMember):
-            list.append(g)
-
-    return list
-
- at inlineCallbacks
-def http___addressbookserver_org_ns__addressbook_findshared(self, request, findshared):
-    """
-    Generate a findshared REPORT.
-    """
-        
-    # Verify root element
-    if findshared.qname() != (addressbookserver_namespace, "addressbook-findshared"):
-        raise ValueError("addressbook-findshared expected as root element, not %s." % (findshared.sname(),))
-
-    # Make sure target resource is of the right type
-    uriResource = yield request.locateResource(request.uri)
-    if uriResource == None:
-        log.err("addressbook-findshared unable to convert request URI to resource: %s" % request.uri)
-        raise HTTPError(StatusResponse(responsecode.NOT_FOUND, "Unable to convert request URI to resource: %s" % request.uri))
-    
-    if uriResource.record.recordType != DirectoryService.recordType_users:
-        log.err("addressbook-findshared request URI is not a user principal: %s" % request.uri)
-        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "Request URI is not a user principal: %s" % request.uri))
-
-    #
-    # Reacquire the user record from DS to make sure it's information is up-to-date
-    #
-    userRecord = uriResource.record
-    userRecord = reloadRecordFromDS(userRecord)
-    if userRecord == None:
-        raise HTTPError(StatusResponse(responsecode.NOT_FOUND, "Unable to reload user record from DS cache: %s" % request.uri))
-    
-    uriResource = None      # Invalidate since it contains a reference to a stale "record" instance
-    
-    #
-    # Run the report
-    #
-    responses = []
-    
-    
-    # 
-    # Get the master lists of Address Book-enabled groups  (No group expansion necessary - each group must contain leaf groups that are enabled)
-    #
-    readOnlyGroups = getReadOnlySharedAddressBookGroups(userRecord.service)        # wrap in tuple() if we're going to use more than once since this returns a generator
-    readOnlyGroups = filterGroupsForMember(readOnlyGroups, userRecord)             # keep only those groups that "user" is a member of (checking nested membership)
-    
-    readWriteGroups = getReadWriteSharedAddressBookGroups(userRecord.service)
-    readWriteGroups = filterGroupsForMember(readWriteGroups, userRecord)
-
-    
-    #
-    # Determine which of the groups have address books enabled and what the user's access is to them
-    #
-    processedGroups = []
-    for memberList in (readWriteGroups, readOnlyGroups):        # Make sure to process R/W group access before R/O access
-        isReadWriteGroup = memberList == readWriteGroups
-        for g in memberList:
-            if g.guid in processedGroups:                            # Just in case we have multiple references to the same group, process only once
-                continue
-            processedGroups.append(g.guid)
- 
-            # Reload the group from DS to make sure it's information is up-to-date
-            g = reloadRecordFromDS(g)
-            if g == None:                   # group disappeared on cache reload
-                continue
-            
-            mode = None
-            if isReadWriteGroup:
-                mode = "ReadWrite"
-            else:
-                mode = "ReadOnly"
-                if userIsAddressBookGroupWriter(userRecord, g):
-                    mode = "ReadWrite"
-    
-            if mode == None:
-                continue
-                    
-            groupPrincipalURL = None
-            groupPrincipal = findPrincipalForRecord(g, self.principalCollections()) 
-            if groupPrincipal:
-                groupPrincipalURL = groupPrincipal.principalURL()
-            
-            
-            abHome = yield groupPrincipal.readProperty((carddav_namespace, "addressbook-home-set"), request)
-            
-            groupDisplayName = yield groupPrincipal.readProperty((davxml.dav_namespace, "displayname"), request)
-            
-            groupUUID = customxml.ResourceID(g.guid)
-            
-            abMode = AddressBookAccessMode(mode)
-    
-            abInfos = []
-            for home in groupPrincipal.addressBookHomeURLs():
-                homeResource = yield request.locateResource(home)
-                for child in homeResource.listChildren():
-                    props = []
-                    childPath = joinURL(homeResource.url(), child)
-                    childResource = yield request.locateResource(childPath)
-                    if childResource and isAddressBookCollectionResource(childResource):
-                        childPath = childPath + "/"                     # Now that we know it's a directory, append the trailing slash
-                        props.append(davxml.HRef(childPath))
-                        
-                        cTag = None
-                        try:
-                            cTag = yield childResource.readProperty((calendarserver_namespace, "getctag"), request)
-                        except:
-                            cTag = None
-                        
-                        if cTag is not None:
-                            props.append(cTag)
-                        
-                        if str(child) == "addressbook":
-                            sharedABFileDictionary = getABSharedFileAsDictionary()
-                            if sharedABFileDictionary:
-                                sharedABDict = sharedABFileDictionary.get("SharedAddressBooks")
-                                if sharedABDict:
-                                    thisGroupsDict = sharedABDict.get(g.guid)
-                                    if thisGroupsDict:
-                                        displayNameString = thisGroupsDict.get("AddressBookName")
-                                        if displayNameString:                        
-                                            displayName = davxml.DisplayName.fromString(displayNameString)
-                                            props.append(displayName)
-
-                        
-                        thisInfo = AddressBookGroupAddressBookInfo(*props)
-                        abInfos.append(thisInfo)
-                            
-            groupAddressBooksProp = AddressBookGroupAddressBooks(*abInfos)
-            #groupAddressBooksProp = AddressBookGroupAddressBooks(*[davxml.HRef(url) for url in groupAddressBooks])                            
-            
-            xml_status      = davxml.Status.fromResponseCode(responsecode.OK)
-            xml_container   = davxml.PropertyContainer(groupDisplayName, groupUUID, abHome, abMode, groupAddressBooksProp)
-            xml_propstat    = davxml.PropertyStatus(xml_container, xml_status)
-            
-            propstats = []
-            propstats.append(xml_propstat)
-    
-            xml_resource = davxml.HRef.fromString(groupPrincipalURL)
-            xml_response = davxml.PropertyStatusResponse(xml_resource, *propstats)
-        
-            responses.append(xml_response)
-
-    returnValue(MultiStatusResponse(responses))

Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/twistedcaldav/resource.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -26,8 +26,6 @@
     "isCalendarCollectionResource",
     "isPseudoCalendarCollectionResource",
     "isAddressBookCollectionResource",
-    "SearchAddressBookResource",
-    "SearchAllAddressBookResource",
 ]
 
 import urllib
@@ -1278,64 +1276,6 @@
         return None
 
 
-
-
-
-class SearchAddressBookResource (CalDAVResource):
-    """
-    Search collection resource.
-    """
-    def __init__(self, parent):
-        """
-        @param parent: the parent resource of this one.
-        """
-        assert parent is not None
-
-        CalDAVResource.__init__(self, principalCollections=parent.principalCollections())
-
-        self.parent = parent
-
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.searchaddressbook)
-
-    def renderHTTP(self, request):
-        return RedirectResponse(request.unparseURL(path="/directory/"))
-
-
-class SearchAllAddressBookResource (CalDAVResource):
-    """
-    Search collection resource.
-    """
-    def __init__(self, parent):
-        """
-        @param parent: the parent resource of this one.
-        """
-        assert parent is not None
-
-        CalDAVResource.__init__(self, principalCollections=parent.principalCollections())
-
-        self.parent = parent
-
-    def resourceType(self, request):
-        return succeed(davxml.ResourceType.searchalladdressbook)
-
-    def renderHTTP(self, request):
-        
-        # if requested path ends with "searchall", redirect it for now, redirect to "addressbook"
-        #
-        # in future, should combine all accessible address books
-        
-        matchString = "/searchall"
-        if request.path[-1] == "/":
-            matchString += "/"
-            
-        if request.path.endswith( matchString ):
-            return RedirectResponse(request.unparseURL(path=request.path[:-len(matchString)] + "/addressbook/"))
-        else:
-            return CalDAVResource.renderHTTP(self, request)
-
-
-
 class AuthenticationWrapper(SuperAuthenticationWrapper):
 
     """ AuthenticationWrapper implementation which allows overriding

Modified: CalendarServer/trunk/twistedcaldav/static.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/static.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/twistedcaldav/static.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -80,7 +80,7 @@
 from twistedcaldav.ical import Property as iProperty
 from twistedcaldav.index import Index, IndexSchedule, SyncTokenValidException
 from twistedcaldav.resource import CalDAVResource, isCalendarCollectionResource, isPseudoCalendarCollectionResource
-from twistedcaldav.resource import isAddressBookCollectionResource, SearchAddressBookResource, SearchAllAddressBookResource
+from twistedcaldav.resource import isAddressBookCollectionResource
 from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource, IScheduleInboxResource
 from twistedcaldav.datafilters.privateevents import PrivateEventFilter
 from twistedcaldav.dropbox import DropBoxHomeResource, DropBoxCollectionResource
@@ -1374,25 +1374,6 @@
         DAVFile.__init__(self, path)
         DirectoryAddressBookHomeProvisioningResource.__init__(self, directory, url)
 
-        # create with permissions
-        try:
-            os.mkdir(path)
-            os.chmod(path, 0750)
-            if config.UserName and config.GroupName:
-                import pwd
-                import grp
-                uid = pwd.getpwnam(config.UserName)[2]
-                gid = grp.getgrnam(config.GroupName)[2]
-                os.chown(path, uid, gid)
- 
-            log.msg("Created %s" % (path,))
-            
-        except (OSError,), e:
-            # this is caused by multiprocessor race and is harmless
-            if e.errno != errno.EEXIST:
-                raise
-
-
     def provisionChild(self, name):
         if name == uidsResourceNameAddressBook:
             return AddressBookHomeUIDProvisioningFile(self.fp.child(name).path, self)
@@ -1499,6 +1480,8 @@
     def liveProperties(self):
         return super(AddressBookHomeFile, self).liveProperties() + (
             (customxml.calendarserver_namespace, "xmpp-uri"),
+            (customxml.calendarserver_namespace, "xmpp-heartbeat-uri"),
+            (customxml.calendarserver_namespace, "xmpp-server"),
         )
 
     def __init__(self, path, parent, record):
@@ -1511,27 +1494,23 @@
 
     def provisionChild(self, name):
  
-        SearchAddressBookFileClass = None
-        SearchAllAddressBookFileClass = None
-        if config.EnableSearchAddressBook and config.DirectoryAddressBook:
-            SearchAddressBookFileClass = SearchAddressBookFile
-        if config.EnableSearchAllAddressBook:
-            SearchAllAddressBookFileClass = SearchAllAddressBookFile
-        
+        if config.Sharing.Enabled:
+            NotificationCollectionFileClass = NotificationCollectionFile
+        else:
+            NotificationCollectionFileClass = None
+
         cls = {
-            "search"       : SearchAddressBookFileClass,
-            "searchall"    : SearchAllAddressBookFileClass,
+            "notification" : NotificationCollectionFileClass,
         }.get(name, None)
 
         if cls is not None:
             child = cls(self.fp.child(name).path, self)
             child.clientNotifier = self.clientNotifier
             return child
-
         return self.createSimilarFile(self.fp.child(name).path)
 
     def createSimilarFile(self, path):
-        if path == self.fp.path:
+        if self.comparePath(path):
             return self
         else:
             similar = CalDAVFile(path, principalCollections=self.principalCollections())
@@ -1552,50 +1531,53 @@
         else:
             qname = property.qname()
 
+        def doneWaiting(result, propVal):
+            return propVal
+
         if qname == (customxml.calendarserver_namespace, "xmpp-uri"):
             pubSubConfiguration = getPubSubConfiguration(config)
             if pubSubConfiguration['enabled']:
-                return succeed(customxml.PubSubXMPPURIProperty(
-                    getPubSubXMPPURI(self.url(), pubSubConfiguration)))
+                if getattr(self, "clientNotifier", None) is not None:
+                    url = self.url()
+                    nodeName = getPubSubPath(url, pubSubConfiguration)
+                    propVal = customxml.PubSubXMPPURIProperty(
+                        getPubSubXMPPURI(url, pubSubConfiguration))
+                    nodeCacher = getNodeCacher()
+                    d = nodeCacher.waitForNode(self.clientNotifier, nodeName)
+                    # In either case we're going to return the xmpp-uri value
+                    d.addCallback(doneWaiting, propVal)
+                    d.addErrback(doneWaiting, propVal)
+                    return d
             else:
                 return succeed(customxml.PubSubXMPPURIProperty())
 
-        return super(AddressBookHomeFile, self).readProperty(property, request)
+        elif qname == (customxml.calendarserver_namespace, "xmpp-heartbeat-uri"):
+            pubSubConfiguration = getPubSubConfiguration(config)
+            if pubSubConfiguration['enabled']:
+                return succeed(
+                    customxml.PubSubHeartbeatProperty(
+                        customxml.PubSubHeartbeatURIProperty(
+                            getPubSubHeartbeatURI(pubSubConfiguration)
+                        ),
+                        customxml.PubSubHeartbeatMinutesProperty(
+                            str(pubSubConfiguration['heartrate'])
+                        )
+                    )
+                )
+            else:
+                return succeed(customxml.PubSubHeartbeatURIProperty())
 
+        elif qname == (customxml.calendarserver_namespace, "xmpp-server"):
+            pubSubConfiguration = getPubSubConfiguration(config)
+            if pubSubConfiguration['enabled']:
+                return succeed(customxml.PubSubXMPPServerProperty(
+                    pubSubConfiguration['xmpp-server']))
+            else:
+                return succeed(customxml.PubSubXMPPServerProperty())
 
-class SearchAddressBookFile (SearchAddressBookResource, CalDAVFile):
-    """
-    Search collection resource.
-    """
-    def __init__(self, path, parent):
-        SearchAddressBookResource.__init__(self, parent)
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-        self.parent = parent
+        return super(AddressBookHomeFile, self).readProperty(property, request)
 
-    def createSimilarFile(self, path):
-        if path == self.fp.path:
-            return self
 
-        # FIXME:  path here is similar too .../addressbooks/__uids__/us/er/user01/search/move2_1.vcf
-        #        so we should really redirect to /directory/move2_1.vcf or perhaps we shouldn't be here in the first place
-        raise HTTPError(responsecode.NOT_FOUND)
-
-class SearchAllAddressBookFile (SearchAllAddressBookResource, CalDAVFile):
-    """
-    Search collection resource.
-    """
-    def __init__(self, path, parent):
-        SearchAllAddressBookResource.__init__(self, parent)
-        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
-        self.parent = parent
-   
-    def createSimilarFile(self, path):
-        if path == self.fp.path:
-            return self
-
-        # FIXME:  see note above
-        raise HTTPError(responsecode.NOT_FOUND)
-
 class DirectoryBackedAddressBookFile (DirectoryBackedAddressBookResource, CalDAVFile):
     """
     Directory-backed address book, supporting directory vcard search.
@@ -1750,11 +1732,3 @@
 twistedcaldav.method.put.CalDAVFile      = CalDAVFile
 
 
-#
-# Attach method to DirectoryCalendarPrincipalResource for "Find Shared Address Books" REPORT method
-#
-from twistedcaldav.directory.principal import DirectoryCalendarPrincipalResource
-from twistedcaldav import report_addressbook_findshared
-setattr(DirectoryCalendarPrincipalResource, "report_http___addressbookserver_org_ns__addressbook_findshared", report_addressbook_findshared.http___addressbookserver_org_ns__addressbook_findshared)
-
-

Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -152,19 +152,17 @@
     "EnableCalDAV"  : True,  # Enable CalDAV service
     "EnableCardDAV" : True,  # Enable CardDAV service
 
-    # XXX CardDAV
+    # CardDAV Features
     "DirectoryAddressBook": {
-        "type": "twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService",
-        "params": directoryAddressBookBackingServiceDefaultParams["twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService"],
+        "Enabled": True,
+        "type":    "twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService",
+        "params":  directoryAddressBookBackingServiceDefaultParams["twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService"],
     },
     "AnonymousDirectoryAddressBookAccess": False, # Anonymous users may access directory address book
 
-    "EnableSearchAddressBook": False,
-    "EnableSearchAllAddressBook":False,
     "MaxAddressBookQueryResults":1000,
     "MaxAddressBookMultigetHrefs":5000,
 
-    "EnableFindSharedReport":False,
     # /XXX CardDAV
 
     #
@@ -683,17 +681,17 @@
     #
     dsType = items.get("DirectoryAddressBook", {}).get("type", None)
     if dsType is None:
-        dsType = configDict["DirectoryAddressBook"]["type"]
+        dsType = configDict.DirectoryAddressBook.type
     else:
-        if dsType == configDict["DirectoryAddressBook"]["type"]:
-            oldParams = configDict["DirectoryAddressBook"]["params"]
+        if dsType == configDict.DirectoryAddressBook.type:
+            oldParams = configDict.DirectoryAddressBook.params
             newParams = items["DirectoryAddressBook"].get("params", {})
             _mergeData(oldParams, newParams)
         else:
             if dsType in directoryAddressBookBackingServiceDefaultParams:
-                configDict["DirectoryAddressBook"]["params"] = copy.deepcopy(directoryAddressBookBackingServiceDefaultParams[dsType])
+                configDict.DirectoryAddressBook.params = copy.deepcopy(directoryAddressBookBackingServiceDefaultParams[dsType])
             else:
-                configDict["DirectoryAddressBook"]["params"] = {}
+                configDict.DirectoryAddressBook.params = {}
 
     for param in items.get("DirectoryAddressBook", {}).get("params", {}):
         if param not in directoryAddressBookBackingServiceDefaultParams[dsType]:
@@ -701,9 +699,9 @@
 
     _mergeData(configDict, items)
 
-    for param in tuple(configDict["DirectoryAddressBook"]["params"]):
-        if param not in directoryAddressBookBackingServiceDefaultParams[configDict["DirectoryAddressBook"]["type"]]:
-            del configDict["DirectoryAddressBook"]["params"][param]
+    for param in tuple(configDict.DirectoryAddressBook.params):
+        if param not in directoryAddressBookBackingServiceDefaultParams[configDict.DirectoryAddressBook.type]:
+            del configDict.DirectoryAddressBook.params[param]
 
 def _postUpdateAugmentService(configDict):
     if configDict.AugmentService.type in DEFAULT_AUGMENT_PARAMS:

Modified: CalendarServer/trunk/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/util.py	2010-04-12 16:27:16 UTC (rev 5468)
+++ CalendarServer/trunk/twistedcaldav/test/util.py	2010-04-12 20:22:32 UTC (rev 5469)
@@ -74,6 +74,8 @@
         ClientFactory.allowTestCache = True
         memcacher.Memcacher.allowTestCache = True
 
+        config.DirectoryAddressBook.Enabled = False
+
     def createHierarchy(self, structure, root=None):
         if root is None:
             root = self.mktemp()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100412/4310f30f/attachment-0001.html>


More information about the calendarserver-changes mailing list