[CalendarServer-changes] [9865] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Sep 26 17:06:04 PDT 2012


Revision: 9865
          http://trac.calendarserver.org//changeset/9865
Author:   gaya at apple.com
Date:     2012-09-26 17:06:04 -0700 (Wed, 26 Sep 2012)
Log Message:
-----------
merge in inviteclean branch

Modified Paths:
--------------
    CalDAVTester/trunk/Resource/CalDAV/sharing/calendars/read-only/2.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/calendars/read-write/2.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/invites/double/2.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/invites/double/4.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/invites/new/2.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/invites/updatenew/2.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/notification-sync/13.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/notification-sync/6.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/peruser-properties/read-write/2.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/replies/accept/2.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/replies/accept/5.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/replies/decline/3.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/setup/2.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/setup/5.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/unshare/shareruninvite/2.xml
    CalDAVTester/trunk/Resource/CalDAV/sharing/unshare/shareruninvite/7.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/2.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/2.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/2.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/5.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/3.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/setup/2.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/setup/5.xml
    CalDAVTester/trunk/scripts/tests/CalDAV/sharing-calendars.xml
    CalDAVTester/trunk/scripts/tests/CardDAV/sharing-addressbooks.xml
    CalDAVTester/trunk/scripts/tests/CardDAV/sharing-replies.xml
    CalendarServer/trunk/calendarserver/tools/purge.py
    CalendarServer/trunk/calendarserver/tools/test/test_purge.py
    CalendarServer/trunk/support/submit
    CalendarServer/trunk/twistedcaldav/directory/util.py
    CalendarServer/trunk/twistedcaldav/method/put_common.py
    CalendarServer/trunk/twistedcaldav/resource.py
    CalendarServer/trunk/twistedcaldav/schedule.py
    CalendarServer/trunk/twistedcaldav/sharing.py
    CalendarServer/trunk/twistedcaldav/storebridge.py
    CalendarServer/trunk/twistedcaldav/test/test_link.py
    CalendarServer/trunk/twistedcaldav/test/test_resource.py
    CalendarServer/trunk/twistedcaldav/test/test_schedule.py
    CalendarServer/trunk/twistedcaldav/test/test_sharing.py
    CalendarServer/trunk/twistedcaldav/test/test_wrapping.py
    CalendarServer/trunk/txdav/base/propertystore/base.py
    CalendarServer/trunk/txdav/base/propertystore/sql.py
    CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py
    CalendarServer/trunk/txdav/caldav/datastore/file.py
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/caldav/datastore/test/common.py
    CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
    CalendarServer/trunk/txdav/caldav/datastore/util.py
    CalendarServer/trunk/txdav/caldav/icalendarstore.py
    CalendarServer/trunk/txdav/carddav/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/file.py
    CalendarServer/trunk/txdav/common/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/sql_legacy.py
    CalendarServer/trunk/txdav/common/icommondatastore.py

Added Paths:
-----------
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/1.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/10.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/2.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/3.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/4.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/5.vcf
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/6.vcf
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/7.vcf
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/8.vcf
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/9.xml

Removed Paths:
-------------
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/1.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/10.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/2.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/3.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/4.xml
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/5.vcf
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/6.vcf
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/7.vcf
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/8.vcf
    CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/9.xml
    CalendarServer/trunk/twistedcaldav/sharedcollection.py

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/calendars/read-only/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/calendars/read-only/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/calendars/read-only/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-accepted/>
     <access>
       <read/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/calendars/read-write/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/calendars/read-write/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/calendars/read-write/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -3,7 +3,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/invites/double/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/invites/double/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/invites/double/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/invites/double/4.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/invites/double/4.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/invites/double/4.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/invites/new/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/invites/new/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/invites/new/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/invites/updatenew/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/invites/updatenew/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/invites/updatenew/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/notification-sync/13.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/notification-sync/13.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/notification-sync/13.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-declined/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/notification-sync/6.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/notification-sync/6.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/notification-sync/6.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/peruser-properties/read-write/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/peruser-properties/read-write/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/peruser-properties/read-write/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/replies/accept/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/replies/accept/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/replies/accept/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/replies/accept/5.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/replies/accept/5.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/replies/accept/5.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -6,7 +6,7 @@
         <invite xmlns='http://calendarserver.org/ns/'>
           <user>
             <uid></uid>
-            <href xmlns='DAV:'>$cuaddr2:</href>
+            <href xmlns='DAV:'>$cuaddrurn2:</href>
             <common-name>User 02</common-name>
             <access>
               <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/replies/decline/3.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/replies/decline/3.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/replies/decline/3.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -6,7 +6,7 @@
         <invite xmlns='http://calendarserver.org/ns/'>
           <user>
             <uid></uid>
-            <href xmlns='DAV:'>$cuaddr2:</href>
+            <href xmlns='DAV:'>$cuaddrurn2:</href>
             <common-name>User 02</common-name>
             <access>
               <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/setup/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/setup/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/setup/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/setup/5.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/setup/5.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/setup/5.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -6,7 +6,7 @@
         <invite xmlns='http://calendarserver.org/ns/'>
           <user>
             <uid></uid>
-            <href xmlns='DAV:'>$cuaddr2:</href>
+            <href xmlns='DAV:'>$cuaddrurn2:</href>
             <common-name>User 02</common-name>
             <access>
               <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/unshare/shareruninvite/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/unshare/shareruninvite/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/unshare/shareruninvite/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr3:</href>
+    <href xmlns='DAV:'>$cuaddrurn3:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CalDAV/sharing/unshare/shareruninvite/7.xml
===================================================================
--- CalDAVTester/trunk/Resource/CalDAV/sharing/unshare/shareruninvite/7.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CalDAV/sharing/unshare/shareruninvite/7.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='calendar'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr3:</href>
+    <href xmlns='DAV:'>$cuaddrurn3:</href>
     <invite-deleted/>
     <access>
       <read-write/>

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/1.xml
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/1.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/1.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
-    <CS:set>
-        <D:href>$cuaddr2:</D:href>
-        <CS:summary>My Main Shared Address Book</CS:summary>
-        <CS:read-write/>
-    </CS:set>
-</CS:share>

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/1.xml (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/1.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/1.xml	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/1.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
+    <CS:set>
+        <D:href>$cuaddr2:</D:href>
+        <CS:summary>My Main Shared Address Book</CS:summary>
+        <CS:read-write/>
+    </CS:set>
+</CS:share>

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/10.xml
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/10.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/10.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,19 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?><notification xmlns='http://calendarserver.org/ns/'>
-  <dtstamp></dtstamp>
-  <invite-notification shared-type='addressbook'>
-    <uid></uid>
-    <href xmlns='DAV:'>$cuaddrurn2:</href>
-    <invite-deleted/>
-    <access>
-      <read-write/>
-    </access>
-    <hosturl>
-      <href xmlns='DAV:'>$addressbookpath1:</href>
-    </hosturl>
-    <organizer>
-      <href xmlns='DAV:'>$principaluri1:</href>
-      <common-name>User 01</common-name>
-    </organizer>
-    <summary>The Shared Address Book</summary>
-  </invite-notification>
-</notification>

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/10.xml (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/10.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/10.xml	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/10.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?><notification xmlns='http://calendarserver.org/ns/'>
+  <dtstamp></dtstamp>
+  <invite-notification shared-type='addressbook'>
+    <uid></uid>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
+    <invite-deleted/>
+    <access>
+      <read-write/>
+    </access>
+    <hosturl>
+      <href xmlns='DAV:'>$addressbookpath1:</href>
+    </hosturl>
+    <organizer>
+      <href xmlns='DAV:'>$principaluri1:</href>
+      <common-name>User 01</common-name>
+    </organizer>
+    <summary>The Shared Address Book</summary>
+  </invite-notification>
+</notification>

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/2.xml
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,19 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?><notification xmlns='http://calendarserver.org/ns/'>
-  <dtstamp></dtstamp>
-  <invite-notification shared-type='addressbook'>
-    <uid></uid>
-    <href xmlns='DAV:'>$cuaddrurn2:</href>
-    <invite-noresponse/>
-    <access>
-      <read-write/>
-    </access>
-    <hosturl>
-      <href xmlns='DAV:'>$addressbookpath1:</href>
-    </hosturl>
-    <organizer>
-      <href xmlns='DAV:'>$principaluri1:</href>
-      <common-name>User 01</common-name>
-    </organizer>
-    <summary>My Main Shared Address Book</summary>
-  </invite-notification>
-</notification>

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/2.xml (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/2.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/2.xml	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?><notification xmlns='http://calendarserver.org/ns/'>
+  <dtstamp></dtstamp>
+  <invite-notification shared-type='addressbook'>
+    <uid></uid>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
+    <invite-noresponse/>
+    <access>
+      <read-write/>
+    </access>
+    <hosturl>
+      <href xmlns='DAV:'>$addressbookpath1:</href>
+    </hosturl>
+    <organizer>
+      <href xmlns='DAV:'>$principaluri1:</href>
+      <common-name>User 01</common-name>
+    </organizer>
+    <summary>My Main Shared Address Book</summary>
+  </invite-notification>
+</notification>

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/3.xml
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/3.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/3.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,13 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<invite-reply xmlns='http://calendarserver.org/ns/'>
-  <href xmlns='DAV:'>mailto:$email2:</href>
-  <invite-accepted/>
-  <hosturl>
-    <href xmlns='DAV:'>$addressbookpath1:</href>
-  </hosturl>
-  <in-reply-to>$inviteuid:</in-reply-to>
-  <summary>The Shared Address Book</summary>
-  <common-name>$username2:</common-name>
-  <first-name>$firstname2:</first-name>
-  <last-name>$lastname2:</last-name>
-</invite-reply>

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/3.xml (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/3.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/3.xml	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/3.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<invite-reply xmlns='http://calendarserver.org/ns/'>
+  <href xmlns='DAV:'>mailto:$email2:</href>
+  <invite-accepted/>
+  <hosturl>
+    <href xmlns='DAV:'>$addressbookpath1:</href>
+  </hosturl>
+  <in-reply-to>$inviteuid:</in-reply-to>
+  <summary>The Shared Address Book</summary>
+  <common-name>$username2:</common-name>
+  <first-name>$firstname2:</first-name>
+  <last-name>$lastname2:</last-name>
+</invite-reply>

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/4.xml
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/4.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/4.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<D:propfind xmlns:D="DAV:">
-<D:prop>
-<D:resourcetype/>
-<D:owner/>
-<D:current-user-privilege-set/>
-</D:prop>
-</D:propfind>

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/4.xml (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/4.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/4.xml	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/4.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propfind xmlns:D="DAV:">
+<D:prop>
+<D:resourcetype/>
+<D:owner/>
+<D:current-user-privilege-set/>
+</D:prop>
+</D:propfind>

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/5.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/5.vcf	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/5.vcf	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,11 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Thompson;Default;;;
-FN:Default Thompson
-EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
-TEL;type=WORK;type=pref:1-555-555-5555
-TEL;type=CELL:1-444-444-4444
-item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
-item1.X-ABADR:us
-UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-1
-END:VCARD

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/5.vcf (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/5.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/5.vcf	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/5.vcf	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-1
+END:VCARD

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/6.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/6.vcf	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/6.vcf	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,11 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Thompson;Default;;;
-FN:Default Thompson
-EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
-TEL;type=WORK;type=pref:1-555-555-5555
-TEL;type=CELL:1-444-444-4444
-item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
-item1.X-ABADR:us
-UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-1
-END:VCARD

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/6.vcf (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/6.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/6.vcf	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/6.vcf	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-1
+END:VCARD

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/7.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/7.vcf	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/7.vcf	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,11 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Thompson;Default;;;
-FN:Default Thompson
-EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
-TEL;type=WORK;type=pref:1-555-555-5555
-TEL;type=CELL:1-444-444-4444
-item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
-item1.X-ABADR:us
-UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-2
-END:VCARD

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/7.vcf (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/7.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/7.vcf	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/7.vcf	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-2
+END:VCARD

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/8.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/8.vcf	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/8.vcf	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,11 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Thompson;Default;;;
-FN:Default Thompson
-EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
-TEL;type=WORK;type=pref:1-555-555-5555
-TEL;type=CELL:1-444-444-4444
-item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
-item1.X-ABADR:us
-UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-2
-END:VCARD

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/8.vcf (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/8.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/8.vcf	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/8.vcf	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-2
+END:VCARD

Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/9.xml
===================================================================
--- CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/9.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/9.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
-    <CS:remove>
-        <D:href>$cuaddr2:</D:href>
-    </CS:remove>
-</CS:share>

Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/9.xml (from rev 9864, CalDAVTester/branches/users/gaya/invitecleanTester/Resource/CardDAV/sharing/addressbooks/main/9.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/9.xml	                        (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/9.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
+    <CS:remove>
+        <D:href>$cuaddr2:</D:href>
+    </CS:remove>
+</CS:share>

Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='addressbook'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-accepted/>
     <access>
       <read/>

Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='addressbook'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='addressbook'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/5.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/5.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/5.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -6,7 +6,7 @@
         <invite xmlns='http://calendarserver.org/ns/'>
           <user>
             <uid></uid>
-            <href xmlns='DAV:'>$cuaddr2:</href>
+            <href xmlns='DAV:'>$cuaddrurn2:</href>
             <common-name>User 02</common-name>
             <access>
               <read-write/>

Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/3.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/3.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/3.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -6,7 +6,7 @@
         <invite xmlns='http://calendarserver.org/ns/'>
           <user>
             <uid></uid>
-            <href xmlns='DAV:'>$cuaddr2:</href>
+            <href xmlns='DAV:'>$cuaddrurn2:</href>
             <common-name>User 02</common-name>
             <access>
               <read-write/>

Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/setup/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/setup/2.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/setup/2.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -2,7 +2,7 @@
   <dtstamp></dtstamp>
   <invite-notification shared-type='addressbook'>
     <uid></uid>
-    <href xmlns='DAV:'>$cuaddr2:</href>
+    <href xmlns='DAV:'>$cuaddrurn2:</href>
     <invite-noresponse/>
     <access>
       <read-write/>

Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/setup/5.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/setup/5.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/setup/5.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -6,7 +6,7 @@
         <invite xmlns='http://calendarserver.org/ns/'>
           <user>
             <uid></uid>
-            <href xmlns='DAV:'>$cuaddr2:</href>
+            <href xmlns='DAV:'>$cuaddrurn2:</href>
             <common-name>User 02</common-name>
             <access>
               <read-write/>

Modified: CalDAVTester/trunk/scripts/tests/CalDAV/sharing-calendars.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CalDAV/sharing-calendars.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/scripts/tests/CalDAV/sharing-calendars.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -174,7 +174,7 @@
 						<value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}organizer/{DAV:}href[=$principaluri1:]</value>
 						<value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}organizer/{http://calendarserver.org/ns/}common-name[=$username1:]</value>
 						<value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}user</value>
-						<value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}user/{DAV:}href[=$cuaddr2:]</value>
+						<value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}user/{DAV:}href[=$cuaddrurn2:]</value>
 						<value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}user/{http://calendarserver.org/ns/}access/{http://calendarserver.org/ns/}read-write</value>
 						<value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}user/{http://calendarserver.org/ns/}invite-accepted</value>
 					</arg>

Modified: CalDAVTester/trunk/scripts/tests/CardDAV/sharing-addressbooks.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/sharing-addressbooks.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/sharing-addressbooks.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -89,6 +89,13 @@
 					<variable>$inviteuid:</variable>
 				</grabelement>
 			</request>
+			<request user="$userid2:" pswd="$pswd2:">
+				<method>DELETE</method>
+				<ruri>$notificationpath2:/$inviteuid:</ruri>
+				<verify>
+					<callback>statusCode</callback>
+				</verify>
+			</request>
 		</test>
 		<test name='3'>
 			<description>Sharee replies ACCEPTED</description>
@@ -341,6 +348,13 @@
 					<variable>$inviteuid:</variable>
 				</grabelement>
 			</request>
+			<request user="$userid2:" pswd="$pswd2:">
+				<method>DELETE</method>
+				<ruri>$notificationpath2:/$inviteuid:</ruri>
+				<verify>
+					<callback>statusCode</callback>
+				</verify>
+			</request>
 		</test>
 		<test name='3'>
 			<description>Sharee replies ACCEPTED</description>
@@ -457,7 +471,286 @@
 			</request>
 		</test>
 	</test-suite>
-	
+	<test-suite name='Share main address book' ignore='no'>
+		<test name='1' ignore='no'>
+			<description>POST invitation</description>
+			<request print-response='no'>
+				<method>POST</method>
+				<ruri>$addressbookpath1:/</ruri>
+				<data>
+					<content-type>text/xml; charset=utf-8</content-type>
+					<filepath>Resource/CardDAV/sharing/addressbooks/main/1.xml</filepath>
+				</data>
+				<verify>
+					<callback>statusCode</callback>
+				</verify>
+			</request>
+		</test>
+		<test name='2' ignore='no'>
+			<description>Check Sharee notification collection</description>
+			<request user="$userid2:" pswd="$pswd2:" print-request='no' print-response='no'>
+				<method>WAITCOUNT 1</method>
+				<ruri>$notificationpath2:/</ruri>
+			</request>
+			<request user="$userid2:" pswd="$pswd2:" print-request='no' print-response='no'>
+				<method>GETNEW</method>
+				<ruri>$notificationpath2:/</ruri>
+				<verify>
+					<callback>xmlDataMatch</callback>
+					<arg>
+						<name>filepath</name>
+						<value>Resource/CardDAV/sharing/addressbooks/main/2.xml</value>
+					</arg>
+					<arg>
+						<name>filter</name>
+						<value>{http://calendarserver.org/ns/}dtstamp</value>
+						<value>{http://calendarserver.org/ns/}uid</value>
+					</arg>
+				</verify>
+				<grabelement>
+					<name>{http://calendarserver.org/ns/}invite-notification/{http://calendarserver.org/ns/}uid</name>
+					<variable>$inviteuid:</variable>
+				</grabelement>
+			</request>
+		</test>
+		<test name='3' ignore='no'>
+			<description>Sharee replies ACCEPTED</description>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+				<method>POST</method>
+				<ruri>$addressbookhome2:/</ruri>
+				<data substitutions='yes'>
+					<content-type>application/xml; charset=utf-8</content-type>
+					<filepath>Resource/CardDAV/sharing/addressbooks/main/3.xml</filepath>
+				</data>
+				<verify>
+					<callback>statusCode</callback>
+				</verify>
+				<grabelement>
+					<name>{DAV:}href</name>
+					<variable>$sharedaddressbook:</variable>
+				</grabelement>
+			</request>
+		</test>
+		<test name='4' ignore='no'>
+			<description>Shared address book exists</description>
+			<request user="$userid2:" pswd="$pswd2:" print-request='no' print-response='no'>
+				<method>PROPFIND</method>
+				<ruri>$sharedaddressbook:/</ruri>
+				<header>
+					<name>Depth</name>
+					<value>0</value>
+				</header>
+				<data>
+					<content-type>text/xml; charset=utf-8</content-type>
+					<filepath>Resource/CardDAV/sharing/addressbooks/main/4.xml</filepath>
+				</data>
+				<verify>
+					<callback>xmlElementMatch</callback>
+					<arg>
+						<name>exists</name>
+						<value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+						<value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value>
+						<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+						<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+						<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+						<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+					</arg>
+					<arg>
+						<name>notexists</name>
+						<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+						<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+					</arg>
+				</verify>
+			</request>
+		</test>
+		<test name='5' ignore='no'>
+			<description>Sharee creates vcard</description>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+				<method>PUT</method>
+				<ruri>$sharedaddressbook:/1.vcf</ruri>
+				<data>
+					<content-type>text/vcard; charset=utf-8</content-type>
+					<filepath>Resource/CardDAV/sharing/addressbooks/main/5.vcf</filepath>
+				</data>
+				<verify>
+					<callback>statusCode</callback>
+				</verify>
+			</request>
+		</test>
+		<test name='6' ignore='no'>
+			<description>Sharer sees vcard</description>
+			<request print-response='no'>
+				<method>GET</method>
+				<ruri>$addressbookpath1:/1.vcf</ruri>
+				<verify>
+					<callback>addressDataMatch</callback>
+					<arg>
+						<name>filepath</name>
+						<value>Resource/CardDAV/sharing/addressbooks/main/5.vcf</value>
+					</arg>
+				</verify>
+			</request>
+		</test>
+		<test name='7' ignore='no'>
+			<description>Sharer changes vcard</description>
+			<request print-response='no'>
+				<method>PUT</method>
+				<ruri>$addressbookpath1:/1.vcf</ruri>
+				<data>
+					<content-type>text/vcard; charset=utf-8</content-type>
+					<filepath>Resource/CardDAV/sharing/addressbooks/main/6.vcf</filepath>
+				</data>
+				<verify>
+					<callback>statusCode</callback>
+				</verify>
+			</request>
+		</test>
+		<test name='8' ignore='no'>
+			<description>Sharee sees changed vcard</description>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+				<method>GET</method>
+				<ruri>$sharedaddressbook:/1.vcf</ruri>
+				<verify>
+					<callback>addressDataMatch</callback>
+					<arg>
+						<name>filepath</name>
+						<value>Resource/CardDAV/sharing/addressbooks/main/6.vcf</value>
+					</arg>
+				</verify>
+			</request>
+		</test>
+		<test name='9' ignore='no'>
+			<description>Sharer creates vcard</description>
+			<request print-response='no'>
+				<method>PUT</method>
+				<ruri>$addressbookpath1:/2.vcf</ruri>
+				<data>
+					<content-type>text/vcard; charset=utf-8</content-type>
+					<filepath>Resource/CardDAV/sharing/addressbooks/main/7.vcf</filepath>
+				</data>
+				<verify>
+					<callback>statusCode</callback>
+				</verify>
+			</request>
+		</test>
+		<test name='10' ignore='no'>
+			<description>Sharee sees new vcard</description>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+				<method>GET</method>
+				<ruri>$sharedaddressbook:/2.vcf</ruri>
+				<verify>
+					<callback>addressDataMatch</callback>
+					<arg>
+						<name>filepath</name>
+						<value>Resource/CardDAV/sharing/addressbooks/main/7.vcf</value>
+					</arg>
+				</verify>
+			</request>
+		</test>
+		<test name='11' ignore='no'>
+			<description>Sharee changes vcard</description>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+				<method>PUT</method>
+				<ruri>$sharedaddressbook:/2.vcf</ruri>
+				<data>
+					<content-type>text/vcard; charset=utf-8</content-type>
+					<filepath>Resource/CardDAV/sharing/addressbooks/main/8.vcf</filepath>
+				</data>
+				<verify>
+					<callback>statusCode</callback>
+				</verify>
+			</request>
+		</test>
+		<test name='12' ignore='no'>
+			<description>Sharer sees changed event</description>
+			<request print-response='no'>
+				<method>GET</method>
+				<ruri>$addressbookpath1:/2.vcf</ruri>
+				<verify>
+					<callback>addressDataMatch</callback>
+					<arg>
+						<name>filepath</name>
+						<value>Resource/CardDAV/sharing/addressbooks/main/8.vcf</value>
+					</arg>
+				</verify>
+			</request>
+		</test>
+		<test name='13' ignore='no'>
+			<description>Unshare main address book</description>
+			<request print-request='no' print-response='no'>
+				<method>POST</method>
+				<ruri>$addressbookpath1:/</ruri>
+				<data>
+					<content-type>text/xml; charset=utf-8</content-type>
+					<filepath>Resource/CardDAV/sharing/addressbooks/main/9.xml</filepath>
+				</data>
+				<verify>
+					<callback>statusCode</callback>
+					<arg>
+						<name>status</name>
+						<value>200</value>
+					</arg>
+				</verify>
+			</request>
+		</test>
+		<test name='14' ignore='no'>
+			<description>Check Sharee notification collection and delete invite-deleted</description>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+				<method>WAITCOUNT 1</method>
+				<ruri>$notificationpath2:/</ruri>
+			</request>
+			<request user="$userid2:" pswd="$pswd2:" print-request='no' print-response='no'>
+				<method>GETNEW</method>
+				<ruri>$notificationpath2:/</ruri>
+				<verify>
+					<callback>xmlDataMatch</callback>
+					<arg>
+						<name>filepath</name>
+						<value>Resource/CardDAV/sharing/addressbooks/main/10.xml</value>
+					</arg>
+					<arg>
+						<name>filter</name>
+						<value>{http://calendarserver.org/ns/}dtstamp</value>
+						<value>{http://calendarserver.org/ns/}uid</value>
+					</arg>
+				</verify>
+			</request>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+				<method>DELETE</method>
+				<ruri>$</ruri>
+			</request>
+		</test>
+		<test name='15' ignore='no'>
+			<description>No more shared addressbook</description>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+				<method>PROPFIND</method>
+				<ruri>$shareeaddressbook:/</ruri>
+				<header>
+					<name>Depth</name>
+					<value>0</value>
+				</header>
+				<data>
+					<content-type>text/xml; charset=utf-8</content-type>
+					<filepath>Resource/Common/PROPFIND/resourcetype.xml</filepath>
+				</data>
+				<verify>
+					<callback>statusCode</callback>
+					<arg>
+						<name>status</name>
+						<value>404</value>
+					</arg>
+				</verify>
+			</request>
+		</test>
+		<test name='16' ignore='no'>
+			<description>Clean up main addressbook</description>
+			<request>
+				<method>DELETEALL</method>
+				<ruri>$addressbookpath1:/</ruri>
+			</request>
+		</test>
+	</test-suite>
+
 	<end>
 		<request user="$useradmin:" pswd="$pswdadmin:">
 			<method>DELETEALL</method>

Modified: CalDAVTester/trunk/scripts/tests/CardDAV/sharing-replies.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/sharing-replies.xml	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/sharing-replies.xml	2012-09-27 00:06:04 UTC (rev 9865)
@@ -165,7 +165,7 @@
 			</request>
 		</test>
 		<test name='6' ignore='no'>
-			<description>Check sharee addressbook displyname/shared-url</description>
+			<description>Check sharee addressbook displayname/shared-url</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>PROPFIND</method>
 				<ruri>$shareeaddressbook:/</ruri>

Modified: CalendarServer/trunk/calendarserver/tools/purge.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/purge.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/calendarserver/tools/purge.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -666,19 +666,7 @@
     # If in "completely" mode, unshare collections, remove notifications
     if calHomeProvisioned and completely:
 
-        # Process shared-to-me calendars
-        names = list((yield storeCalHome.listSharedChildren()))
-        for name in names:
-            if verbose:
-                if dryrun:
-                    print "Would unshare: %s" % (name,)
-                else:
-                    print "Unsharing: %s" % (name,)
-            if not dryrun:
-                child = (yield storeCalHome.sharedChildWithName(name))
-                (yield child.unshare())
-
-        # Process shared calendars
+        # Process shared and shared-to-me calendars
         children = list((yield storeCalHome.children()))
         for child in children:
             if verbose:

Modified: CalendarServer/trunk/calendarserver/tools/test/test_purge.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_purge.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/calendarserver/tools/test/test_purge.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -847,10 +847,10 @@
 
         txn = self._sqlCalendarStore.newTransaction()
         home = (yield txn.calendarHomeWithUID(self.uid))
-        calendar2 = (yield home.sharedChildWithName(self.sharedName))
+        calendar2 = (yield home.childWithName(self.sharedName))
         self.assertNotEquals(calendar2, None)
         home2 = (yield txn.calendarHomeWithUID(self.uid2))
-        calendar1 = (yield home2.sharedChildWithName(self.sharedName2))
+        calendar1 = (yield home2.childWithName(self.sharedName2))
         self.assertNotEquals(calendar1, None)
         (yield txn.commit())
 
@@ -890,7 +890,7 @@
         self.assertEquals(home, None)
         # Verify calendar1 was unshared to uid2
         home2 = (yield txn.calendarHomeWithUID(self.uid2))
-        self.assertEquals((yield home2.sharedChildWithName(self.sharedName)), None)
+        self.assertEquals((yield home2.childWithName(self.sharedName)), None)
         (yield txn.commit())
 
         count, ignored = (yield purgeUID(self.storeUnderTest(), self.uid, self.directory,

Modified: CalendarServer/trunk/support/submit
===================================================================
--- CalendarServer/trunk/support/submit	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/support/submit	2012-09-27 00:06:04 UTC (rev 9865)
@@ -38,6 +38,7 @@
 
         submission_enabled=true;
 ignore_uncommitted_changes=false;
+    build_no_verify_source=false;
 
 usage ()
 {
@@ -46,19 +47,20 @@
   if [ "${1-}" != "-" ]; then echo "$@"; echo; fi;
 
   echo "Usage: ${program} release [release ...]";
-  echo "       ${program} -b[ip]";
+  echo "       ${program} release -b[ipn]";
   echo "";
   echo "Options:";
   echo "	-b Run buildit";
   echo "	-i Install resulting build on this system";
   echo "	-p Create a package with the resulting build";
   echo "	-f Ignore uncommitted changes";
+  echo "	-n skip buildit source verification";
 
   if [ "${1-}" == "-" ]; then return 0; fi;
   exit 64;
 }
 
-while getopts 'hbipf' option; do
+while getopts 'hbipfn' option; do
   case "$option" in
     '?') usage; ;;
     'h') usage -; exit 0; ;;
@@ -66,6 +68,7 @@
     'i')                    install=true; ;;
     'p')                    package=true; ;;
     'f') ignore_uncommitted_changes=true; ;;
+    'n') 	 build_no_verify_source=true; ;;
   esac;
 done;
 shift $((${OPTIND} - 1));
@@ -73,6 +76,7 @@
 if ! "${build}"; then
   if "${install}"; then usage "-i flag requires -b"; fi;
   if "${package}"; then usage "-p flag requires -b"; fi;
+  if "${build_no_verify_source}"; then usage "-n flag requires -b"; fi;
 
   if ! "${submission_enabled}"; then
     echo "Submissions from this branch are not enabled.";
@@ -178,10 +182,16 @@
   for release in "${releases}"; do
       release_flags="${release_flags} -release ${release}";
   done;
+  
+  if "${build_no_verify_source}"; then
+    verify_flags=" -noverifysource";
+  else
+    verify_flags="";
+  fi;  
 
   sudo buildit "${wc}" \
     $(file /System/Library/Frameworks/Python.framework/Versions/Current/Python | sed -n -e 's|^.*(for architecture \([^)][^)]*\).*$|-arch \1|p' | sed 's|ppc7400|ppc|') \
-    ${merge_flags}${release_flags};
+    ${merge_flags}${release_flags}${verify_flags};
 
   if "${package}"; then
     package_file="${project_version}.tgz";
@@ -199,4 +209,4 @@
   submitproject "${wc}" ${releases};
 fi;
 
-rm -rf "${tmp}";
+sudo rm -rf "${tmp}";

Modified: CalendarServer/trunk/twistedcaldav/directory/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/util.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/directory/util.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -64,6 +64,8 @@
         return value
 
 
+TRANSACTION_KEY = '_newStoreTransaction'
+
 def transactionFromRequest(request, newStore):
     """
     Return the associated transaction from the given HTTP request, creating a
@@ -85,7 +87,6 @@
     @rtype: L{ITransaction} (and possibly L{ICalendarTransaction} and
         L{IAddressBookTransaction} as well.
     """
-    TRANSACTION_KEY = '_newStoreTransaction'
     transaction = getattr(request, TRANSACTION_KEY, None)
     if transaction is None:
         transaction = newStore.newTransaction(repr(request))

Modified: CalendarServer/trunk/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/put_common.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/method/put_common.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -751,9 +751,9 @@
         Make sure sharees only use dropbox paths of the sharer.
         """
         
-        # Only relevant if calendar is virtual share
+        # Only relevant if calendar is sharee collection
         changed = False
-        if self.destinationparent.isVirtualShare():
+        if self.destinationparent.isShareeCollection():
             
             # Get all X-APPLE-DROPBOX's and ATTACH's that are http URIs
             xdropboxes = self.calendar.getAllPropertiesInAnyComponent(
@@ -827,7 +827,7 @@
             return changed
         
         # Never add default alarms to calendar data in shared calendars
-        if self.destinationparent.isVirtualShare():
+        if self.destinationparent.isShareeCollection():
             return changed
 
         # Add default alarm for VEVENT and VTODO only
@@ -942,8 +942,8 @@
             if do_implicit_action and self.allowImplicitSchedule:
 
                 # Cannot do implicit in sharee's shared calendar
-                isvirt = self.destinationparent.isVirtualShare()
-                if isvirt:
+                isShareeCollection = self.destinationparent.isShareeCollection()
+                if isShareeCollection:
                     raise HTTPError(ErrorResponse(
                         responsecode.FORBIDDEN,
                         (calendarserver_namespace, "sharee-privilege-needed",),

Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/resource.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -70,7 +70,7 @@
 from twistedcaldav.datafilters.privateevents import PrivateEventFilter
 from twistedcaldav.directory.internal import InternalDirectoryRecord
 from twistedcaldav.extensions import DAVResource, DAVPrincipalResource, \
-    PropertyNotFoundError, DAVResourceWithChildrenMixin
+    DAVResourceWithChildrenMixin
 from twistedcaldav.ical import Component
 
 from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
@@ -525,29 +525,9 @@
         """
         Need to special case schedule-calendar-transp for backwards compatability.
         """
-
-        if type(property) is tuple:
-            qname = property
-        else:
-            qname = property.qname()
-
-        isvirt = self.isVirtualShare()
-        if isvirt:
-            if self.isShadowableProperty(qname):
-                ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
-                p = self.deadProperties().contains(qname, uid=ownerPrincipal.principalUID())
-                if p:
-                    returnValue(p)
-
-            elif (not self.isGlobalProperty(qname)):
-                result = (yield self._hasSharedProperty(qname, request))
-                returnValue(result)
-
         res = (yield self._hasGlobalProperty(property, request))
         returnValue(res)
 
-
-    @inlineCallbacks
     def _hasSharedProperty(self, qname, request):
 
         # Always have default alarms on shared calendars
@@ -557,13 +537,11 @@
             caldavxml.DefaultAlarmVToDoDateTime.qname(),
             caldavxml.DefaultAlarmVToDoDate.qname(),
         ) and self.isCalendarCollection():
-            returnValue(True)
+            return True
 
-        ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
-        p = self.deadProperties().contains(qname, uid=ownerPrincipal.principalUID())
-        returnValue(p)
+        p = self.deadProperties().contains(qname)
+        return p
 
-
     def _hasGlobalProperty(self, property, request):
         """
         Need to special case schedule-calendar-transp for backwards compatability.
@@ -589,8 +567,6 @@
         else:
             qname = property.qname()
 
-        isvirt = self.isVirtualShare()
-
         if self.isCalendarCollection() or self.isAddressBookCollection():
 
             # Push notification DAV property "pushkey"
@@ -602,7 +578,7 @@
                 if hasattr(self, "_newStoreObject"):
                     dataObject = getattr(self, "_newStoreObject")
                 if dataObject:
-                    label = "collection" if isvirt else "default"
+                    label = "collection" if self.isShareeCollection() else "default"
                     nodeName = (yield dataObject.nodeName(label=label))
                     if nodeName:
                         propVal = customxml.PubSubXMPPPushKeyProperty(nodeName)
@@ -610,32 +586,16 @@
 
                 returnValue(customxml.PubSubXMPPPushKeyProperty())
 
-        if isvirt:
-            if self.isShadowableProperty(qname):
-                ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
-                try:
-                    p = self.deadProperties().get(qname, uid=ownerPrincipal.principalUID())
-                    returnValue(p)
-                except PropertyNotFoundError:
-                    pass
-
-            elif (not self.isGlobalProperty(qname)):
-                result = (yield self._readSharedProperty(qname, request))
-                returnValue(result)
-
         res = (yield self._readGlobalProperty(qname, property, request))
         returnValue(res)
 
 
-    @inlineCallbacks
     def _readSharedProperty(self, qname, request):
 
         # Default behavior - read per-user dead property
-        ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
-        p = self.deadProperties().get(qname, uid=ownerPrincipal.principalUID())
-        returnValue(p)
+        p = self.deadProperties().get(qname)
+        return p
 
-
     @inlineCallbacks
     def _readGlobalProperty(self, qname, property, request):
 
@@ -747,10 +707,10 @@
                 returnValue(customxml.AllowedSharingModes(customxml.CanBeShared()))
 
         elif qname == customxml.SharedURL.qname():
-            isvirt = self.isVirtualShare()
+            isShareeCollection = self.isShareeCollection()
 
-            if isvirt:
-                returnValue(customxml.SharedURL(element.HRef.fromString(self._share.hosturl)))
+            if isShareeCollection:
+                returnValue(customxml.SharedURL(element.HRef.fromString(self._share.url())))
             else:
                 returnValue(None)
 
@@ -764,14 +724,6 @@
             "%r is not a WebDAVElement instance" % (property,)
         )
 
-        # Per-user Dav props currently only apply to a sharee's copy of a calendar
-        isvirt = self.isVirtualShare()
-        if isvirt and (self.isShadowableProperty(property.qname()) or (not self.isGlobalProperty(property.qname()))):
-            yield self._preProcessWriteProperty(property, request, isShare=True)
-            ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
-            p = self.deadProperties().set(property, uid=ownerPrincipal.principalUID())
-            returnValue(p)
-
         res = (yield self._writeGlobalProperty(property, request))
         returnValue(res)
 
@@ -876,8 +828,8 @@
     def accessControlList(self, request, *args, **kwargs):
 
         acls = None
-        isvirt = self.isVirtualShare()
-        if isvirt:
+        isShareeCollection = self.isShareeCollection()
+        if isShareeCollection:
             acls = (yield self.shareeAccessControlList(request, *args, **kwargs))
 
         if acls is None:
@@ -933,9 +885,9 @@
         Return the DAV:owner property value (MUST be a DAV:href or None).
         """
 
-        isVirt = self.isVirtualShare()
-        if isVirt:
-            parent = (yield self.locateParent(request, self._share.hosturl))
+        isShareeCollection = self.isShareeCollection()
+        if isShareeCollection:
+            parent = (yield self.locateParent(request, self._share.url()))
         else:
             parent = (yield self.locateParent(request, request.urlForResource(self)))
         if parent and isinstance(parent, CalDAVResource):
@@ -950,9 +902,9 @@
         """
         Return the DAV:owner property value (MUST be a DAV:href or None).
         """
-        isVirt = self.isVirtualShare()
-        if isVirt:
-            parent = (yield self.locateParent(request, self._share.hosturl))
+        isShareeCollection = self.isShareeCollection()
+        if isShareeCollection:
+            parent = (yield self.locateParent(request, self._share.url()))
         else:
             parent = (yield self.locateParent(request, request.urlForResource(self)))
         if parent and isinstance(parent, CalDAVResource):
@@ -968,14 +920,9 @@
         This is the owner of the resource based on the URI used to access it. For a shared
         collection it will be the sharee, otherwise it will be the regular the ownerPrincipal.
         """
-
-        isVirt = self.isVirtualShare()
-        if isVirt:
-            returnValue(self._shareePrincipal)
-        else:
-            parent = (yield self.locateParent(
-                request, request.urlForResource(self)
-            ))
+        parent = (yield self.locateParent(
+            request, request.urlForResource(self)
+        ))
         if parent and isinstance(parent, CalDAVResource):
             result = (yield parent.resourceOwnerPrincipal(request))
             returnValue(result)
@@ -1064,8 +1011,7 @@
         """
         See L{ICalDAVResource.isSpecialCollection}.
         """
-        if not self.isCollection():
-            return False
+        if not self.isCollection(): return False
 
         try:
             resourcetype = self.resourceType()
@@ -1390,17 +1336,17 @@
         """
 
         sharedParent = None
-        isvirt = self.isVirtualShare()
-        if isvirt:
-            # A virtual share's quota root is the resource owner's root
-            sharedParent = (yield request.locateResource(parentForURL(self._share.hosturl)))
+        isShareeCollection = self.isShareeCollection()
+        if isShareeCollection:
+            # A sharee collection's quota root is the resource owner's root
+            sharedParent = (yield request.locateResource(parentForURL(self._share.url())))
         else:
             parent = (yield self.locateParent(request, request.urlForResource(self)))
             if isCalendarCollectionResource(parent) or isAddressBookCollectionResource(parent):
-                isvirt = parent.isVirtualShare()
-                if isvirt:
-                    # A virtual share's quota root is the resource owner's root
-                    sharedParent = (yield request.locateResource(parentForURL(parent._share.hosturl)))
+                isShareeCollection = parent.isShareeCollection()
+                if isShareeCollection:
+                    # A sharee collection's quota root is the resource owner's root
+                    sharedParent = (yield request.locateResource(parentForURL(parent._share.url())))
 
         if sharedParent:
             result = (yield sharedParent.quotaRootResource(request))
@@ -2183,16 +2129,6 @@
 
         return props
 
-
-    def sharesDB(self):
-        """
-        Retrieve the new-style shares DB wrapper.
-        """
-        if not hasattr(self, "_sharesDB"):
-            self._sharesDB = self._newStoreHome.retrieveOldShares()
-        return self._sharesDB
-
-
     def url(self):
         return joinURL(self.parent.url(), self.name, "/")
 
@@ -2304,14 +2240,11 @@
             self.putChild(name, child)
             returnValue(child)
 
-        # Try normal child type
+        # get regular or shared child
         child = (yield self.makeRegularChild(name))
 
-        # Try shares next if child does not exist
-        if not child.exists() and self.canShare():
-            sharedchild = yield self.provisionShare(name)
-            if sharedchild:
-                returnValue(sharedchild)
+        # add _share attribute if child is shared
+        yield self.provisionShare(child)
 
         returnValue(child)
 
@@ -2344,7 +2277,6 @@
         children = set(self._provisionedChildren.keys())
         children.update(self._provisionedLinks.keys())
         children.update((yield self._newStoreHome.listChildren()))
-        children.update((yield self._newStoreHome.listSharedChildren()))
         returnValue(children)
 
 
@@ -2679,6 +2611,9 @@
     @inlineCallbacks
     def makeRegularChild(self, name):
         newCalendar = yield self._newStoreHome.calendarWithName(name)
+        if newCalendar and not newCalendar.owned() and not self.canShare():
+            newCalendar = None
+
         from twistedcaldav.storebridge import CalendarCollectionResource
         similar = CalendarCollectionResource(
             newCalendar, self, name=name,
@@ -2865,7 +2800,7 @@
             if defaultAddressBookProperty and len(defaultAddressBookProperty.children) == 1:
                 defaultAddressBook = str(defaultAddressBookProperty.children[0])
                 adbk = (yield request.locateResource(str(defaultAddressBook)))
-                if adbk is not None and isAddressBookCollectionResource(adbk) and adbk.exists() and not adbk.isVirtualShare():
+                if adbk is not None and isAddressBookCollectionResource(adbk) and adbk.exists() and not adbk.isShareeCollection():
                     returnValue(defaultAddressBookProperty)
 
             # Default is not valid - we have to try to pick one
@@ -2888,7 +2823,7 @@
             if len(new_adbk) == 1:
                 adbkURI = str(new_adbk[0])
                 adbk = (yield request.locateResource(str(new_adbk[0])))
-            if adbk is None or not adbk.exists() or not isAddressBookCollectionResource(adbk) or adbk.isVirtualShare():
+            if adbk is None or not adbk.exists() or not isAddressBookCollectionResource(adbk) or adbk.isShareeCollection():
                 # Validate that href's point to a valid addressbook.
                 raise HTTPError(ErrorResponse(
                     responsecode.CONFLICT,
@@ -2938,6 +2873,8 @@
                 mainCls = GlobalAddressBookCollectionResource
 
         newAddressBook = yield self._newStoreHome.addressbookWithName(name)
+        if newAddressBook and not newAddressBook.owned() and not self.canShare():
+            newAddressBook = None
         similar = mainCls(
             newAddressBook, self, name,
             principalCollections=self.principalCollections()
@@ -2955,13 +2892,17 @@
         defaultAddressBookURL = joinURL(self.url(), "addressbook")
         defaultAddressBook = (yield self.makeRegularChild("addressbook"))
         if defaultAddressBook is None or not defaultAddressBook.exists():
-            getter = iter((yield self._newStoreHome.addressbooks()))  # These are only unshared children
+            addressbooks = yield self._newStoreHome.addressbooks()
+            ownedAddressBooks = [addressbook for addressbook in addressbooks if addressbook.owned()]
+            ownedAddressBooks.sort(key=lambda ab:ab.name())
+
+            # These are only unshared children
             # FIXME: the back-end should re-provision a default addressbook here.
             # Really, the dead property shouldn't be necessary, and this should
             # be entirely computed by a back-end method like 'defaultAddressBook()'
             try:
-                anAddressBook = getter.next()
-            except StopIteration:
+                anAddressBook = ownedAddressBooks[0]
+            except IndexError:
                 raise RuntimeError("No address books at all.")
 
             defaultAddressBookURL = joinURL(self.url(), anAddressBook.name())

Modified: CalendarServer/trunk/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/schedule.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/schedule.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -245,7 +245,7 @@
         if defaultCalendarProperty and len(defaultCalendarProperty.children) == 1:
             defaultCalendar = str(defaultCalendarProperty.children[0])
             cal = (yield request.locateResource(str(defaultCalendar)))
-            if cal is not None and isCalendarCollectionResource(cal) and cal.exists() and not cal.isVirtualShare():
+            if cal is not None and isCalendarCollectionResource(cal) and cal.exists() and not cal.isShareeCollection():
                 returnValue(defaultCalendarProperty) 
         
         # Default is not valid - we have to try to pick one
@@ -272,7 +272,7 @@
 
         # TODO: check that owner of the new calendar is the same as owner of this inbox
         if cal is None or not cal.exists() or not isCalendarCollectionResource(cal) or \
-            cal.isVirtualShare() or not cal.isSupportedComponent(componentType):
+            cal.isShareeCollection() or not cal.isSupportedComponent(componentType):
             # Validate that href's point to a valid calendar.
             raise HTTPError(ErrorResponse(
                 responsecode.CONFLICT,
@@ -309,6 +309,8 @@
                     if calendarName == "inbox":
                         continue
                     calendar = (yield self.parent._newStoreHome.calendarWithName(calendarName))
+                    if not calendar.owned():
+                        continue
                     if not calendar.isSupportedComponent(componentType):
                         continue
                     break

Deleted: CalendarServer/trunk/twistedcaldav/sharedcollection.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/sharedcollection.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/sharedcollection.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -1,62 +0,0 @@
-##
-# Copyright (c) 2010-2012 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.
-##
-
-__all__ = [
-    "SharedCollectionResource",
-]
-
-from twext.web2.http import HTTPError, StatusResponse
-from twext.web2 import responsecode
-
-from twisted.internet.defer import inlineCallbacks, returnValue
-
-from twistedcaldav.linkresource import LinkResource
-
-
-"""
-Sharing behavior
-"""
-
-class SharedCollectionResource(LinkResource):
-    """
-    This is similar to a LinkResource except that we locate our shared collection resource dynamically.
-    """
-    
-    def __init__(self, parent, share):
-        self.share = share
-        super(SharedCollectionResource, self).__init__(parent, self.share.hosturl)
-
-    @inlineCallbacks
-    def linkedResource(self, request):
-        """
-        Resolve the share host url to the underlying resource (set to be a virtual share).
-        """
-        
-        if not hasattr(self, "_linkedResource"):
-            self._linkedResource = (yield request.locateResource(self.share.hosturl))
-            
-            if self._linkedResource is not None:
-                # FIXME: this is awkward - because we are "mutating" this object into a virtual share
-                # we must not cache the resource at this URL, otherwise an access of the owner's resource
-                # will return the same virtually shared one which would be wrong.
-                request._forgetResource(self._linkedResource, self.share.hosturl)
-    
-                ownerPrincipal = (yield self.parent.ownerPrincipal(request))
-                self._linkedResource.setVirtualShare(ownerPrincipal, self.share)
-            else:
-                raise HTTPError(StatusResponse(responsecode.NOT_FOUND, "Missing link target: %s" % (self.linkURL,)))
-
-        returnValue(self._linkedResource)

Modified: CalendarServer/trunk/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/sharing.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/sharing.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -30,6 +30,10 @@
 from twext.web2.dav.http import ErrorResponse, MultiStatusResponse
 from twext.web2.dav.resource import TwistedACLInheritable
 from twext.web2.dav.util import allDataFromStream, joinURL
+from txdav.common.datastore.sql_tables import _BIND_MODE_OWN, \
+    _BIND_MODE_READ, _BIND_MODE_WRITE, _BIND_STATUS_INVITED, \
+    _BIND_MODE_DIRECT, _BIND_STATUS_ACCEPTED, _BIND_STATUS_DECLINED, \
+    _BIND_STATUS_INVALID
 from txdav.xml import element
 
 from twisted.internet.defer import succeed, inlineCallbacks, DeferredList, \
@@ -40,19 +44,22 @@
 from twistedcaldav.customxml import calendarserver_namespace
 from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
 from twistedcaldav.linkresource import LinkFollowerMixIn
-from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
 from twistedcaldav.sql import AbstractSQLDatabase, db_prefix
 
 from pycalendar.datetime import PyCalendarDateTime
 
-from uuid import uuid4
 import os
 import types
 
-# Types of sharing mode
-SHARETYPE_INVITE = "I"  # Invite based sharing
-SHARETYPE_DIRECT = "D"  # Direct linking based sharing
+# FIXME: Get rid of these imports
+from twistedcaldav.directory.util import TRANSACTION_KEY
+# circular import
+#from txdav.common.datastore.sql import ECALENDARTYPE, EADDRESSBOOKTYPE
+ECALENDARTYPE = 0
+EADDRESSBOOKTYPE = 1
+#ENOTIFICATIONTYPE = 2
 
+
 class SharedCollectionMixin(object):
 
     @inlineCallbacks
@@ -63,20 +70,33 @@
         """
         if config.Sharing.Enabled:
 
+            def invitePropertyElement(invitation, includeUID=True):
+
+                userid = "urn:uuid:" + invitation.shareeUID()
+                principal = self.principalForUID(invitation.shareeUID())
+                cn = principal.displayName() if principal else invitation.shareeUID()
+                return customxml.InviteUser(
+                    customxml.UID.fromString(invitation.uid()) if includeUID else None,
+                    element.HRef.fromString(userid),
+                    customxml.CommonName.fromString(cn),
+                    customxml.InviteAccess(invitationAccessMapToXML[invitation.access()]()),
+                    invitationStatusMapToXML[invitation.state()](),
+                )
+
             # See if this property is on the shared calendar
             isShared = yield self.isShared(request)
             if isShared:
                 yield self.validateInvites(request)
-                records = yield self.invitesDB().allRecords()
+                invitations = yield self._allInvitations()
                 returnValue(customxml.Invite(
-                    *[record.makePropertyElement() for record in records]
+                    *[invitePropertyElement(invitation) for invitation in invitations]
                 ))
 
             # See if it is on the sharee calendar
-            if self.isVirtualShare():
-                original = (yield request.locateResource(self._share.hosturl))
+            if self.isShareeCollection():
+                original = (yield request.locateResource(self._share.url()))
                 yield original.validateInvites(request)
-                records = yield original.invitesDB().allRecords()
+                invitations = yield original._allInvitations()
 
                 ownerPrincipal = (yield original.ownerPrincipal(request))
                 owner = ownerPrincipal.principalURL()
@@ -87,7 +107,7 @@
                         element.HRef.fromString(owner),
                         customxml.CommonName.fromString(ownerCN),
                     ),
-                    *[record.makePropertyElement(includeUID=False) for record in records]
+                    *[invitePropertyElement(invitation, includeUID=False) for invitation in invitations]
                 ))
 
         returnValue(None)
@@ -101,10 +121,6 @@
         rtype = element.ResourceType(*(rtype.children + (customxml.SharedOwner(),)))
         self.writeDeadProperty(rtype)
 
-        # Create invites database
-        self.invitesDB().create()
-
-
     @inlineCallbacks
     def downgradeFromShare(self, request):
 
@@ -115,18 +131,14 @@
         self.writeDeadProperty(rtype)
 
         # Remove all invitees
-        for record in (yield self.invitesDB().allRecords()):
-            yield self.uninviteRecordFromShare(record, request)
+        for invitation in (yield self._allInvitations()):
+            yield self.uninviteFromShare(invitation, request)
 
-        # Remove invites database
-        self.invitesDB().remove()
-        delattr(self, "_invitesDB")
-
         returnValue(True)
 
 
     @inlineCallbacks
-    def changeUserInviteState(self, request, inviteUID, principalURL, state, summary=None):
+    def changeUserInviteState(self, request, inviteUID, shareeUID, state, summary=None):
         shared = (yield self.isShared(request))
         if not shared:
             raise HTTPError(ErrorResponse(
@@ -135,9 +147,8 @@
                 "Invalid share",
             ))
 
-        principalUID = principalURL.split("/")[3]
-        record = yield self.invitesDB().recordForInviteUID(inviteUID)
-        if record is None or record.principalUID != principalUID:
+        invitation = yield self._invitationForUID(inviteUID)
+        if invitation is None or invitation.shareeUID() != shareeUID:
             raise HTTPError(ErrorResponse(
                 responsecode.FORBIDDEN,
                 (customxml.calendarserver_namespace, "valid-request"),
@@ -145,11 +156,8 @@
             ))
 
         # Only certain states are sharer controlled
-        if record.state in ("NEEDS-ACTION", "ACCEPTED", "DECLINED",):
-            record.state = state
-            if summary is not None:
-                record.summary = summary
-            yield self.invitesDB().addOrUpdateRecord(record)
+        if invitation.state() in ("NEEDS-ACTION", "ACCEPTED", "DECLINED",):
+            yield self._updateInvitation(invitation, state=state, summary=summary)
 
 
     @inlineCallbacks
@@ -180,11 +188,11 @@
                 (calendarserver_namespace, "valid-principal"),
                 "Current user principal not specified",
             ))
-        principal = (yield request.locateResource(principalURL))
+        sharee = (yield request.locateResource(principalURL))
 
         # Check enabled for service
         from twistedcaldav.directory.principal import DirectoryCalendarPrincipalResource
-        if not isinstance(principal, DirectoryCalendarPrincipalResource):
+        if not isinstance(sharee, DirectoryCalendarPrincipalResource):
             raise HTTPError(ErrorResponse(
                 responsecode.FORBIDDEN,
                 (calendarserver_namespace, "invalid-principal"),
@@ -193,9 +201,9 @@
 
         # Get the home collection
         if self.isCalendarCollection():
-            home = yield principal.calendarHome(request)
+            shareeHomeResource = yield sharee.calendarHome(request)
         elif self.isAddressBookCollection():
-            home = yield principal.addressBookHome(request)
+            shareeHomeResource = yield sharee.addressBookHome(request)
         else:
             raise HTTPError(ErrorResponse(
                 responsecode.FORBIDDEN,
@@ -204,9 +212,9 @@
             ))
 
         # TODO: Make sure principal is not sharing back to themselves
-        compareURL = (yield self.canonicalURL(request))
-        homeURL = home.url()
-        if compareURL.startswith(homeURL):
+        hostURL = (yield self.canonicalURL(request))
+        shareeHomeURL = shareeHomeResource.url()
+        if hostURL.startswith(shareeHomeURL):
             raise HTTPError(ErrorResponse(
                 responsecode.FORBIDDEN,
                 (calendarserver_namespace, "invalid-share"),
@@ -214,8 +222,8 @@
             ))
 
         # Accept it
-        directID = home.sharesDB().directShareID(home, self)
-        response = (yield home.acceptDirectShare(request, compareURL, directID, self.displayName()))
+        directUID = Share.directUID(shareeHomeResource._newStoreHome, self._newStoreObject)
+        response = (yield shareeHomeResource.acceptDirectShare(request, hostURL, directUID, self.displayName()))
 
         # Return the URL of the shared calendar
         returnValue(response)
@@ -227,29 +235,26 @@
         returnValue((yield self.isSpecialCollection(customxml.SharedOwner)))
 
 
-    def setVirtualShare(self, shareePrincipal, share):
-        self._isVirtualShare = True
-        self._shareePrincipal = shareePrincipal
+    def setShare(self, share):
+        self._isShareeCollection = True #  _isShareeCollection attr is used by self tests
         self._share = share
 
-        if hasattr(self, "_newStoreObject"):
-            self._newStoreObject.setSharingUID(self._shareePrincipal.principalUID())
 
+    def isShareeCollection(self):
+        """ Return True if this is a sharee view of a shared calendar collection """
+        return hasattr(self, "_isShareeCollection")
 
-    def isVirtualShare(self):
-        """ Return True if this is a shared calendar collection """
-        return hasattr(self, "_isVirtualShare")
 
-
     @inlineCallbacks
-    def removeVirtualShare(self, request):
-        """ Return True if this is a shared calendar collection """
+    def removeShareeCollection(self, request):
 
+        sharee = self.principalForUID(self._share.shareeUID())
+
         # Remove from sharee's calendar/address book home
         if self.isCalendarCollection():
-            shareeHome = yield self._shareePrincipal.calendarHome(request)
+            shareeHome = yield sharee.calendarHome(request)
         elif self.isAddressBookCollection():
-            shareeHome = yield self._shareePrincipal.addressBookHome(request)
+            shareeHome = yield sharee.addressBookHome(request)
         returnValue((yield shareeHome.removeShare(request, self._share)))
 
 
@@ -262,8 +267,8 @@
         else:
             rtype = superMethod()
 
-        isVirt = self.isVirtualShare()
-        if isVirt:
+        isShareeCollection = self.isShareeCollection()
+        if isShareeCollection:
             rtype = element.ResourceType(
                 *(
                     tuple([child for child in rtype.children if child.qname() != customxml.SharedOwner.qname()]) +
@@ -289,50 +294,46 @@
     @inlineCallbacks
     def shareeAccessControlList(self, request, *args, **kwargs):
 
-        assert self._isVirtualShare, "Only call this for a virtual share"
+        assert self._isShareeCollection, "Only call this for a sharee collection"
 
         wikiAccessMethod = kwargs.get("wikiAccessMethod", getWikiAccess)
 
+        sharee = self.principalForUID(self._share.shareeUID())
+
         # Direct shares use underlying privileges of shared collection
-        if self._share.sharetype == SHARETYPE_DIRECT:
-            original = (yield request.locateResource(self._share.hosturl))
+        if self._share.direct():
+            original = (yield request.locateResource(self._share.url()))
             owner = yield original.ownerPrincipal(request)
             if owner.record.recordType == WikiDirectoryService.recordType_wikis:
                 # Access level comes from what the wiki has granted to the
                 # sharee
-                userID = self._shareePrincipal.record.guid
+                userID = sharee.record.guid
                 wikiID = owner.record.shortNames[0]
-                inviteAccess = (yield wikiAccessMethod(userID, wikiID))
-                if inviteAccess == "read":
-                    inviteAccess = "read-only"
-                elif inviteAccess in ("write", "admin"):
-                    inviteAccess = "read-write"
+                access = (yield wikiAccessMethod(userID, wikiID))
+                if access == "read":
+                    access = "read-only"
+                elif access in ("write", "admin"):
+                    access = "read-write"
                 else:
-                    inviteAccess = None
+                    access = None
             else:
                 result = (yield original.accessControlList(request, *args,
                     **kwargs))
                 returnValue(result)
         else:
-            # Invite shares use access mode from the invite
+            # Invited shares use access mode from the invite
+            # Get the access for self
+            access = Invitation(self._newStoreObject).access()
 
-            # Get the invite for this sharee
-            invite = yield self.invitesDB().recordForInviteUID(
-                self._share.shareuid
-            )
-            if invite is None:
-                returnValue(element.ACL())
-            inviteAccess = invite.access
-
         userprivs = [
         ]
-        if inviteAccess in ("read-only", "read-write", "read-write-schedule",):
+        if access in ("read-only", "read-write",):
             userprivs.append(element.Privilege(element.Read()))
             userprivs.append(element.Privilege(element.ReadACL()))
             userprivs.append(element.Privilege(element.ReadCurrentUserPrivilegeSet()))
-        if inviteAccess in ("read-only",):
+        if access in ("read-only",):
             userprivs.append(element.Privilege(element.WriteProperties()))
-        if inviteAccess in ("read-write", "read-write-schedule",):
+        if access in ("read-write",):
             userprivs.append(element.Privilege(element.Write()))
         proxyprivs = list(userprivs)
         try:
@@ -344,7 +345,7 @@
         aces = (
             # Inheritable specific access for the resource's associated principal.
             element.ACE(
-                element.Principal(element.HRef(self._shareePrincipal.principalURL())),
+                element.Principal(element.HRef(sharee.principalURL())),
                 element.Grant(*userprivs),
                 element.Protected(),
                 TwistedACLInheritable(),
@@ -371,7 +372,7 @@
             aces += (
                 # DAV:read/DAV:read-current-user-privilege-set access for this principal's calendar-proxy-read users.
                 element.ACE(
-                    element.Principal(element.HRef(joinURL(self._shareePrincipal.principalURL(), "calendar-proxy-read/"))),
+                    element.Principal(element.HRef(joinURL(sharee.principalURL(), "calendar-proxy-read/"))),
                     element.Grant(
                         element.Privilege(element.Read()),
                         element.Privilege(element.ReadCurrentUserPrivilegeSet()),
@@ -381,7 +382,7 @@
                 ),
                 # DAV:read/DAV:read-current-user-privilege-set/DAV:write access for this principal's calendar-proxy-write users.
                 element.ACE(
-                    element.Principal(element.HRef(joinURL(self._shareePrincipal.principalURL(), "calendar-proxy-write/"))),
+                    element.Principal(element.HRef(joinURL(sharee.principalURL(), "calendar-proxy-write/"))),
                     element.Grant(*proxyprivs),
                     element.Protected(),
                     TwistedACLInheritable(),
@@ -392,7 +393,7 @@
 
 
     @inlineCallbacks
-    def validUserIDForShare(self, userid, request):
+    def validUserIDForShare(self, userid, request=None):
         """
         Test the user id to see if it is a valid identifier for sharing and
         return a "normalized" form for our own use (e.g. convert mailto: to
@@ -408,10 +409,11 @@
         # First try to resolve as a principal
         principal = self.principalForCalendarUserAddress(userid)
         if principal:
-            ownerPrincipal = (yield self.ownerPrincipal(request))
-            owner = ownerPrincipal.principalURL()
-            if owner == principal.principalURL():
-                returnValue(None)
+            if request:
+                ownerPrincipal = (yield self.ownerPrincipal(request))
+                owner = ownerPrincipal.principalURL()
+                if owner == principal.principalURL():
+                    returnValue(None)
             returnValue(principal.principalURL())
 
         # TODO: we do not support external users right now so this is being hard-coded
@@ -422,48 +424,21 @@
             returnValue(None)
 
 
-    def validUserIDWithCommonNameForShare(self, userid, cn):
-        """
-        Validate user ID and find the common name.
-
-        @param userid: the userid to test
-        @type userid: C{str}
-        @param cn: default common name to use if principal has none
-        @type cn: C{str}
-
-        @return: C{tuple} of C{str} of normalized userid or C{None} if
-            userid is not allowed, and appropriate common name.
-        """
-
-        # First try to resolve as a principal
-        principal = self.principalForCalendarUserAddress(userid)
-        if principal:
-            return userid, principal.principalURL(), principal.displayName()
-
-        # TODO: we do not support external users right now so this is being hard-coded
-        # off in spite of the config option.
-        #elif config.Sharing.AllowExternalUsers:
-        #    return userid, None, cn
-        else:
-            return None, None, None
-
-
     @inlineCallbacks
     def validateInvites(self, request):
         """
         Make sure each userid in an invite is valid - if not re-write status.
         """
+        #assert request
+        invitations = yield self._allInvitations()
+        for invitation in invitations:
+            if invitation.state() != "INVALID":
+                if not (yield self.validUserIDForShare("urn:uuid:" + invitation.shareeUID(), request)):
+                    yield self._updateInvitation(invitation, state="INVALID")
 
-        records = yield self.invitesDB().allRecords()
-        for record in records:
-            uid = (yield self.validUserIDForShare(record.userid, request))
-            if uid is None and record.state != "INVALID":
-                record.state = "INVALID"
-                yield self.invitesDB().addOrUpdateRecord(record)
+        returnValue(len(invitations))
 
-        returnValue(len(records))
 
-
     def inviteUserToShare(self, userid, cn, ace, summary, request):
         """ Send out in invite first, and then add this user to the share list
             @param userid:
@@ -520,76 +495,103 @@
 
 
     @inlineCallbacks
-    def _createLock(self, userid, request):
+    def _createInvitation(self, shareeUID, access, summary,):
+        '''
+        Create a new homeChild and wrap it in an Invitation
+        '''
+        if self.isCalendarCollection():
+            shareeHome = yield self._newStoreObject._txn.calendarHomeWithUID(shareeUID, create=True)
+        elif self.isAddressBookCollection():
+            shareeHome = yield self._newStoreObject._txn.addressbookHomeWithUID(shareeUID, create=True)
+
+        sharedName = yield self._newStoreObject.shareWith(shareeHome,
+                                                    mode=invitationAccessToBindModeMap[access],
+                                                    status=_BIND_STATUS_INVITED,
+                                                    message=summary)
+
+        shareeHomeChild = yield shareeHome.invitedChildWithName(sharedName)
+        invitation = Invitation(shareeHomeChild)
+        returnValue(invitation)
+
+    @inlineCallbacks
+    def _updateInvitation(self, invitation, access=None, state=None, summary=None):
+        mode = None if access is None else invitationAccessToBindModeMap[access]
+        status = None if state is None else invitationStateToBindStatusMap[state]
+
+        yield self._newStoreObject.updateShare(invitation._shareeHomeChild, mode=mode, status=status, message=summary)
+        assert not access or access == invitation.access(), "access=%s != invitation.access()=%s" % (access, invitation.access())
+        assert not state or state == invitation.state(), "state=%s != invitation.state()=%s" % (state, invitation.state())
+        assert not summary or summary == invitation.summary(), "summary=%s != invitation.summary()=%s" % (summary, invitation.summary())
+
+
+    @inlineCallbacks
+    def _allInvitations(self, includeAccepted=True):
         """
-        Create an instance of MemcacheLock whose key is based on the sharee's
-        uid and the collection's URL
+        Get list of all invitations to this object
+        
+        For legacy reasons, all invitations are all invited + shared (accepted, not direct).
+        Combine these two into a single sorted list so code is similar to that for legacy invite db
         """
-        returnValue(MemcacheLock(
-            "ShareInviteLock",
-            (yield self._lockToken(userid, request)),
-            timeout=config.Scheduling.Options.UIDLockTimeoutSeconds,
-            expire_time=config.Scheduling.Options.UIDLockExpirySeconds,
-        ))
+        invitedHomeChildren = yield self._newStoreObject.asInvited()
+        if includeAccepted:
+            acceptedHomeChildren = yield self._newStoreObject.asShared()
+            # remove direct shares (it might be OK not to remove these, that would be different from legacy code)
+            indirectAccceptedHomeChildren = [homeChild for homeChild in acceptedHomeChildren
+                                             if homeChild.shareMode() != _BIND_MODE_DIRECT]
+            invitedHomeChildren += indirectAccceptedHomeChildren
 
+        invitations = [Invitation(homeChild) for homeChild in invitedHomeChildren]
+        invitations.sort(key=lambda invitation:invitation.shareeUID())
 
+        returnValue(invitations)
+
     @inlineCallbacks
-    def _acquireLock(self, lock):
+    def _invitationForShareeUID(self, shareeUID, includeAccepted=True):
         """
-        Attempt to acquire a lock -- can raise MemcacheLockTimeoutError
+        Get an invitation for this sharee principal UID
         """
-        try:
-            yield lock.acquire()
-        except MemcacheLockTimeoutError:
-            self.log_error("Memcache lock timeout for sharing invite")
-            raise
+        invitations = yield self._allInvitations(includeAccepted=includeAccepted)
+        for invitation in invitations:
+            if invitation.shareeUID() == shareeUID:
+                returnValue(invitation)
+        returnValue(None)
 
 
     @inlineCallbacks
-    def _lockToken(self, userid, request):
+    def _invitationForUID(self, uid, includeAccepted=True):
         """
-        Generate a string we can use for a memcache lock key
+        Get an invitation for an invitations uid 
         """
-        hosturl = (yield self.canonicalURL(request))
-        returnValue("%s:%s" % (hosturl, userid))
+        invitations = yield self._allInvitations(includeAccepted=includeAccepted)
+        for invitation in invitations:
+            if invitation.uid() == uid:
+                returnValue(invitation)
+        returnValue(None)
 
 
+
     @inlineCallbacks
     def inviteSingleUserToShare(self, userid, cn, ace, summary, request):
 
-        # Validate userid and cn
-        userid, principalURL, cn = self.validUserIDWithCommonNameForShare(userid, cn)
-
         # We currently only handle local users
-        if principalURL is None:
+        sharee = self.principalForCalendarUserAddress(userid)
+        if not sharee:
             returnValue(False)
 
-        # Acquire a memcache lock based on collection URL and sharee UID
-        # TODO: when sharing moves into the store this should be replaced
-        # by DB-level locking
-        lock = (yield self._createLock(userid, request))
-        yield self._acquireLock(lock)
+        shareeUID = sharee.principalUID()
 
-        try:
-            # Look for existing invite and update its fields or create new one
-            principalUID = principalURL.split("/")[3]
-            record = yield self.invitesDB().recordForPrincipalUID(principalUID)
-            if record:
-                record.name = cn
-                record.access = inviteAccessMapFromXML[type(ace)]
-                record.summary = summary
-            else:
-                record = Invite(str(uuid4()), userid, principalUID, cn, inviteAccessMapFromXML[type(ace)], "NEEDS-ACTION", summary)
+        # Look for existing invite and update its fields or create new one
+        invitation = yield self._invitationForShareeUID(shareeUID)
+        if invitation:
+            yield self._updateInvitation(invitation, access=invitationAccessMapFromXML[type(ace)], summary=summary)
+        else:
+            invitation = yield self._createInvitation(
+                                shareeUID=shareeUID,
+                                access=invitationAccessMapFromXML[type(ace)],
+                                summary=summary)
+        # Send invite notification
+        yield self.sendInviteNotification(invitation, request)
 
-            # Send invite
-            yield self.sendInvite(record, request)
-
-            # Add to database
-            yield self.invitesDB().addOrUpdateRecord(record)
-
-        finally:
-            lock.clean()
-
         returnValue(True)
 
 
@@ -597,46 +599,41 @@
     def uninviteSingleUserFromShare(self, userid, aces, request):
         # Cancel invites - we'll just use whatever userid we are given
 
-        # Acquire a memcache lock based on collection URL and sharee UID
-        # TODO: when sharing moves into the store this should be replaced
-        # by DB-level locking
-        lock = (yield self._createLock(userid, request))
-        yield self._acquireLock(lock)
+        sharee = self.principalForCalendarUserAddress(userid)
+        if not sharee:
+            returnValue(False)
 
-        try:
-            record = yield self.invitesDB().recordForUserID(userid)
-            if record:
-                result = (yield self.uninviteRecordFromShare(record, request))
-            else:
-                result = False
-        finally:
-            lock.clean()
+        shareeUID = sharee.principalUID()
 
+        invitation = yield self._invitationForShareeUID(shareeUID)
+        if invitation:
+            result = (yield self.uninviteFromShare(invitation, request))
+        else:
+            result = False
+
         returnValue(result)
 
 
     @inlineCallbacks
-    def uninviteRecordFromShare(self, record, request):
+    def uninviteFromShare(self, invitation, request):
 
         # Remove any shared calendar or address book
-        sharee = self.principalForCalendarUserAddress(record.userid)
+        sharee = self.principalForUID(invitation.shareeUID())
         if sharee:
             if self.isCalendarCollection():
-                shareeHome = yield sharee.calendarHome(request)
+                shareeHomeResource = yield sharee.calendarHome(request)
             elif self.isAddressBookCollection():
-                shareeHome = yield sharee.addressBookHome(request)
-            displayname = (yield shareeHome.removeShareByUID(request, record.inviteuid))
-
+                shareeHomeResource = yield sharee.addressBookHome(request)
+            displayName = (yield shareeHomeResource.removeShareByUID(request, invitation.uid()))
             # If current user state is accepted then we send an invite with the new state, otherwise
             # we cancel any existing invites for the user
-            if record and record.state != "ACCEPTED":
-                yield self.removeInvite(record, request)
-            elif record:
-                record.state = "DELETED"
-                yield self.sendInvite(record, request, displayname=displayname)
+            if invitation and invitation.state() != "ACCEPTED":
+                yield self.removeInviteNotification(invitation, request)
+            elif invitation:
+                yield self.sendInviteNotification(invitation, request, displayName=displayName, notificationState="DELETED")
 
-        # Remove from database
-        yield self.invitesDB().removeRecordForInviteUID(record.inviteuid)
+        # Direct shares for  with valid sharee principal will already be deleted
+        yield self._newStoreObject.unshareWith(invitation._shareeHomeChild.viewerHome())
 
         returnValue(True)
 
@@ -648,7 +645,7 @@
 
 
     @inlineCallbacks
-    def sendInvite(self, record, request, displayname=None):
+    def sendInviteNotification(self, invitation, request, notificationState=None, displayName=None):
 
         ownerPrincipal = (yield self.ownerPrincipal(request))
         owner = ownerPrincipal.principalURL()
@@ -656,30 +653,37 @@
         hosturl = (yield self.canonicalURL(request))
 
         # Locate notifications collection for user
-        sharee = self.principalForCalendarUserAddress(record.userid)
+        sharee = self.principalForUID(invitation.shareeUID())
         if sharee is None:
-            raise ValueError("sharee is None but userid was valid before")
+            raise ValueError("sharee is None but principalUID was valid before")
 
         # We need to look up the resource so that the response cache notifier is properly initialized
         notificationResource = (yield request.locateResource(sharee.notificationURL()))
         notifications = notificationResource._newStoreNotifications
 
+        '''
         # Look for existing notification
-        oldnotification = (yield notifications.notificationObjectWithUID(record.inviteuid))
+        # oldnotification is not used don't query for it
+        oldnotification = (yield notifications.notificationObjectWithUID(invitation.uid()))
         if oldnotification:
             # TODO: rollup changes?
             pass
+        '''
 
         # Generate invite XML
-        typeAttr = {'shared-type': self.sharedResourceType()}
+        userid = "urn:uuid:" + invitation.shareeUID()
+        state = notificationState if notificationState else invitation.state()
+        summary = invitation.summary() if displayName is None else displayName
+
+        typeAttr = {'shared-type':self.sharedResourceType()}
         xmltype = customxml.InviteNotification(**typeAttr)
         xmldata = customxml.Notification(
             customxml.DTStamp.fromString(PyCalendarDateTime.getNowUTC().getText()),
             customxml.InviteNotification(
-                customxml.UID.fromString(record.inviteuid),
-                element.HRef.fromString(record.userid),
-                inviteStatusMapToXML[record.state](),
-                customxml.InviteAccess(inviteAccessMapToXML[record.access]()),
+                customxml.UID.fromString(invitation.uid()),
+                element.HRef.fromString(userid),
+                invitationStatusMapToXML[state](),
+                customxml.InviteAccess(invitationAccessMapToXML[invitation.access()]()),
                 customxml.HostURL(
                     element.HRef.fromString(hosturl),
                 ),
@@ -687,29 +691,28 @@
                     element.HRef.fromString(owner),
                     customxml.CommonName.fromString(ownerCN),
                 ),
-                customxml.InviteSummary.fromString(record.summary if displayname is None else displayname),
+                customxml.InviteSummary.fromString(summary),
                 self.getSupportedComponentSet() if self.isCalendarCollection() else None,
                 **typeAttr
             ),
         ).toxml()
 
         # Add to collections
-        yield notifications.writeNotificationObject(record.inviteuid, xmltype, xmldata)
+        yield notifications.writeNotificationObject(invitation.uid(), xmltype, xmldata)
 
-
     @inlineCallbacks
-    def removeInvite(self, record, request):
+    def removeInviteNotification(self, invitation, request):
 
         # Locate notifications collection for user
-        sharee = self.principalForCalendarUserAddress(record.userid)
+        sharee = self.principalForUID(invitation.shareeUID())
         if sharee is None:
-            raise ValueError("sharee is None but userid was valid before")
-        notifications = (yield request.locateResource(sharee.notificationURL()))
+            raise ValueError("sharee is None but principalUID was valid before")
+        notificationResource = (yield request.locateResource(sharee.notificationURL()))
+        notifications = notificationResource._newStoreNotifications
 
         # Add to collections
-        yield notifications.deleteNotifictionMessageByUID(request, record.inviteuid)
+        yield notifications.removeNotificationObjectWithUID(invitation.uid())
 
-
     @inlineCallbacks
     def _xmlHandleInvite(self, request, docroot):
         yield self.authorize(request, (element.Read(), element.Write()))
@@ -912,45 +915,68 @@
         ("text", "xml") : xmlRequestHandler,
     }
 
-inviteAccessMapToXML = {
+invitationAccessMapToXML = {
     "read-only"           : customxml.ReadAccess,
     "read-write"          : customxml.ReadWriteAccess,
 }
-inviteAccessMapFromXML = dict([(v, k) for k, v in inviteAccessMapToXML.iteritems()])
+invitationAccessMapFromXML = dict([(v, k) for k, v in invitationAccessMapToXML.iteritems()])
 
-inviteStatusMapToXML = {
+invitationStatusMapToXML = {
     "NEEDS-ACTION" : customxml.InviteStatusNoResponse,
     "ACCEPTED"     : customxml.InviteStatusAccepted,
     "DECLINED"     : customxml.InviteStatusDeclined,
     "DELETED"      : customxml.InviteStatusDeleted,
     "INVALID"      : customxml.InviteStatusInvalid,
 }
-inviteStatusMapFromXML = dict([(v, k) for k, v in inviteStatusMapToXML.iteritems()])
+invitationStatusMapFromXML = dict([(v, k) for k, v in invitationStatusMapToXML.iteritems()])
 
-class Invite(object):
+invitationStateToBindStatusMap = {
+    "NEEDS-ACTION": _BIND_STATUS_INVITED,
+    "ACCEPTED": _BIND_STATUS_ACCEPTED,
+    "DECLINED": _BIND_STATUS_DECLINED,
+    "INVALID": _BIND_STATUS_INVALID,
+}
+invitationStateFromBindStatusMap = dict((v, k) for k, v in invitationStateToBindStatusMap.iteritems())
+invitationAccessToBindModeMap = {
+    "own": _BIND_MODE_OWN,
+    "read-only": _BIND_MODE_READ,
+    "read-write": _BIND_MODE_WRITE,
+    }
+invitationAccessFromBindModeMap = dict((v, k) for k, v in invitationAccessToBindModeMap.iteritems())
 
+class Invitation(object):
+    """
+        Invitation is a read-only wrapper for CommonHomeChild, that uses terms similar LegacyInvite sharing.py code base.
+    """
+    def __init__(self, shareeHomeChild):
+        self._shareeHomeChild = shareeHomeChild
+
+    def uid(self):
+        return self._shareeHomeChild.shareUID()
+
+    def shareeUID(self):
+        return self._shareeHomeChild.viewerHome().uid()
+
+    def access(self):
+        return invitationAccessFromBindModeMap.get(self._shareeHomeChild.shareMode())
+
+    def state(self):
+        return invitationStateFromBindStatusMap.get(self._shareeHomeChild.shareStatus())
+
+    def summary(self):
+        return self._shareeHomeChild.shareMessage()
+
+
+class LegacyInvite(object):
+
     def __init__(self, inviteuid, userid, principalUID, common_name, access, state, summary):
         self.inviteuid = inviteuid
-        self.userid = userid
         self.principalUID = principalUID
-        self.name = common_name
         self.access = access
         self.state = state
         self.summary = summary
 
 
-    def makePropertyElement(self, includeUID=True):
-
-        return customxml.InviteUser(
-            customxml.UID.fromString(self.inviteuid) if includeUID else None,
-            element.HRef.fromString(self.userid),
-            customxml.CommonName.fromString(self.name),
-            customxml.InviteAccess(inviteAccessMapToXML[self.access]()),
-            inviteStatusMapToXML[self.state](),
-        )
-
-
-
 class InvitesDatabase(AbstractSQLDatabase, LoggingMixIn):
 
     db_basename = db_prefix + "invites"
@@ -1011,7 +1037,7 @@
 
         self._db_execute("""insert or replace into INVITE (INVITEUID, USERID, PRINCIPALUID, NAME, ACCESS, STATE, SUMMARY)
             values (:1, :2, :3, :4, :5, :6, :7)
-            """, record.inviteuid, record.userid, record.principalUID, record.name, record.access, record.state, record.summary,
+            """, record.inviteuid, "userid", record.principalUID, "name", record.access, record.state, record.summary,
         )
 
 
@@ -1097,53 +1123,84 @@
 
     def _makeRecord(self, row):
 
-        return Invite(*[str(item) if type(item) == types.UnicodeType else item for item in row])
+        return LegacyInvite(*[str(item) if type(item) == types.UnicodeType else item for item in row])
 
-
-
 class SharedHomeMixin(LinkFollowerMixIn):
     """
     A mix-in for calendar/addressbook homes that defines the operations for
     manipulating a sharee's set of shared calendars.
     """
 
+
     @inlineCallbacks
-    def provisionShare(self, name):
+    def provisionShare(self, child, request=None):
+        share = yield self._shareForHomeChild(child._newStoreObject, request)
+        if share:
+            child.setShare(share)
+
+    @inlineCallbacks
+    def _shareForHomeChild(self, child, request=None):
         # Try to find a matching share
-        child = None
-        shares = yield self.allShares()
-        if name in shares:
-            from twistedcaldav.sharedcollection import SharedCollectionResource
-            child = SharedCollectionResource(self, shares[name])
-            self.putChild(name, child)
-        returnValue(child)
+        if not child or child.owned():
+            returnValue(None)
 
+        sharerHomeChild = yield child.ownerHome().childWithID(child._resourceID)
 
-    @inlineCallbacks
-    def allShares(self):
-        if not hasattr(self, "_allShares"):
-            allShareRecords = yield self.sharesDB().allRecords()
-            self._allShares = dict([(share.localname, share) for share in
-                                    allShareRecords])
-        returnValue(self._allShares)
+        # get the shared object's URL
+        sharer = self.principalForUID(sharerHomeChild.viewerHome().uid())
 
+        if not request:
+            # FIXEME:  Fake up a request that can be used to get the sharer home resource
+            class _FakeRequest(object):pass
+            fakeRequest = _FakeRequest()
+            setattr(fakeRequest, TRANSACTION_KEY, self._newStoreHome._txn)
+            request = fakeRequest
 
+        if self._newStoreHome._homeType == ECALENDARTYPE:
+            sharerHomeCollection = yield sharer.calendarHome(request)
+        elif self._newStoreHome._homeType == EADDRESSBOOKTYPE:
+            sharerHomeCollection = yield sharer.addressBookHome(request)
+
+        url = joinURL(sharerHomeCollection.url(), sharerHomeChild.name())
+        share = Share(shareeHomeChild=child, sharerHomeChild=sharerHomeChild, url=url)
+
+        returnValue(share)
+
     @inlineCallbacks
-    def allShareNames(self):
-        allShares = yield self.allShares()
-        returnValue(tuple(allShares.keys()))
+    def _shareForUID(self, shareUID, request):
 
+        # since child.shareUID() == child.name() for indirect shares
+        child = yield self._newStoreHome.childWithName(shareUID)
+        if child:
+            share = yield self._shareForHomeChild(child, request)
+            if share and share.uid() == shareUID:
+                returnValue(share)
 
+        # find direct shares
+        children = yield self._newStoreHome.children()
+        for child in children:
+            share = yield self._shareForHomeChild(child, request)
+            if share and share.uid() == shareUID:
+                returnValue(share)
+
+        returnValue(None)
+
     @inlineCallbacks
     def acceptInviteShare(self, request, hostUrl, inviteUID, displayname=None):
 
         # Check for old share
-        oldShare = yield self.sharesDB().recordForShareUID(inviteUID)
+        oldShare = yield self._shareForUID(inviteUID, request)
 
         # Send the invite reply then add the link
         yield self._changeShare(request, "ACCEPTED", hostUrl, inviteUID, displayname)
+        if oldShare:
+            share = oldShare
+        else:
+            sharedCollection = yield request.locateResource(hostUrl)
+            shareeHomeChild = yield self._newStoreHome.childWithName(inviteUID)
+            share = Share(shareeHomeChild=shareeHomeChild, sharerHomeChild=sharedCollection._newStoreObject, url=hostUrl)
 
-        response = (yield self._acceptShare(request, oldShare, SHARETYPE_INVITE, hostUrl, inviteUID, displayname))
+        response = yield self._acceptShare(request, not oldShare, share, displayname)
         returnValue(response)
 
 
@@ -1151,47 +1208,58 @@
     def acceptDirectShare(self, request, hostUrl, resourceUID, displayname=None):
 
         # Just add the link
-        oldShare = yield self.sharesDB().recordForShareUID(resourceUID)
-        response = (yield self._acceptShare(request, oldShare, SHARETYPE_DIRECT, hostUrl, resourceUID, displayname))
+        oldShare = yield self._shareForUID(resourceUID, request)
+        if oldShare:
+            share = oldShare
+        else:
+            sharedCollection = yield request.locateResource(hostUrl)
+            sharedName = yield sharedCollection._newStoreObject.shareWith(shareeHome=self._newStoreHome,
+                                                    mode=_BIND_MODE_DIRECT,
+                                                    status=_BIND_STATUS_ACCEPTED,
+                                                    message=displayname)
+
+            shareeHomeChild = yield self._newStoreHome.childWithName(sharedName)
+            share = Share(shareeHomeChild=shareeHomeChild, sharerHomeChild=sharedCollection._newStoreObject, url=hostUrl)
+
+        response = yield self._acceptShare(request, not oldShare, share, displayname)
         returnValue(response)
 
-
     @inlineCallbacks
-    def _acceptShare(self, request, oldShare, sharetype, hostUrl, shareUID, displayname=None):
+    def _acceptShare(self, request, isNewShare, share, displayname=None):
 
-        # Add or update in DB
-        if oldShare:
-            share = oldShare
-        else:
-            share = SharedCollectionRecord(shareUID, sharetype, hostUrl, str(uuid4()), displayname)
-            yield self.sharesDB().addOrUpdateRecord(share)
-
         # Get shared collection in non-share mode first
-        sharedCollection = (yield request.locateResource(hostUrl))
-        ownerPrincipal = (yield self.ownerPrincipal(request))
+        sharedCollection = yield request.locateResource(share.url())
 
         # For a direct share we will copy any calendar-color over using the owners view
         color = None
-        if sharetype == SHARETYPE_DIRECT and not oldShare and sharedCollection.isCalendarCollection():
+        if share.direct() and isNewShare and sharedCollection.isCalendarCollection():
             try:
                 color = (yield sharedCollection.readProperty(customxml.CalendarColor, request))
             except HTTPError:
                 pass
 
+        sharee = self.principalForUID(share.shareeUID())
+        if sharedCollection.isCalendarCollection():
+            shareeHomeResource = yield sharee.calendarHome(request)
+        elif sharedCollection.isAddressBookCollection():
+            shareeHomeResource = yield sharee.addressBookHome(request)
+        shareeURL = joinURL(shareeHomeResource.url(), share.name())
+        shareeCollection = yield request.locateResource(shareeURL)
+        shareeCollection.setShare(share)
+
         # Set per-user displayname or color to whatever was given
-        sharedCollection.setVirtualShare(ownerPrincipal, share)
         if displayname:
-            yield sharedCollection.writeProperty(element.DisplayName.fromString(displayname), request)
+            yield shareeCollection.writeProperty(element.DisplayName.fromString(displayname), request)
         if color:
-            yield sharedCollection.writeProperty(customxml.CalendarColor.fromString(color), request)
+            yield shareeCollection.writeProperty(customxml.CalendarColor.fromString(color), request)
 
         # Calendars always start out transparent and with empty default alarms
-        if not oldShare and sharedCollection.isCalendarCollection():
-            yield sharedCollection.writeProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Transparent()), request)
-            yield sharedCollection.writeProperty(caldavxml.DefaultAlarmVEventDateTime.fromString(""), request)
-            yield sharedCollection.writeProperty(caldavxml.DefaultAlarmVEventDate.fromString(""), request)
-            yield sharedCollection.writeProperty(caldavxml.DefaultAlarmVToDoDateTime.fromString(""), request)
-            yield sharedCollection.writeProperty(caldavxml.DefaultAlarmVToDoDate.fromString(""), request)
+        if isNewShare and shareeCollection.isCalendarCollection():
+            yield shareeCollection.writeProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Transparent()), request)
+            yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDateTime.fromString(""), request)
+            yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDate.fromString(""), request)
+            yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVToDoDateTime.fromString(""), request)
+            yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVToDoDate.fromString(""), request)
 
         # Notify client of changes
         yield self.notifyChanged()
@@ -1200,7 +1268,7 @@
         returnValue(XMLResponse(
             code=responsecode.OK,
             element=customxml.SharedAs(
-                element.HRef.fromString(joinURL(self.url(), share.localname))
+                element.HRef.fromString(joinURL(self.url(), share.name()))
             )
         ))
 
@@ -1211,13 +1279,13 @@
         Remove a shared collection named in resourceName
         """
 
-        # Send a decline when an invite share is removed only
-        if share.sharetype == SHARETYPE_INVITE:
-            result = (yield self.declineShare(request, share.hosturl, share.shareuid))
-            returnValue(result)
-        else:
+        if share.direct():
             yield self.removeDirectShare(request, share)
             returnValue(None)
+        else:
+            # Send a decline when an invite share is removed only
+            result = yield self.declineShare(request, share.url(), share.uid())
+            returnValue(result)
 
 
     @inlineCallbacks
@@ -1227,14 +1295,13 @@
         current display name of the shared collection.
         """
 
-        displayname = None
-        share = yield self.sharesDB().recordForShareUID(shareUID)
+        share = yield self._shareForUID(shareUID, request)
         if share:
-            displayname = yield self.removeDirectShare(request, share)
+            displayName = (yield self.removeDirectShare(request, share))
+            returnValue(displayName)
+        else:
+            returnValue(None)
 
-        returnValue(displayname)
-
-
     @inlineCallbacks
     def removeDirectShare(self, request, share):
         """
@@ -1242,7 +1309,7 @@
         current display name of the shared collection.
         """
 
-        shareURL = joinURL(self.url(), share.localname)
+        shareURL = joinURL(self.url(), share.name())
         shared = (yield request.locateResource(shareURL))
         displayname = shared.displayName()
 
@@ -1254,10 +1321,11 @@
                 inbox = (yield request.locateResource(inboxURL))
                 inbox.processFreeBusyCalendar(shareURL, False)
 
-        yield self.sharesDB().removeRecordForShareUID(share.shareuid)
 
-        # Notify client of changes
-        yield self.notifyChanged()
+        if share.direct():
+            yield share._sharerHomeChild.unshareWith(share._shareeHomeChild.viewerHome())
+        else:
+            yield share._sharerHomeChild.updateShare(share._shareeHomeChild, status=_BIND_STATUS_DECLINED)
 
         returnValue(displayname)
 
@@ -1281,7 +1349,7 @@
 
         # Change state in sharer invite
         ownerPrincipal = (yield self.ownerPrincipal(request))
-        owner = ownerPrincipal.principalURL()
+        ownerPrincipalUID = ownerPrincipal.principalUID()
         sharedCollection = (yield request.locateResource(hostUrl))
         if sharedCollection is None:
             # Original shared collection is gone - nothing we can do except ignore it
@@ -1292,7 +1360,7 @@
             ))
 
         # Change the record
-        yield sharedCollection.changeUserInviteState(request, replytoUID, owner, state, displayname)
+        yield sharedCollection.changeUserInviteState(request, replytoUID, ownerPrincipalUID, state, displayname)
 
         yield self.sendReply(request, ownerPrincipal, sharedCollection, state, hostUrl, replytoUID, displayname)
 
@@ -1302,7 +1370,8 @@
 
         # Locate notifications collection for sharer
         sharer = (yield sharedCollection.ownerPrincipal(request))
-        notifications = (yield request.locateResource(sharer.notificationURL()))
+        notificationResource = (yield request.locateResource(sharer.notificationURL()))
+        notifications = notificationResource._newStoreNotifications
 
         # Generate invite XML
         notificationUID = "%s-reply" % (replytoUID,)
@@ -1324,7 +1393,7 @@
                 *(
                     (
                         element.HRef.fromString(cua),
-                        inviteStatusMapToXML[state](),
+                        invitationStatusMapToXML[state](),
                         customxml.HostURL(
                             element.HRef.fromString(hostUrl),
                         ),
@@ -1338,7 +1407,7 @@
         ).toxml()
 
         # Add to collections
-        yield notifications.addNotification(request, notificationUID, xmltype, xmldata)
+        yield notifications.writeNotificationObject(notificationUID, xmltype, xmldata)
 
 
     def _handleInviteReply(self, request, invitereplydoc):
@@ -1383,8 +1452,39 @@
         self.localname = localname
         self.summary = summary
 
+class Share(object):
 
+    def __init__(self, sharerHomeChild, shareeHomeChild, url):
+        self._shareeHomeChild = shareeHomeChild
+        self._sharerHomeChild = sharerHomeChild
+        self._sharedResourceURL = url
 
+    @classmethod
+    def directUID(cls, shareeHome, sharerHomeChild):
+        return "Direct-%s-%s" % (shareeHome._resourceID, sharerHomeChild._resourceID,)
+
+    def uid(self):
+        # Move to CommonHomeChild shareUID?
+        if self._shareeHomeChild.shareMode() == _BIND_MODE_DIRECT:
+            return self.directUID(shareeHome=self._shareeHomeChild.viewerHome(), sharerHomeChild=self._sharerHomeChild,)
+        else:
+            return self._shareeHomeChild.shareUID()
+
+    def direct(self):
+        return self._shareeHomeChild.shareMode() == _BIND_MODE_DIRECT
+
+    def url(self):
+        return self._sharedResourceURL
+
+    def name(self):
+        return self._shareeHomeChild.name()
+
+    def summary(self):
+        return self._shareeHomeChild.shareMessage()
+
+    def shareeUID(self):
+        return self._shareeHomeChild.viewerHome().uid()
+
 class SharedCollectionsDatabase(AbstractSQLDatabase, LoggingMixIn):
 
     db_basename = db_prefix + "shares"

Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -32,6 +32,7 @@
 from txdav.base.propertystore.base import PropertyName
 from txdav.caldav.icalendarstore import QuotaExceeded
 from txdav.common.icommondatastore import NoSuchObjectResourceError
+from txdav.common.datastore.sql_tables import _BIND_MODE_READ, _BIND_MODE_WRITE
 from txdav.idav import PropertyChangeNotAllowedError
 
 from twext.web2 import responsecode
@@ -96,8 +97,7 @@
         return PropertyName(namespace, name)
 
 
-    # FIXME 'uid' here should be verifying something.
-    def get(self, qname, uid=None):
+    def get(self, qname):
         try:
             return self._newPropertyStore[self._convertKey(qname)]
         except KeyError:
@@ -107,7 +107,7 @@
             ))
 
 
-    def set(self, property, uid=None):
+    def set(self, property):
         try:
             self._newPropertyStore[self._convertKey(property.qname())] = property
         except PropertyChangeNotAllowedError:
@@ -118,7 +118,7 @@
             
 
 
-    def delete(self, qname, uid=None):
+    def delete(self, qname):
         try:
             del self._newPropertyStore[self._convertKey(qname)]
         except KeyError:
@@ -127,11 +127,11 @@
             pass
 
 
-    def contains(self, qname, uid=None, cache=True):
+    def contains(self, qname):
         return (self._convertKey(qname) in self._newPropertyStore)
 
 
-    def list(self, uid=None, filterByUID=True, cache=True):
+    def list(self):
         return [(pname.namespace, pname.name) for pname in
                 self._newPropertyStore.keys()]
 
@@ -266,15 +266,6 @@
         return self._newStoreObject.retrieveOldIndex()
 
 
-    def invitesDB(self):
-        """
-        Retrieve the new-style invites DB wrapper.
-        """
-        if not hasattr(self, "_invitesDB"):
-            self._invitesDB = self._newStoreObject.retrieveOldInvites()
-        return self._invitesDB
-
-
     def exists(self):
         # FIXME: tests
         return self._newStoreObject is not None
@@ -435,11 +426,11 @@
         @rtype: something adaptable to L{twext.web2.iweb.IResponse}
         """
 
-        # Check virtual share first
-        isVirtual = self.isVirtualShare()
-        if isVirtual:
+        # Check sharee collection first
+        isShareeCollection = self.isShareeCollection()
+        if isShareeCollection:
             log.debug("Removing shared collection %s" % (self,))
-            yield self.removeVirtualShare(request)
+            yield self.removeShareeCollection(request)
             returnValue(NO_CONTENT)
 
         log.debug("Deleting collection %s" % (self,))
@@ -1535,26 +1526,23 @@
     def sharedDropboxACEs(self):
 
         aces = ()
-        records = yield self._newStoreCalendarObject._parentCollection.retrieveOldInvites().allRecords()
-        for record in records:
-            # Invite shares use access mode from the invite
-            if record.state != "ACCEPTED":
-                continue
-            
+        calendars = yield self._newStoreCalendarObject._parentCollection.asShared()
+        for calendar in calendars:
+
             userprivs = [
             ]
-            if record.access in ("read-only", "read-write", "read-write-schedule",):
+            if calendar.shareMode() in (_BIND_MODE_READ, _BIND_MODE_WRITE,):
                 userprivs.append(davxml.Privilege(davxml.Read()))
                 userprivs.append(davxml.Privilege(davxml.ReadACL()))
                 userprivs.append(davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()))
-            if record.access in ("read-only",):
+            if calendar.shareMode() in (_BIND_MODE_READ,):
                 userprivs.append(davxml.Privilege(davxml.WriteProperties()))
-            if record.access in ("read-write", "read-write-schedule",):
+            if calendar.shareMode() in (_BIND_MODE_WRITE,):
                 userprivs.append(davxml.Privilege(davxml.Write()))
             proxyprivs = list(userprivs)
             proxyprivs.remove(davxml.Privilege(davxml.ReadACL()))
 
-            principal = self.principalForUID(record.principalUID)
+            principal = self.principalForUID(calendar._home.uid())
             aces += (
                 # Inheritable specific access for the resource's associated principal.
                 davxml.ACE(
@@ -2207,13 +2195,6 @@
         return self.getChild(segments[0]), segments[1:]
 
 
-    def notificationsDB(self):
-        """
-        Retrieve the new-style index wrapper.
-        """
-        return self._newStoreNotifications.retrieveOldIndex()
-
-
     def exists(self):
         # FIXME: tests
         return True

Modified: CalendarServer/trunk/twistedcaldav/test/test_link.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_link.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/test/test_link.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -22,7 +22,6 @@
 
 from twistedcaldav.linkresource import LinkResource
 from twistedcaldav.resource import CalendarHomeResource
-from twistedcaldav.sharedcollection import SharedCollectionResource
 from twistedcaldav.test.util import TestCase
 
 
@@ -48,6 +47,9 @@
     def __init__(self, link):
         self.hosturl = link
 
+    def url(self):
+        return self.hosturl
+
 class LinkResourceTests(TestCase):
 
     @inlineCallbacks
@@ -92,31 +94,3 @@
             self.assertEqual(e.response.code, responsecode.LOOP_DETECTED)
         else:
             self.fail("HTTPError exception not raised")
-
-class SharedCollectionResourceTests(TestCase):
-
-    @inlineCallbacks
-    def test_okLink(self):
-        resource = StubCalendarHomeResource(self.site.resource, "home", object(), StubHome())
-        self.site.resource.putChild("home", resource)
-        link = SharedCollectionResource(resource, StubShare("/home/outbox/"))
-        resource.putChild("link", link)
-
-        request = SimpleRequest(self.site, "GET", "/home/link/")
-        linked_to, _ignore = (yield resource.locateChild(request, ["link",]))
-        self.assertTrue(linked_to is resource.getChild("outbox"))
-
-    @inlineCallbacks
-    def test_badLink(self):
-        resource = CalendarHomeResource(self.site.resource, "home", object(), StubHome())
-        self.site.resource.putChild("home", resource)
-        link = SharedCollectionResource(resource, StubShare("/home/outbox/abc"))
-        resource.putChild("link", link)
-
-        request = SimpleRequest(self.site, "GET", "/home/link/")
-        try:
-            yield resource.locateChild(request, ["link",])
-        except HTTPError, e:
-            self.assertEqual(e.response.code, responsecode.NOT_FOUND)
-        else:
-            self.fail("HTTPError exception not raised")

Modified: CalendarServer/trunk/twistedcaldav/test/test_resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_resource.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/test/test_resource.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -331,8 +331,8 @@
         else:
             self.assertEqual(str(default.children[0]), "/addressbooks/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newadbk/")
         
-        # Force the new calendar to think it is a virtual share
-        newadbk._isVirtualShare = True
+        # Force the new calendar to think it is a sharee collection
+        newadbk._isShareeCollection = True
         
         try:
             default = yield home.readProperty(carddavxml.DefaultAddressBookURL, request)

Modified: CalendarServer/trunk/twistedcaldav/test/test_schedule.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_schedule.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/test/test_schedule.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -372,8 +372,8 @@
         else:
             self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newcalendar")
         
-        # Force the new calendar to think it is a virtual share
-        newcalendar._isVirtualShare = True
+        # Force the new calendar to think it is a sharee collection
+        newcalendar._isShareeCollection = True
         
         try:
             default = yield inbox.readProperty(caldavxml.ScheduleDefaultCalendarURL, request)

Modified: CalendarServer/trunk/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_sharing.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/test/test_sharing.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -25,7 +25,7 @@
 from twistedcaldav import customxml
 from twistedcaldav.config import config
 from twistedcaldav.test.util import HomeTestCase, norequest
-from twistedcaldav.sharing import SharedCollectionMixin, SHARETYPE_DIRECT, WikiDirectoryService
+from twistedcaldav.sharing import SharedCollectionMixin, WikiDirectoryService
 
 from twistedcaldav.resource import CalDAVResource
 from txdav.common.datastore.test.util import buildStore, StubNotifierFactory
@@ -47,11 +47,19 @@
                 self.calendarUserAddresses = set((cuaddr,))
 
         def __init__(self, cuaddr):
-            self.path = "/principals/__uids__/%s" % (cuaddr[7:].split('@')[0],)
-            self.homepath = "/calendars/__uids__/%s" % (cuaddr[7:].split('@')[0],)
-            self.displayname = cuaddr[7:].split('@')[0].upper()
-            self.record = self.FakeRecord(cuaddr[7:].split('@')[0], cuaddr)
+            if cuaddr.startswith("mailto:"):
+                name = cuaddr[7:].split('@')[0]
+            elif cuaddr.startswith("urn:uuid:"):
+                name = cuaddr[9:]
+            else:
+                name = cuaddr
 
+            self.path = "/principals/__uids__/%s" % (name,)
+            self.homepath = "/calendars/__uids__/%s" % (name,)
+            self.displayname = name.upper()
+            self.record = self.FakeRecord(name, cuaddr)
+
+
         def calendarHome(self, request):
             class FakeHome(object):
                 def removeShareByUID(self, request, uid):
@@ -61,24 +69,31 @@
         def principalURL(self):
             return self.path
 
+        def principalUID(self):
+            return self.record.guid
+
         def displayName(self):
             return self.displayname
 
 
     @inlineCallbacks
     def setUp(self):
+        self.calendarStore = yield buildStore(self, StubNotifierFactory())
+
         yield super(SharingTests, self).setUp()
 
         self.patch(config.Sharing, "Enabled", True)
         self.patch(config.Sharing.Calendars, "Enabled", True)
 
-        CalDAVResource.validUserIDForShare = self._fakeValidUserID
-        CalDAVResource.validUserIDWithCommonNameForShare = self._fakeValidUserID_CN
-        CalDAVResource.sendInvite = lambda self, record, request: succeed(True)
-        CalDAVResource.removeInvite = lambda self, record, request: succeed(True)
+        CalDAVResource.sendInviteNotification = lambda self, record, request: succeed(True)
+        CalDAVResource.removeInviteNotification = lambda self, record, request: succeed(True)
 
-        self.patch(CalDAVResource, "principalForCalendarUserAddress", lambda self, cuaddr: SharingTests.FakePrincipal(cuaddr))
+        self.patch(CalDAVResource, "validUserIDForShare", lambda self, userid, request: None if "bogus" in userid else SharingTests.FakePrincipal(userid).principalURL())
+        self.patch(CalDAVResource, "principalForCalendarUserAddress", lambda self, cuaddr: None if "bogus" in cuaddr else SharingTests.FakePrincipal(cuaddr))
+        self.patch(CalDAVResource, "principalForUID", lambda self, principalUID: SharingTests.FakePrincipal("urn:uuid:" + principalUID))
 
+    def createDataStore(self):
+        return self.calendarStore
 
     @inlineCallbacks
     def _refreshRoot(self, request=None):
@@ -91,36 +106,6 @@
         returnValue(result)
 
 
-    def _fakeValidUserID_Base(self, userid, request, *args):
-        if userid.startswith("/principals/"):
-            return userid
-        if userid.endswith("@example.com"):
-            principal = SharingTests.FakePrincipal(userid)
-            return principal.path if len(args) == 0 else (userid, principal.path, principal.displayname,)
-        else:
-            return None if len(args) == 0 else (None, None, None,)
-
-
-    def _fakeValidUserID(self, userid, request, *args):
-        return succeed(self._fakeValidUserID_Base(userid, request, *args))
-
-
-    def _fakeValidUserID_CN(self, userid, *args):
-        return self._fakeValidUserID_Base(userid, None, *args)
-
-
-    def _fakeInvalidUserID_Base(self, userid, request, *args):
-        return None if len(args) == 0 else (None, None, None,)
-
-
-    def _fakeInvalidUserID(self, userid, request, *args):
-        return succeed(self._fakeInvalidUserID_Base(userid, request, *args))
-
-
-    def _fakeInvalidUserID_CN(self, userid, *args):
-        return self._fakeInvalidUserID_Base(userid, None, *args)
-
-
     @inlineCallbacks
     def _doPOST(self, body, resultcode=responsecode.OK):
         request = SimpleRequest(self.site, "POST", "/calendar/")
@@ -148,8 +133,8 @@
         self.assertEquals(rtype, regularCalendarType)
         isShared = (yield self.resource.isShared(None))
         self.assertFalse(isShared)
-        isVShared = self.resource.isVirtualShare()
-        self.assertFalse(isVShared)
+        isShareeCollection = self.resource.isShareeCollection()
+        self.assertFalse(isShareeCollection)
 
         self.resource.upgradeToShare()
 
@@ -157,8 +142,8 @@
         self.assertEquals(rtype, sharedOwnerType)
         isShared = (yield self.resource.isShared(None))
         self.assertTrue(isShared)
-        isVShared = self.resource.isVirtualShare()
-        self.assertFalse(isVShared)
+        isShareeCollection = self.resource.isShareeCollection()
+        self.assertFalse(isShareeCollection)
 
 
     @inlineCallbacks
@@ -170,8 +155,8 @@
         self.assertEquals(rtype, sharedOwnerType)
         isShared = (yield self.resource.isShared(None))
         self.assertTrue(isShared)
-        isVShared = self.resource.isVirtualShare()
-        self.assertFalse(isVShared)
+        isShareeCollection = self.resource.isShareeCollection()
+        self.assertFalse(isShareeCollection)
 
         yield self.resource.downgradeFromShare(None)
 
@@ -179,8 +164,8 @@
         self.assertEquals(rtype, regularCalendarType)
         isShared = (yield self.resource.isShared(None))
         self.assertFalse(isShared)
-        isVShared = self.resource.isVirtualShare()
-        self.assertFalse(isVShared)
+        isShareeCollection = self.resource.isShareeCollection()
+        self.assertFalse(isShareeCollection)
 
 
     @inlineCallbacks
@@ -202,7 +187,7 @@
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user02 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user02"),
                 customxml.CommonName.fromString("USER02"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusNoResponse(),
@@ -211,8 +196,8 @@
 
         isShared = (yield self.resource.isShared(None))
         self.assertTrue(isShared)
-        isVShared = self.resource.isVirtualShare()
-        self.assertFalse(isVShared)
+        isShareeCollection = self.resource.isShareeCollection()
+        self.assertFalse(isShareeCollection)
 
 
     @inlineCallbacks
@@ -233,7 +218,7 @@
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user02 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user02"),
                 customxml.CommonName.fromString("USER02"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusNoResponse(),
@@ -242,8 +227,8 @@
 
         isShared = (yield self.resource.isShared(None))
         self.assertTrue(isShared)
-        isVShared = (yield self.resource.isVirtualShare())
-        self.assertFalse(isVShared)
+        isShareeCollection = (yield self.resource.isShareeCollection())
+        self.assertFalse(isShareeCollection)
 
 
     @inlineCallbacks
@@ -282,7 +267,7 @@
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user02 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user02"),
                 customxml.CommonName.fromString("USER02"),
                 customxml.InviteAccess(customxml.ReadAccess()),
                 customxml.InviteStatusNoResponse(),
@@ -357,21 +342,21 @@
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user02 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user02"),
                 customxml.CommonName.fromString("USER02"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusNoResponse(),
             ),
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user03 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user03"),
                 customxml.CommonName.fromString("USER03"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusNoResponse(),
             ),
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user04 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user04"),
                 customxml.CommonName.fromString("USER04"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusNoResponse(),
@@ -415,21 +400,20 @@
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user02 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user02"),
                 customxml.CommonName.fromString("USER02"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusNoResponse(),
             ),
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user04 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user04"),
                 customxml.CommonName.fromString("USER04"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusNoResponse(),
             ),
         ))
 
-
     @inlineCallbacks
     def test_POSTaddRemoveSameInvitee(self):
 
@@ -466,14 +450,14 @@
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user02 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user02"),
                 customxml.CommonName.fromString("USER02"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusNoResponse(),
             ),
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user03 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user03"),
                 customxml.CommonName.fromString("USER03"),
                 customxml.InviteAccess(customxml.ReadAccess()),
                 customxml.InviteStatusNoResponse(),
@@ -576,23 +560,23 @@
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user01 at example.com"),
+                davxml.HRef.fromString("urn:uuid:user01"),
                 customxml.CommonName.fromString("USER01"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusNoResponse(),
             )
         ))
 
-        self.resource.validUserIDForShare = self._fakeInvalidUserID
-        self.resource.validUserIDWithCommonNameForShare = self._fakeInvalidUserID_CN
+        self.resource.validUserIDForShare = lambda userid, request: None
         self.resource.principalForCalendarUserAddress = lambda cuaddr: None
+        self.resource.principalForUID = lambda principalUID: None
 
         propInvite = (yield self.resource.readProperty(customxml.Invite, None))
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
             customxml.InviteUser(
                 customxml.UID.fromString(""),
-                davxml.HRef.fromString("mailto:user01 at example.com"),
-                customxml.CommonName.fromString("USER01"),
+                davxml.HRef.fromString("urn:uuid:user01"),
+                customxml.CommonName.fromString("user01"),
                 customxml.InviteAccess(customxml.ReadWriteAccess()),
                 customxml.InviteStatusInvalid(),
             )
@@ -625,18 +609,28 @@
 
         class StubCollection(object):
             def __init__(self):
-                self._isVirtualShare = True
+                self._isShareeCollection = True
                 self._shareePrincipal = StubUserPrincipal()
             def isCalendarCollection(self):
                 return True
 
         class StubShare(object):
-            def __init__(self):
-                self.sharetype = SHARETYPE_DIRECT
-                self.hosturl = "/wikifoo"
+            def direct(self):
+                return True
 
+            def url(self):
+                return "/wikifoo"
+
+            def uid(self):
+                return "012345"
+
+            def shareeUID(self):
+                return StubUserPrincipal().record.guid
+
         class TestCollection(SharedCollectionMixin, StubCollection):
-            pass
+            def principalForUID(self, uid):
+                principal = StubUserPrincipal()
+                return principal if principal.record.guid == uid else None
 
         class StubRecord(object):
             def __init__(self, recordType, name, guid):
@@ -693,7 +687,7 @@
         self.assertTrue("<write/>" in acl.toxml())
 
 
-
+'''
 class DatabaseSharingTests(SharingTests):
 
     @inlineCallbacks
@@ -704,3 +698,5 @@
 
     def createDataStore(self):
         return self.calendarStore
+
+'''

Modified: CalendarServer/trunk/twistedcaldav/test/test_wrapping.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_wrapping.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/twistedcaldav/test/test_wrapping.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -53,6 +53,7 @@
 from twistedcaldav.directory.test.test_xmlfile import XMLFileBase
 from txdav.caldav.icalendarstore import ICalendarHome
 from txdav.carddav.iaddressbookstore import IAddressBookHome
+from txdav.caldav.datastore.file import Calendar
 
 
 
@@ -399,6 +400,8 @@
         Exceeding quota on an attachment returns an HTTP error code.
         """
         self.patch(config, "EnableDropBox", True)
+        self.patch(Calendar, "asShared", lambda self: [])
+
         yield self.populateOneObject("1.ics", test_event_text)
         calendarObject = yield self.getResource(
             "/calendars/users/wsanchez/dropbox/uid-test.dropbox/too-big-attachment",

Modified: CalendarServer/trunk/txdav/base/propertystore/base.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/base.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/base/propertystore/base.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -109,16 +109,22 @@
         PropertyName.fromElement(TwistedQuotaRootProperty),
     ))
 
-    def __init__(self, defaultUser):
+    def __init__(self, defaultUser, shareeUser=None):
         """
         Instantiate the property store for a user. The default is the default user
         (owner) property to read in the case of global or shadowable properties.
+        The sharee user is a user sharing the user to read for per-user properties.
 
-        @param defaultuser: the default user uid
-        @type defaultuser: C{str}
+        @param defaultUser: the default user uid
+        @type defaultUser: C{str}
+
+        @param shareeUser: the per user uid or None if the same as defaultUser
+        @type shareeUser: C{str}
         """
         
-        self._perUser = self._defaultUser = defaultUser
+        assert(defaultUser is not None or shareeUser is not None)
+        self._defaultUser = shareeUser if defaultUser is None else defaultUser
+        self._perUser = defaultUser if shareeUser is None else shareeUser
         self._shadowableKeys = set(AbstractPropertyStore._defaultShadowableKeys)
         self._globalKeys = set(AbstractPropertyStore._defaultGlobalKeys)
 

Modified: CalendarServer/trunk/txdav/base/propertystore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/sql.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/base/propertystore/sql.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -73,13 +73,13 @@
 
     @classmethod
     @inlineCallbacks
-    def load(cls, defaultuser, txn, resourceID, created=False, notifyCallback=None):
+    def load(cls, defaultuser, shareUser, txn, resourceID, created=False, notifyCallback=None):
         """
         @param notifyCallback: a callable used to trigger notifications when the
             property store changes.
         """
         self = cls.__new__(cls)
-        super(PropertyStore, self).__init__(defaultuser)
+        super(PropertyStore, self).__init__(defaultuser, shareUser)
         self._txn = txn
         self._resourceID = resourceID
         self._cached = {}

Modified: CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -48,10 +48,9 @@
         self.addCleanup(self.maybeCommitLast)
         self._txn = self.store.newTransaction()
         self.propertyStore = self.propertyStore1 = yield PropertyStore.load(
-            "user01", self._txn, 1
+            "user01", None, self._txn, 1
         )
-        self.propertyStore2 = yield PropertyStore.load("user01", self._txn, 1)
-        self.propertyStore2._setPerUserUID("user02")
+        self.propertyStore2 = yield PropertyStore.load("user01", "user02", self._txn, 1)
 
 
     @inlineCallbacks
@@ -74,14 +73,13 @@
 
         store = self.propertyStore1
         self.propertyStore = self.propertyStore1 = yield PropertyStore.load(
-            "user01", self._txn, 1
+            "user01", None, self._txn, 1
         )
         self.propertyStore1._shadowableKeys = store._shadowableKeys
         self.propertyStore1._globalKeys = store._globalKeys
 
         store = self.propertyStore2
-        self.propertyStore2 = yield PropertyStore.load("user01", self._txn, 1)
-        self.propertyStore2._setPerUserUID("user02")
+        self.propertyStore2 = yield PropertyStore.load("user01", "user02", self._txn, 1)
         self.propertyStore2._shadowableKeys = store._shadowableKeys
         self.propertyStore2._globalKeys = store._globalKeys
 
@@ -96,14 +94,13 @@
 
         store = self.propertyStore1
         self.propertyStore = self.propertyStore1 = yield PropertyStore.load(
-            "user01", self._txn, 1
+            "user01", None, self._txn, 1
         )
         self.propertyStore1._shadowableKeys = store._shadowableKeys
         self.propertyStore1._globalKeys = store._globalKeys
 
         store = self.propertyStore2
-        self.propertyStore2 = yield PropertyStore.load("user01", self._txn, 1)
-        self.propertyStore2._setPerUserUID("user02")
+        self.propertyStore2 = yield PropertyStore.load("user01", "user02", self._txn, 1)
         self.propertyStore2._shadowableKeys = store._shadowableKeys
         self.propertyStore2._globalKeys = store._globalKeys
 
@@ -127,7 +124,7 @@
                 pass
         self.addCleanup(maybeAbortIt)
         concurrentPropertyStore = yield PropertyStore.load(
-            "user01", concurrentTxn, 1
+            "user01", None, concurrentTxn, 1
         )
         concurrentPropertyStore[pname] = pval1
         race = []
@@ -155,9 +152,8 @@
     def test_copy(self):
 
         # Existing store
-        store1_user1 = yield PropertyStore.load("user01", self._txn, 2)
-        store1_user2 = yield PropertyStore.load("user01", self._txn, 2)
-        store1_user2._setPerUserUID("user02")
+        store1_user1 = yield PropertyStore.load("user01", None, self._txn, 2)
+        store1_user2 = yield PropertyStore.load("user01", "user02", self._txn, 2)
 
         # Populate current store with data
         props_user1 = (
@@ -179,20 +175,18 @@
         self._txn = self.store.newTransaction()
 
         # Existing store
-        store1_user1 = yield PropertyStore.load("user01", self._txn, 2)
+        store1_user1 = yield PropertyStore.load("user01", None, self._txn, 2)
 
         # New store
-        store2_user1 = yield PropertyStore.load("user01", self._txn, 3)
+        store2_user1 = yield PropertyStore.load("user01", None, self._txn, 3)
 
         # Do copy and check results
         yield store2_user1.copyAllProperties(store1_user1)
         
         self.assertEqual(store1_user1.keys(), store2_user1.keys())
 
-        store1_user2 = yield PropertyStore.load("user01", self._txn, 2)
-        store1_user2._setPerUserUID("user02")
-        store2_user2 = yield PropertyStore.load("user01", self._txn, 3)
-        store2_user2._setPerUserUID("user02")
+        store1_user2 = yield PropertyStore.load("user01", "user02", self._txn, 2)
+        store2_user2 = yield PropertyStore.load("user01", "user02", self._txn, 3)
         self.assertEqual(store1_user2.keys(), store2_user2.keys())
 
 

Modified: CalendarServer/trunk/txdav/caldav/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/file.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/caldav/datastore/file.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -148,7 +148,7 @@
         results = []
         objectResources = (yield self.objectResourcesWithUID(uid, ("inbox",)))
         for objectResource in objectResources:
-            if allow_shared or objectResource._parentCollection._owned:
+            if allow_shared or objectResource._parentCollection.owned():
                 results.append(objectResource)
             
         returnValue(results)

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -52,9 +52,8 @@
     IAttachment
 from txdav.common.datastore.sql import CommonHome, CommonHomeChild,\
     CommonObjectResource, ECALENDARTYPE
-from txdav.common.datastore.sql_legacy import \
-    PostgresLegacyIndexEmulator, SQLLegacyCalendarInvites,\
-    SQLLegacyCalendarShares, PostgresLegacyInboxIndexEmulator
+from txdav.common.datastore.sql_legacy import PostgresLegacyIndexEmulator,\
+    PostgresLegacyInboxIndexEmulator
 from txdav.common.datastore.sql_tables import CALENDAR_TABLE,\
     CALENDAR_BIND_TABLE, CALENDAR_OBJECT_REVISIONS_TABLE, CALENDAR_OBJECT_TABLE,\
     _ATTACHMENTS_MODE_NONE, _ATTACHMENTS_MODE_READ, _ATTACHMENTS_MODE_WRITE,\
@@ -115,7 +114,6 @@
 
         self._childClass = Calendar
         super(CalendarHome, self).__init__(transaction, ownerUID, notifiers)
-        self._shares = SQLLegacyCalendarShares(self)
 
 
     createCalendarWithName = CommonHome.createChildWithName
@@ -226,7 +224,7 @@
         results = []
         objectResources = (yield self.objectResourcesWithUID(uid, ["inbox"]))
         for objectResource in objectResources:
-            if allow_shared or objectResource._parentCollection._owned:
+            if allow_shared or objectResource._parentCollection.owned():
                 results.append(objectResource)
 
         returnValue(results)
@@ -397,6 +395,7 @@
     implements(ICalendar)
 
     # structured tables.  (new, preferred)
+    _homeSchema = schema.CALENDAR_HOME
     _bindSchema = schema.CALENDAR_BIND
     _homeChildSchema = schema.CALENDAR
     _homeChildMetaDataSchema = schema.CALENDAR_METADATA
@@ -423,7 +422,6 @@
             self._index = PostgresLegacyInboxIndexEmulator(self)
         else:
             self._index = PostgresLegacyIndexEmulator(self)
-        self._invites = SQLLegacyCalendarInvites(self)
 
 
     @classmethod

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/common.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -995,7 +995,7 @@
         yield self.commit()
         normalCal = yield self.calendarUnderTest()
         otherHome = yield self.homeUnderTest(name=OTHER_HOME_UID)
-        otherCal = yield otherHome.sharedChildWithName(newCalName)
+        otherCal = yield otherHome.childWithName(newCalName)
         self.assertNotIdentical(otherCal, None)
         self.assertEqual(
             (yield
@@ -1003,13 +1003,6 @@
             (yield
              (yield normalCal.calendarObjectWithName("1.ics")).component())
         )
-        # Check legacy shares database too, since that's what the protocol layer
-        # is still using to list things.
-        self.assertEqual(
-            [(record.shareuid, record.localname) for record in
-             (yield otherHome.retrieveOldShares().allRecords())],
-            [(newCalName, newCalName)]
-        )
 
 
     @inlineCallbacks
@@ -1023,17 +1016,15 @@
         cal = yield self.calendarUnderTest()
         other = yield self.homeUnderTest(name=OTHER_HOME_UID)
         newName = yield cal.shareWith(other, _BIND_MODE_READ)
-        otherCal = yield other.sharedChildWithName(self.sharedName)
+        otherCal = yield other.childWithName(self.sharedName)
 
         # Name should not change just because we updated the mode.
         self.assertEqual(newName, self.sharedName)
         self.assertNotIdentical(otherCal, None)
 
-        # FIXME: permission information should be visible on the retrieved
-        # calendar object, we shoudln't need to go via the legacy API.
-        invites = yield cal.retrieveOldInvites().allRecords()
-        self.assertEqual(len(invites), 1)
-        self.assertEqual(invites[0].access, "read-only")
+        invitedCals = yield cal.asShared()
+        self.assertEqual(len(invitedCals), 1)
+        self.assertEqual(invitedCals[0].shareMode(), _BIND_MODE_READ)
 
 
     @inlineCallbacks
@@ -1048,12 +1039,10 @@
         cal = yield self.calendarUnderTest()
         other = yield self.homeUnderTest(name=OTHER_HOME_UID)
         newName = yield cal.unshareWith(other)
-        otherCal = yield other.sharedChildWithName(newName)
+        otherCal = yield other.childWithName(newName)
         self.assertIdentical(otherCal, None)
-        invites = yield cal.retrieveOldInvites().allRecords()
-        self.assertEqual(len(invites), 0)
-        shares = yield other.retrieveOldShares().allRecords()
-        self.assertEqual(len(shares), 0)
+        invitedCals = yield cal.asShared()
+        self.assertEqual(len(invitedCals), 0)
 
     @inlineCallbacks
     def test_unshareSharerSide(self, commit=False):
@@ -1066,15 +1055,13 @@
             yield self.commit()
         cal = yield self.calendarUnderTest()
         other = yield self.homeUnderTest(name=OTHER_HOME_UID)
-        otherCal = yield other.sharedChildWithName(self.sharedName)
+        otherCal = yield other.childWithName(self.sharedName)
         self.assertNotEqual(otherCal, None)
         yield cal.unshare()
-        otherCal = yield other.sharedChildWithName(self.sharedName)
+        otherCal = yield other.childWithName(self.sharedName)
         self.assertEqual(otherCal, None)
-        invites = yield cal.retrieveOldInvites().allRecords()
-        self.assertEqual(len(invites), 0)
-        shares = yield other.retrieveOldShares().allRecords()
-        self.assertEqual(len(shares), 0)
+        invitedCals = yield cal.asShared()
+        self.assertEqual(len(invitedCals), 0)
 
     @inlineCallbacks
     def test_unshareShareeSide(self, commit=False):
@@ -1087,15 +1074,13 @@
             yield self.commit()
         cal = yield self.calendarUnderTest()
         other = yield self.homeUnderTest(name=OTHER_HOME_UID)
-        otherCal = yield other.sharedChildWithName(self.sharedName)
+        otherCal = yield other.childWithName(self.sharedName)
         self.assertNotEqual(otherCal, None)
         yield otherCal.unshare()
-        otherCal = yield other.sharedChildWithName(self.sharedName)
+        otherCal = yield other.childWithName(self.sharedName)
         self.assertEqual(otherCal, None)
-        invites = yield cal.retrieveOldInvites().allRecords()
-        self.assertEqual(len(invites), 0)
-        shares = yield other.retrieveOldShares().allRecords()
-        self.assertEqual(len(shares), 0)
+        invitedCals = yield cal.asShared()
+        self.assertEqual(len(invitedCals), 0)
 
     @inlineCallbacks
     def test_unshareWithInDifferentTransaction(self):
@@ -1145,6 +1130,9 @@
 
         result = (yield home.hasCalendarResourceUIDSomewhereElse("uid2", object, "schedule"))
         self.assertTrue(result)
+        
+        # FIXME:  do this without legacy calls
+        '''
         from twistedcaldav.sharing import SharedCollectionRecord
         scr = SharedCollectionRecord(
             shareuid="opaque", sharetype="D", summary="ignored",
@@ -1157,6 +1145,8 @@
             "uid2-5", object, "schedule"
         ))
         self.assertFalse(result)
+        '''
+        yield None
 
 
     @inlineCallbacks

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -47,7 +47,6 @@
 from twistedcaldav.dateops import datetimeMktime
 from twistedcaldav.ical import Component
 from twistedcaldav.query import calendarqueryfilter
-from twistedcaldav.sharing import SharedCollectionRecord
 
 import datetime
 from pycalendar.datetime import PyCalendarDateTime
@@ -916,38 +915,40 @@
 
         # Provision the home and calendar now
         txn = calendarStore.newTransaction()
-        home = yield txn.homeWithUID(ECALENDARTYPE, "uid1", create=True)
-        self.assertNotEqual(home, None)
-        cal = yield home.calendarWithName("calendar")
+        sharerHome = yield txn.homeWithUID(ECALENDARTYPE, "uid1", create=True)
+        self.assertNotEqual(sharerHome, None)
+        cal = yield sharerHome.calendarWithName("calendar")
         self.assertNotEqual(cal, None)
+        shareeHome = yield txn.homeWithUID(ECALENDARTYPE, "uid2", create=True)
+        self.assertNotEqual(shareeHome, None)
         yield txn.commit()
 
         txn1 = calendarStore.newTransaction()
         txn2 = calendarStore.newTransaction()
 
-        home1 = yield txn1.homeWithUID(ECALENDARTYPE, "uid1", create=True)
-        home2 = yield txn2.homeWithUID(ECALENDARTYPE, "uid1", create=True)
+        sharerHome1 = yield txn1.homeWithUID(ECALENDARTYPE, "uid1", create=True)
+        self.assertNotEqual(sharerHome1, None)
+        cal1 = yield sharerHome1.calendarWithName("calendar")
+        self.assertNotEqual(cal1, None)
+        shareeHome1 = yield txn1.homeWithUID(ECALENDARTYPE, "uid2", create=True)
+        self.assertNotEqual(shareeHome1, None)
 
-        shares1 = yield home1.retrieveOldShares()
-        shares2 = yield home2.retrieveOldShares()
+        sharerHome2 = yield txn2.homeWithUID(ECALENDARTYPE, "uid1", create=True)
+        self.assertNotEqual(sharerHome2, None)
+        cal2 = yield sharerHome2.calendarWithName("calendar")
+        self.assertNotEqual(cal2, None)
+        shareeHome2 = yield txn1.homeWithUID(ECALENDARTYPE, "uid2", create=True)
+        self.assertNotEqual(shareeHome2, None)
 
-        record = SharedCollectionRecord(
-            "abcd",
-            "D",
-            "/calendars/__uids__/uid2/calendar/",
-            "XYZ",
-            "Shared Wiki Calendar",
-        )
-
         @inlineCallbacks
         def _defer1():
-            yield shares1.addOrUpdateRecord(record)
+            yield cal1.shareWith(shareeHome=sharerHome1, mode=_BIND_MODE_DIRECT, status=_BIND_STATUS_ACCEPTED, message="Shared Wiki Calendar")
             yield txn1.commit()
         d1 = _defer1()
 
         @inlineCallbacks
         def _defer2():
-            yield shares2.addOrUpdateRecord(record)
+            yield cal2.shareWith(shareeHome=sharerHome2, mode=_BIND_MODE_DIRECT, status=_BIND_STATUS_ACCEPTED, message="Shared Wiki Calendar")
             yield txn2.commit()
         d2 = _defer2()
 
@@ -978,9 +979,9 @@
             bind.SEEN_BY_SHAREE: True,
         })
         yield _bindCreate.on(self.transactionUnderTest())
-        sharedCalendar = yield shareeHome.sharedChildWithName("shared_1")
+        sharedCalendar = yield shareeHome.childWithName("shared_1")
         self.assertTrue(sharedCalendar is not None)
-        sharedCalendar = yield shareeHome.sharedChildWithName("shared_1_vtodo")
+        sharedCalendar = yield shareeHome.childWithName("shared_1_vtodo")
         self.assertTrue(sharedCalendar is None)
 
         # Now do the transfer and see if a new binding exists
@@ -988,11 +989,11 @@
             "home_splits")).createCalendarWithName("calendar_new")
         yield calendar._transferSharingDetails(newcalendar, "VTODO")
 
-        sharedCalendar = yield shareeHome.sharedChildWithName("shared_1")
+        sharedCalendar = yield shareeHome.childWithName("shared_1")
         self.assertTrue(sharedCalendar is not None)
         self.assertEqual(sharedCalendar._resourceID, calendar._resourceID)
 
-        sharedCalendar = yield shareeHome.sharedChildWithName("shared_1-vtodo")
+        sharedCalendar = yield shareeHome.childWithName("shared_1-vtodo")
         self.assertTrue(sharedCalendar is not None)
         self.assertEqual(sharedCalendar._resourceID, newcalendar._resourceID)
 

Modified: CalendarServer/trunk/txdav/caldav/datastore/util.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/util.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/caldav/datastore/util.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -405,7 +405,7 @@
         """
         component = yield self.component()
         calendar = self.calendar()
-        isOwner = asAdmin or (calendar._owned and
+        isOwner = asAdmin or (calendar.owned() and
                               calendar.ownerCalendarHome().uid() == accessUID)
         for data_filter in [
             PerUserDataFilter(accessUID),

Modified: CalendarServer/trunk/txdav/caldav/icalendarstore.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/icalendarstore.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/caldav/icalendarstore.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -408,7 +408,7 @@
         C{txn.calendarHomeWithUID("alice") ...
         .calendarWithName("calendar").viewerCalendarHome()} will return Alice's
         home, whereas C{txn.calendarHomeWithUID("bob") ...
-        .sharedChildWithName("alice's calendar").viewerCalendarHome()} will
+        .childWithName("alice's calendar").viewerCalendarHome()} will
         return Bob's calendar home.
 
         @return: (synchronously) the calendar home of the user into which this
@@ -417,12 +417,6 @@
         """
         # TODO: implement this for the file store.
 
-        # TODO: implement home-child- retrieval APIs to retrieve shared items
-        # from the store; the example in the docstring ought to be
-        # calendarWithName not sharedChildWithName.
-
-
-
 class ICalendarObject(IDataStoreObject):
     """
     Calendar object

Modified: CalendarServer/trunk/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/sql.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/carddav/datastore/sql.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -38,9 +38,7 @@
 from twistedcaldav.memcacher import Memcacher
 from twistedcaldav.vcard import Component as VCard, InvalidVCardDataError
 
-from txdav.common.datastore.sql_legacy import \
-    PostgresLegacyABIndexEmulator, SQLLegacyAddressBookInvites,\
-    SQLLegacyAddressBookShares
+from txdav.common.datastore.sql_legacy import PostgresLegacyABIndexEmulator
 
 from txdav.carddav.datastore.util import validateAddressBookComponent
 from txdav.carddav.iaddressbookstore import IAddressBookHome, IAddressBook,\
@@ -91,7 +89,6 @@
 
         self._childClass = AddressBook
         super(AddressBookHome, self).__init__(transaction, ownerUID, notifiers)
-        self._shares = SQLLegacyAddressBookShares(self)
 
 
     addressbooks = CommonHome.children
@@ -148,6 +145,7 @@
     implements(IAddressBook)
 
     # structured tables.  (new, preferred)
+    _homeSchema = schema.ADDRESSBOOK_HOME
     _bindSchema = schema.ADDRESSBOOK_BIND
     _homeChildSchema = schema.ADDRESSBOOK
     _homeChildMetaDataSchema = schema.ADDRESSBOOK_METADATA
@@ -165,9 +163,8 @@
     def __init__(self, *args, **kw):
         super(AddressBook, self).__init__(*args, **kw)
         self._index = PostgresLegacyABIndexEmulator(self)
-        self._invites = SQLLegacyAddressBookInvites(self)
+        
 
-
     @property
     def _addressbookHome(self):
         return self._home

Modified: CalendarServer/trunk/txdav/common/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/file.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/common/datastore/file.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -721,6 +721,8 @@
         """
         return BIND_OWN
 
+    def owned(self):
+        return self._owned
 
     _renamedName = None
 

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -49,14 +49,14 @@
 
 from twext.internet.decorate import memoizedKey
 
-from txdav.common.datastore.sql_legacy import PostgresLegacyNotificationsEmulator
 from txdav.caldav.icalendarstore import ICalendarTransaction, ICalendarStore
 
 from txdav.carddav.iaddressbookstore import IAddressBookTransaction
 
 from txdav.common.datastore.sql_tables import schema
 from txdav.common.datastore.sql_tables import _BIND_MODE_OWN, \
-    _BIND_STATUS_ACCEPTED, NOTIFICATION_OBJECT_REVISIONS_TABLE
+    _BIND_STATUS_ACCEPTED, _BIND_STATUS_DECLINED, \
+    NOTIFICATION_OBJECT_REVISIONS_TABLE
 from txdav.common.icommondatastore import HomeChildNameNotAllowedError, \
     HomeChildNameAlreadyExistsError, NoSuchHomeChildError, \
     ObjectResourceNameNotAllowedError, ObjectResourceNameAlreadyExistsError, \
@@ -82,7 +82,6 @@
 from twistedcaldav.customxml import NotificationType
 from twistedcaldav.dateops import datetimeMktime, parseSQLTimestamp,\
     pyCalendarTodatetime
-from txdav.xml.rfc2518 import DisplayName
 
 from txdav.base.datastore.util import normalizeUUIDOrNot
 from twext.enterprise.queue import NullQueuer
@@ -770,7 +769,6 @@
             a = ("-- Label: %s\n" % (self._label.replace("%", "%%"),) + a[0],) + a[1:]
         if self._store.logSQL:
             log.error("SQL: %r %r" % (a, kw,))
-        results = ()
         try:
             results = (yield self._sqlTxn.execSQL(*a, **kw))
         finally:
@@ -981,10 +979,8 @@
         self._txn = transaction
         self._ownerUID = ownerUID
         self._resourceID = None
-        self._shares = None
         self._childrenLoaded = False
         self._children = {}
-        self._sharedChildren = {}
         self._notifiers = notifiers
         self._quotaUsedBytes = None
         self._created = None
@@ -1022,7 +1018,7 @@
                       From=home, Where=home.OWNER_UID == Parameter("ownerUID"))
 
     @classproperty
-    def _ownerFromFromResourceID(cls): #@NoSelf
+    def _ownerFromResourceID(cls): #@NoSelf
         home = cls._homeSchema
         return Select([home.OWNER_UID],
                       From=home,
@@ -1133,7 +1129,7 @@
     @classmethod
     @inlineCallbacks
     def homeUIDWithResourceID(cls, txn, rid):
-        rows = (yield cls._ownerFromFromResourceID.on(txn, resourceID=rid))
+        rows = (yield cls._ownerFromResourceID.on(txn, resourceID=rid))
         if rows:
             returnValue(rows[0][0])
         else:
@@ -1157,10 +1153,6 @@
         return self._txn
 
 
-    def retrieveOldShares(self):
-        return self._shares
-
-
     def name(self):
         """
         Implement L{IDataStoreObject.name} to return the uid.
@@ -1185,16 +1177,12 @@
         """
         Load and cache all children - Depth:1 optimization
         """
-        results1 = (yield self._childClass.loadAllObjects(self, owned=True))
-        for result in results1:
+        results = (yield self._childClass.loadAllObjects(self))
+        for result in results:
             self._children[result.name()] = result
-        results2 = (yield self._childClass.loadAllObjects(self, owned=False))
-        for result in results2:
-            self._sharedChildren[result.name()] = result
         self._childrenLoaded = True
-        returnValue(results1 + results2)
+        returnValue(results)
 
-
     def listChildren(self):
         """
         Retrieve the names of the children in this home.
@@ -1205,19 +1193,16 @@
         if self._childrenLoaded:
             return succeed(self._children.keys())
         else:
-            return self._childClass.listObjects(self, owned=True)
+            return self._childClass.listObjects(self)
 
 
-    def listSharedChildren(self):
+    def listInvitedChildren(self):
         """
-        Retrieve the names of the children in this home.
+        Retrieve the names of the invited children in this home.
 
         @return: an iterable of C{str}s.
         """ 
-        if self._childrenLoaded:
-            return succeed(self._sharedChildren.keys())
-        else:
-            return self._childClass.listObjects(self, owned=False)
+        return self._childClass.listInvitedObjects(self)
 
 
     @memoizedKey("name", "_children")
@@ -1229,7 +1214,7 @@
         @param name: a string.
         @return: an L{ICalendar} or C{None} if no such child exists.
         """
-        return self._childClass.objectWithName(self, name, owned=True)
+        return self._childClass.objectWithName(self, name)
 
     @memoizedKey("resourceID", "_children")
     def childWithID(self, resourceID):
@@ -1242,25 +1227,16 @@
         """
         return self._childClass.objectWithID(self, resourceID)
 
-    @memoizedKey("name", "_sharedChildren")
-    def sharedChildWithName(self, name):
+    def invitedChildWithName(self, name):
         """
-        Retrieve the shared child with the given C{name} contained in this
-        home. Return a child object with this home and the name.
+        Retrieve the invited child with the given C{name} contained in this
+        home.
 
-        IMPORTANT: take care when using this. Shared calendars should normally
-        be accessed through the owner home collection, not the sharee home collection.
-        The only reason for access through sharee home is to do some housekeeping
-        for maintaining the revisions database to show shared calendars appearing and
-        disappearing in the sharee home.
-
         @param name: a string.
-        @return: an L{ICalendar} or C{None} if no such child
-            exists.
+        @return: an L{ICalendar} or C{None} if no such child exists.
         """
-        return self._childClass.objectWithName(self, name, owned=False)
+        return self._childClass.invitedObjectWithName(self, name)
 
-
     @inlineCallbacks
     def createChildWithName(self, name):
         if name.startswith("."):
@@ -1381,37 +1357,38 @@
         # Now deal with shared collections
         bind = self._bindSchema
         rev = self._revisionsSchema
-        shares = yield self.listSharedChildren()
-        for sharename in shares:
-            sharetoken = 0 if sharename in changed_collections else token
-            shareID = (yield Select(
-                [bind.RESOURCE_ID], From=bind,
-                Where=(bind.RESOURCE_NAME == sharename).And(
-                    bind.HOME_RESOURCE_ID == self._resourceID).And(
-                        bind.BIND_MODE != _BIND_MODE_OWN)
-            ).on(self._txn))[0][0]
-            results = [
-                (
-                    sharename,
-                    name if name else "",
-                    wasdeleted
-                )
-                for name, wasdeleted in
-                (yield Select([rev.RESOURCE_NAME, rev.DELETED],
-                                 From=rev,
-                                Where=(rev.REVISION > sharetoken).And(
-                                rev.RESOURCE_ID == shareID)).on(self._txn))
-                if name
-            ]
+        shares = yield self.children()
+        for share in shares:
+            if not share.owned():
+                sharetoken = 0 if share.name() in changed_collections else token
+                shareID = (yield Select(
+                    [bind.RESOURCE_ID], From=bind,
+                    Where=(bind.RESOURCE_NAME == share.name()).And(
+                        bind.HOME_RESOURCE_ID == self._resourceID).And(
+                            bind.BIND_MODE != _BIND_MODE_OWN)
+                ).on(self._txn))[0][0]
+                results = [
+                    (
+                        share.name(),
+                        name if name else "",
+                        wasdeleted
+                    )
+                    for name, wasdeleted in
+                    (yield Select([rev.RESOURCE_NAME, rev.DELETED],
+                                     From=rev,
+                                    Where=(rev.REVISION > sharetoken).And(
+                                    rev.RESOURCE_ID == shareID)).on(self._txn))
+                    if name
+                ]
+    
+                for path, name, wasdeleted in results:
+                    if wasdeleted:
+                        if sharetoken:
+                            deleted.append("%s/%s" % (path, name,))
+    
+                for path, name, wasdeleted in results:
+                    changed.append("%s/%s" % (path, name,))
 
-            for path, name, wasdeleted in results:
-                if wasdeleted:
-                    if sharetoken:
-                        deleted.append("%s/%s" % (path, name,))
-
-            for path, name, wasdeleted in results:
-                changed.append("%s/%s" % (path, name,))
-
         changed.sort()
         deleted.sort()
         returnValue((changed, deleted))
@@ -1421,6 +1398,7 @@
     def _loadPropertyStore(self):
         props = yield PropertyStore.load(
             self.uid(),
+            self.uid(),
             self._txn,
             self._resourceID,
             notifyCallback=self.notifyChanged
@@ -1530,7 +1508,7 @@
     def _preLockResourceIDQuery(cls): #@NoSelf
         meta = cls._homeMetaDataSchema
         return Select(From=meta,
-                      Where=meta.RESOURCE_ID==Parameter("resourceID"),
+                      Where=meta.RESOURCE_ID == Parameter("resourceID"),
                       ForUpdate=True)
 
 
@@ -1953,7 +1931,7 @@
             else:
                 self._syncTokenRevision = (
                     yield self._completelyNewRevisionQuery.on(
-                        self._txn, homeID=self._home._resourceID,
+                        self._txn, homeID=self.ownerHome()._resourceID,
                         resourceID=self._resourceID, name=name)
                 )[0][0]
         self._maybeNotify()
@@ -1969,10 +1947,6 @@
 class CommonHomeChild(LoggingMixIn, FancyEqMixin, _SharedSyncLogic):
     """
     Common ancestor class of AddressBooks and Calendars.
-
-    @ivar _owned: Is this calendar or addressbook referencing its sharer (owner)
-        home? (i.e. C{True} if L{ownerCalendarHome} will actually return the
-        sharer, C{False} or if it will return a sharee.)
     """
 
     compareAttributes = (
@@ -1984,10 +1958,11 @@
     _objectResourceClass = None
 
     _bindSchema              = None
-    _homeChildSchema         = None
+    _homeSchema              = None
+    _homeChildSchema          = None
     _homeChildMetaDataSchema = None
-    _revisionsSchema         = None
-    _objectSchema            = None
+    _revisionsSchema          = None
+    _objectSchema              = None
 
     _bindTable           = None
     _homeChildTable      = None
@@ -1997,7 +1972,7 @@
     _objectTable         = None
 
 
-    def __init__(self, home, name, resourceID, owned, mode):
+    def __init__(self, home, name, resourceID, mode, status, message=None, ownerHome=None):
 
         if home._notifiers:
             childID = "%s/%s" % (home.uid(), name)
@@ -2009,8 +1984,10 @@
         self._home              = home
         self._name              = name
         self._resourceID        = resourceID
-        self._owned             = owned
         self._bindMode          = mode
+        self._bindStatus         = status
+        self._bindMessage         = message
+        self._ownerHome         = home if ownerHome is None else ownerHome
         self._created           = None
         self._modified          = None
         self._objects           = {}
@@ -2018,16 +1995,15 @@
         self._syncTokenRevision = None
         self._notifiers         = notifiers
         self._index             = None  # Derived classes need to set this
-        self._invites           = None  # Derived classes need to set this
 
 
     @classproperty
-    def _ownedChildListQuery(cls): #@NoSelf
+    def _childNamesForHomeID(cls): #@NoSelf
         bind = cls._bindSchema
         return Select([bind.RESOURCE_NAME], From=bind,
                       Where=(bind.HOME_RESOURCE_ID ==
-                             Parameter("resourceID")).And(
-                                 bind.BIND_MODE == _BIND_MODE_OWN))
+                             Parameter("homeID")).And
+                                (bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
 
 
     @classmethod
@@ -2060,46 +2036,54 @@
             "_modified",
         )
         
-    @classproperty
-    def _sharedChildListQuery(cls): #@NoSelf
-        bind = cls._bindSchema
-        return Select([bind.RESOURCE_NAME], From=bind,
-                      Where=(bind.HOME_RESOURCE_ID ==
-                             Parameter("resourceID")).And(
-                                 bind.BIND_MODE != _BIND_MODE_OWN).And(
-                                 bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
-
     @classmethod
     @inlineCallbacks
-    def listObjects(cls, home, owned):
+    def listObjects(cls, home):
         """
         Retrieve the names of the children that exist in the given home.
 
         @return: an iterable of C{str}s.
         """
         # FIXME: tests don't cover this as directly as they should.
-        if owned:
-            rows = yield cls._ownedChildListQuery.on(
-                home._txn, resourceID=home._resourceID)
-        else:
-            rows = yield cls._sharedChildListQuery.on(
-                home._txn, resourceID=home._resourceID)
+        rows = yield cls._childNamesForHomeID.on(
+                home._txn, homeID=home._resourceID)
         names = [row[0] for row in rows]
         returnValue(names)
 
 
+    @classproperty
+    def _invitedBindForHomeID(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._bindFor((bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                            .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED))
+
     @classmethod
-    def _allHomeChildrenQuery(cls, owned):
+    @inlineCallbacks
+    def listInvitedObjects(cls, home):
+        """
+        Retrieve the names of the children with invitations in the given home.
+
+        @return: an iterable of C{str}s.
+        """
+        rows = yield cls._invitedBindForHomeID.on(
+            home._txn, homeID=home._resourceID
+        )
+        names = [row[3] for row in rows]
+        returnValue(names)
+
+
+    @classproperty
+    def _childrenAndMetadataForHomeID(cls): #@NoSelf
         bind = cls._bindSchema
         child = cls._homeChildSchema
         childMetaData = cls._homeChildMetaDataSchema
-        if owned:
-            ownedPiece = bind.BIND_MODE == _BIND_MODE_OWN
-        else:
-            ownedPiece = (bind.BIND_MODE != _BIND_MODE_OWN).And(
-                bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
 
-        columns = [child.RESOURCE_ID, bind.RESOURCE_NAME, bind.BIND_MODE]
+        columns = [bind.BIND_MODE,
+                   bind.HOME_RESOURCE_ID,
+                   bind.RESOURCE_ID,
+                   bind.RESOURCE_NAME,
+                   bind.BIND_STATUS,
+                   bind.MESSAGE]
         columns.extend(cls.metadataColumns())
         return Select(columns,
                      From=child.join(
@@ -2107,48 +2091,30 @@
                          'left outer').join(
                          childMetaData, childMetaData.RESOURCE_ID == bind.RESOURCE_ID,
                          'left outer'),
-                     Where=(bind.HOME_RESOURCE_ID == Parameter("resourceID")
-                           ).And(ownedPiece))
+                     Where=(bind.HOME_RESOURCE_ID == Parameter("homeID")
+                           ).And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
 
 
-    @classproperty
-    def _ownedHomeChildrenQuery(cls): #@NoSelf
-        return cls._allHomeChildrenQuery(True)
-
-
-    @classproperty
-    def _sharedHomeChildrenQuery(cls): #@NoSelf
-        return cls._allHomeChildrenQuery(False)
-
-
-    @classproperty
-    def _insertInviteQuery(cls): #@NoSelf
-        inv = schema.INVITE
-        return Insert(
-            {
-                inv.INVITE_UID: Parameter("uid"),
-                inv.NAME: Parameter("name"),
-                inv.HOME_RESOURCE_ID: Parameter("homeID"),
-                inv.RESOURCE_ID: Parameter("resourceID"),
-                inv.RECIPIENT_ADDRESS: Parameter("recipient")
-            }
-        )
-
-
-    @classproperty
-    def _updateBindQuery(cls): #@NoSelf
+    @classmethod
+    def _updateBindColumnsQuery(cls, columnMap): #@NoSelf
         bind = cls._bindSchema
-        return Update({bind.BIND_MODE: Parameter("mode"),
-                       bind.BIND_STATUS: Parameter("status"),
-                       bind.MESSAGE: Parameter("message")},
+        return Update(columnMap,
                       Where=
                       (bind.RESOURCE_ID == Parameter("resourceID"))
                       .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
                       Return=bind.RESOURCE_NAME)
 
+    @classproperty
+    def _updateBindQuery(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._updateBindColumnsQuery(
+                    {bind.BIND_MODE: Parameter("mode"),
+                     bind.BIND_STATUS: Parameter("status"),
+                     bind.MESSAGE: Parameter("message")})
 
+
     @inlineCallbacks
-    def shareWith(self, shareeHome, mode):
+    def shareWith(self, shareeHome, mode, status=None, message=None):
         """
         Share this (owned) L{CommonHomeChild} with another home.
 
@@ -2156,16 +2122,25 @@
         @type shareeHome: L{CommonHome}
 
         @param mode: The sharing mode; L{_BIND_MODE_READ} or
-            L{_BIND_MODE_WRITE}.
+            L{_BIND_MODE_WRITE} or L{_BIND_MODE_DIRECT}
         @type mode: L{str}
 
+        @param status: The sharing mode; L{_BIND_STATUS_INVITED} or
+            L{_BIND_STATUS_ACCEPTED} or L{_BIND_STATUS_DECLINED} or
+            L{_BIND_STATUS_INVALID}.
+        @type mode: L{str}
+
+        @param message: The proposed message to go along with the share, which
+            will be used as the default display name.
+        @type mode: L{str}
+
         @return: the name of the shared calendar in the new calendar home.
         @rtype: L{str}
         """
-        dn = PropertyName.fromElement(DisplayName)
-        dnprop = (self.properties().get(dn) or
-                  DisplayName.fromString(self.name()))
-        # FIXME: honor current home type
+        
+        if status is None:
+            status = _BIND_STATUS_ACCEPTED
+        
         @inlineCallbacks
         def doInsert(subt):
             newName = str(uuid4())
@@ -2173,13 +2148,8 @@
                 subt, homeID=shareeHome._resourceID,
                 resourceID=self._resourceID, name=newName, mode=mode,
                 seenByOwner=True, seenBySharee=True,
-                bindStatus=_BIND_STATUS_ACCEPTED,
+                bindStatus=status, message=message
             )
-            yield self._insertInviteQuery.on(
-                subt, uid=newName, name=str(dnprop),
-                homeID=shareeHome._resourceID, resourceID=self._resourceID,
-                recipient=shareeHome.uid()
-            )
             returnValue(newName)
         try:
             sharedName = yield self._txn.subtransaction(doInsert)
@@ -2187,19 +2157,92 @@
             # FIXME: catch more specific exception
             sharedName = (yield self._updateBindQuery.on(
                 self._txn,
-                mode=mode, status=_BIND_STATUS_ACCEPTED, message=None,
+                mode=mode, status=status, message=message,
                 resourceID=self._resourceID, homeID=shareeHome._resourceID
             ))[0][0]
-            # Invite already exists; no need to update it, since the name will
-            # remain the same.
+                
+        # Must send notification to ensure cache invalidation occurs
+        yield self.notifyChanged()
 
-        shareeProps = yield PropertyStore.load(shareeHome.uid(), self._txn,
-                                               self._resourceID)
-        shareeProps[dn] = dnprop
         returnValue(sharedName)
 
 
     @inlineCallbacks
+    def updateShare(self, shareeView, mode=None, status=None, message=None, name=None):
+        """
+        Update share mode, status, and message for a home child shared with
+        this (owned) L{CommonHomeChild}.
+
+        @param shareeView: The sharee home child that shares this.
+        @type shareeView: L{CommonHomeChild}
+
+        @param mode: The sharing mode; L{_BIND_MODE_READ} or
+            L{_BIND_MODE_WRITE} or None to not update
+        @type mode: L{str}
+
+        @param status: The sharing mode; L{_BIND_STATUS_INVITED} or
+            L{_BIND_STATUS_ACCEPTED} or L{_BIND_STATUS_DECLINED} or
+            L{_BIND_STATUS_INVALID}  or None to not update
+        @type status: L{str}
+
+        @param message: The proposed message to go along with the share, which
+            will be used as the default display name, or None to not update
+        @type message: L{str}
+
+        @param name: The bind resource name or None to not update
+        @type message: L{str}
+
+        @return: the name of the shared item in the sharee's home.
+        @rtype: a L{Deferred} which fires with a L{str}
+        """
+        # TODO: raise a nice exception if shareeView is not, in fact, a shared
+        # version of this same L{CommonHomeChild}
+
+        #remove None parameters, and substitute None for empty string
+        bind = self._bindSchema
+        columnMap = dict([(k, v if v else None) 
+                          for k,v in {bind.BIND_MODE:mode,
+                            bind.BIND_STATUS:status,
+                            bind.MESSAGE:message,
+                            bind.RESOURCE_NAME:name}.iteritems() if v is not None])
+                                
+        if len(columnMap):
+            
+            #TODO:  with bit of parameter wrangling, call shareWith() here instead.
+            sharedname = yield self._updateBindColumnsQuery(columnMap).on(
+                            self._txn,
+                            resourceID=self._resourceID, homeID=shareeView._home._resourceID
+                        )
+            
+            #update affected attributes
+            if mode:
+                shareeView._bindMode = columnMap[bind.BIND_MODE]
+                
+            if status:
+                shareeView._bindStatus = columnMap[bind.BIND_STATUS]
+                if shareeView._bindStatus == _BIND_STATUS_ACCEPTED:
+                    yield shareeView._initSyncToken()
+                elif shareeView._bindStatus == _BIND_STATUS_DECLINED:
+                    shareeView._deletedSyncToken(sharedRemoval=True);
+
+            if message:
+                shareeView._bindMessage = columnMap[bind.MESSAGE]
+            
+            queryCacher = self._txn._queryCacher
+            if queryCacher:
+                cacheKey = queryCacher.keyForObjectWithName(shareeView._home._resourceID, shareeView._name)
+                queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+            
+            shareeView._name = sharedname[0][0]
+
+            # Must send notification to ensure cache invalidation occurs
+            yield self.notifyChanged()
+                    
+        returnValue(shareeView._name)
+        
+
+
+    @inlineCallbacks
     def unshareWith(self, shareeHome):
         """
         Remove the shared version of this (owned) L{CommonHomeChild} from the
@@ -2212,15 +2255,38 @@
 
         @return: a L{Deferred} which will fire with the previously-used name.
         """
+        
+        
+        #remove sync tokens
+        shareeChildren = yield shareeHome.children()
+        for shareeChild in shareeChildren:
+            if not shareeChild.owned() and shareeChild._resourceID == self._resourceID:
+                shareeChild._deletedSyncToken(sharedRemoval=True);
+ 
+                queryCacher = self._txn._queryCacher
+                if queryCacher:
+                    cacheKey = queryCacher.keyForObjectWithName(shareeHome._resourceID, shareeChild._name)
+                    queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
+                break;
+
         bind = self._bindSchema
-        resourceName = (yield Delete(
+        rows = yield Delete(
             From=bind,
             Where=(bind.RESOURCE_ID == Parameter("resourceID"))
                   .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
             Return=bind.RESOURCE_NAME,
         ).on(self._txn, resourceID=self._resourceID,
-             homeID=shareeHome._resourceID))[0][0]
-        shareeHome._sharedChildren.pop(resourceName, None)
+             homeID=shareeHome._resourceID)
+        
+        resourceName = None
+        if rows:
+            resourceName = rows[0][0]
+            shareeHome._children.pop(resourceName, None)
+        
+        # Must send notification to ensure cache invalidation occurs
+        yield self.notifyChanged()
+       
         returnValue(resourceName)
 
 
@@ -2230,7 +2296,30 @@
         """
         return self._bindMode
 
+    def owned(self):
+        """
+        @see: L{ICalendar.owned}
+        """
+        return self._bindMode == _BIND_MODE_OWN
 
+    def shareStatus(self):
+        """
+        @see: L{ICalendar.shareStatus}
+        """
+        return self._bindStatus
+
+    def shareMessage(self):
+        """
+        @see: L{ICalendar.shareMessage}
+        """
+        return self._bindMessage
+
+    def shareUID(self):
+        """
+        @see: L{ICalendar.shareUID}
+        """
+        return self.name()
+
     @inlineCallbacks
     def unshare(self, homeType):
         """
@@ -2238,8 +2327,7 @@
 
         @param homeType: a valid store type (ECALENDARTYPE or EADDRESSBOOKTYPE)
         """
-        mode = self.shareMode()
-        if mode == _BIND_MODE_OWN:
+        if self.owned():
             # This collection may be shared to others
             for sharedToHome in [x.viewerHome() for x in (yield self.asShared())]:
                 (yield self.unshareWith(sharedToHome))
@@ -2252,16 +2340,28 @@
             (yield sharerCollection.unshareWith(self._home))
 
 
+    @classmethod
+    def _bindFor(cls, condition): #@NoSelf
+        bind = cls._bindSchema
+        return Select(
+            [bind.BIND_MODE,
+             bind.HOME_RESOURCE_ID,
+             bind.RESOURCE_ID,
+             bind.RESOURCE_NAME,
+             bind.BIND_STATUS,
+             bind.MESSAGE],
+                  From=bind,
+                  Where=condition
+        )
 
     @classproperty
-    def _bindEntriesFor(cls): #@NoSelf
+    def _sharedBindForResourceID(cls): #@NoSelf
         bind = cls._bindSchema
-        return Select([bind.BIND_MODE, bind.HOME_RESOURCE_ID,
-                       bind.RESOURCE_NAME],
-                      From=bind,
-                      Where=(bind.RESOURCE_ID == Parameter("resourceID")).And
-                            (bind.BIND_STATUS == _BIND_STATUS_ACCEPTED).And
-                            (bind.BIND_MODE != _BIND_MODE_OWN))
+        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+                            .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+                            .And(bind.BIND_MODE != _BIND_MODE_OWN)
+                            )
+    
 
 
     @inlineCallbacks
@@ -2276,26 +2376,76 @@
             L{CommonHomeChild} as a child of different L{CommonHome}s
         @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
         """
-        rows = yield self._bindEntriesFor.on(self._txn,
-                                             resourceID=self._resourceID)
+        if not self.owned():
+            returnValue([])
+
+        # get all accepted binds
+        acceptedRows = yield self._sharedBindForResourceID.on(
+            self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+        )
+
         cls = self.__class__ # for ease of grepping...
         result = []
-        for mode, homeResourceID, sharedResourceName in rows:
+        for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in acceptedRows: #@UnusedVariable
+            assert bindStatus == _BIND_STATUS_ACCEPTED
             # TODO: this could all be issued in parallel; no need to serialize
             # the loop.
             new = cls(
-                (yield self._txn.homeWithResourceID(self._home._homeType,
-                                                    homeResourceID)),
-                sharedResourceName, self._resourceID, False, mode
+                home=(yield self._txn.homeWithResourceID(self._home._homeType, homeID)),
+                name=resourceName, resourceID=self._resourceID,
+                mode=bindMode, status=bindStatus,
+                message=bindMessage, ownerHome=self._home
             )
             yield new.initFromStore()
             result.append(new)
         returnValue(result)
 
 
+    @classproperty
+    def _invitedBindForResourceID(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+                            .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+                            )
+
+    @inlineCallbacks
+    def asInvited(self):
+        """
+        Retrieve all the versions of this L{CommonHomeChild} as it is invited to
+        everyone.
+
+        @see: L{ICalendarHome.asInvited}
+
+        @return: L{CommonHomeChild} objects that represent this
+            L{CommonHomeChild} as a child of different L{CommonHome}s
+        @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
+        """
+        if not self.owned():
+            returnValue([])
+        
+        rows = yield self._invitedBindForResourceID.on(
+            self._txn, resourceID=self._resourceID, homeID=self._home._resourceID,
+        )
+        cls = self.__class__ # for ease of grepping...
+
+        result = []
+        for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in rows: #@UnusedVariable
+            # TODO: this could all be issued in parallel; no need to serialize
+            # the loop.
+            new = cls(
+                home=(yield self._txn.homeWithResourceID(self._home._homeType, homeID)),
+                name=resourceName, resourceID=self._resourceID,
+                mode=bindMode, status=bindStatus,
+                message=bindMessage, ownerHome=self._home
+            )
+            yield new.initFromStore()
+            result.append(new)
+        returnValue(result)
+
+
     @classmethod
     @inlineCallbacks
-    def loadAllObjects(cls, home, owned):
+    def loadAllObjects(cls, home):
         """
         Load all L{CommonHomeChild} instances which are children of a given
         L{CommonHome} and return a L{Deferred} firing a list of them.  This must
@@ -2306,13 +2456,10 @@
         results = []
 
         # Load from the main table first
-        if owned:
-            query = cls._ownedHomeChildrenQuery
-        else:
-            query = cls._sharedHomeChildrenQuery
-        dataRows = (yield query.on(home._txn, resourceID=home._resourceID))
+        dataRows = (yield cls._childrenAndMetadataForHomeID.on(home._txn, homeID=home._resourceID))
 
         if dataRows:
+            
             # Get property stores for all these child resources (if any found)
             propertyStores = (yield PropertyStore.forMultipleResources(
                 home.uid(), home._txn,
@@ -2322,15 +2469,10 @@
 
             bind = cls._bindSchema
             rev = cls._revisionsSchema
-            if owned:
-                ownedCond = bind.BIND_MODE == _BIND_MODE_OWN
-            else:
-                ownedCond = bind.BIND_MODE != _BIND_MODE_OWN
             revisions = (yield Select(
                 [rev.RESOURCE_ID, Max(rev.REVISION)],
                 From=rev.join(bind, rev.RESOURCE_ID == bind.RESOURCE_ID, 'left'),
                 Where=(bind.HOME_RESOURCE_ID == home._resourceID).
-                    And(ownedCond).
                     And((rev.RESOURCE_NAME != None).Or(rev.DELETED == False)),
                 GroupBy=rev.RESOURCE_ID
             ).on(home._txn))
@@ -2338,9 +2480,23 @@
 
         # Create the actual objects merging in properties
         for items in dataRows:
-            resourceID, resourceName, bindMode = items[:3]
-            metadata = items[3:]
-            child = cls(home, resourceName, resourceID, owned, bindMode)
+            bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = items[:6] #@UnusedVariable
+            metadata=items[7:]
+            
+            if bindStatus == _BIND_MODE_OWN:
+                ownerHome = home
+            else:
+                #TODO: get all ownerHomeIDs at once
+                ownerHomeID = (yield cls._ownerHomeWithResourceID.on(
+                                home._txn, resourceID=resourceID))[0][0]
+                ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
+
+            child = cls(
+                home=home,
+                name=resourceName, resourceID=resourceID,
+                mode=bindMode, status=bindStatus,
+                message=bindMessage, ownerHome=ownerHome
+            )
             for attr, value in zip(cls.metadataAttributes(), metadata):
                 setattr(child, attr, value)
             child._syncTokenRevision = revisions[resourceID]
@@ -2350,48 +2506,65 @@
         returnValue(results)
 
 
+    @classproperty
+    def _invitedBindForNameAndHomeID(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
+                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                               .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+                               )
+
+
     @classmethod
-    def _homeChildLookup(cls, ownedPart):
+    @inlineCallbacks
+    def invitedObjectWithName(cls, home, name):
         """
-        Common portions of C{_ownedResourceIDByName}
-        C{_resourceIDSharedToHomeByName}, except for the 'owned' fragment of the
-        Where clause, supplied as an argument.
-        """
-        bind = cls._bindSchema
-        return Select(
-            [bind.RESOURCE_ID, bind.BIND_MODE],
-            From=bind,
-            Where=(bind.RESOURCE_NAME == Parameter('objectName')).And(
-                   bind.HOME_RESOURCE_ID == Parameter('homeID')).And(
-                    ownedPart))
+        Retrieve the child with the given C{name} contained in the given
+        C{home}.
 
+        @param home: a L{CommonHome}.
 
-    @classproperty
-    def _resourceIDOwnedByHomeByName(cls): #@NoSelf
+        @param name: a string; the name of the L{CommonHomeChild} to retrieve.
+
+        @param owned: a boolean - whether or not to get a shared child
+        @return: an L{CommonHomeChild} or C{None} if no such child
+            exists.
         """
-        DAL query to look up an object resource ID owned by a home, given a
-        resource name (C{objectName}), and a home resource ID
-        (C{homeID}).
-        """
-        return cls._homeChildLookup(
-            cls._bindSchema.BIND_MODE == _BIND_MODE_OWN)
+        rows = yield cls._invitedBindForNameAndHomeID.on(home._txn,
+                              name=name, homeID=home._resourceID)
 
+        if not rows:
+            returnValue(None)
 
+        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+        
+        #TODO:  combine with _invitedBindForNameAndHomeID and sort results
+        ownerHomeID = (yield cls._ownerHomeWithResourceID.on(
+                        home._txn, resourceID=resourceID))[0][0]
+        ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
+
+        child = cls(
+            home=home,
+            name=resourceName, resourceID=resourceID,
+            mode=bindMode, status=bindStatus,
+            message=bindMessage, ownerHome=ownerHome,
+        )
+        yield child.initFromStore()
+        returnValue(child)
+
+
     @classproperty
-    def _resourceIDSharedToHomeByName(cls): #@NoSelf
-        """
-        DAL query to look up an object resource ID shared to a home, given a
-        resource name (C{objectName}), and a home resource ID
-        (C{homeID}).
-        """
-        return cls._homeChildLookup(
-            (cls._bindSchema.BIND_MODE != _BIND_MODE_OWN).And(
-                cls._bindSchema.BIND_STATUS == _BIND_STATUS_ACCEPTED))
+    def _childForNameAndHomeID(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
+                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                               .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+                               )
 
-
     @classmethod
     @inlineCallbacks
-    def objectWithName(cls, home, name, owned):
+    def objectWithName(cls, home, name):
+        # replaces objectWithName()
         """
         Retrieve the child with the given C{name} contained in the given
         C{home}.
@@ -2400,53 +2573,67 @@
 
         @param name: a string; the name of the L{CommonHomeChild} to retrieve.
 
-        @param owned: a boolean - whether or not to get a shared child
         @return: an L{CommonHomeChild} or C{None} if no such child
             exists.
         """
-        data = None
+        rows = None
         queryCacher = home._txn._queryCacher
-        # Only caching non-shared objects so that we don't need to invalidate
-        # in sql_legacy
-        if owned and queryCacher:
+        
+        if queryCacher:
             # Retrieve data from cache
             cacheKey = queryCacher.keyForObjectWithName(home._resourceID, name)
-            data = yield queryCacher.get(cacheKey)
-
-        if data is None:
+            rows = yield queryCacher.get(cacheKey)
+            
+        if rows is None:
             # No cached copy
-            if owned:
-                query = cls._resourceIDOwnedByHomeByName
-            else:
-                query = cls._resourceIDSharedToHomeByName
-            data = yield query.on(home._txn,
-                                  objectName=name, homeID=home._resourceID)
-            if owned and data and queryCacher:
+            rows = yield cls._childForNameAndHomeID.on(home._txn, name=name, homeID=home._resourceID)
+                    
+            if rows:
+                bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+                # get ownerHomeID                
+                if bindMode == _BIND_MODE_OWN:
+                    ownerHomeID = homeID
+                else:
+                    ownerHomeID = (yield cls._ownerHomeWithResourceID.on(
+                                    home._txn, resourceID=resourceID))[0][0]
+                rows[0].append(ownerHomeID)
+            
+            if rows and queryCacher:
                 # Cache the result
-                queryCacher.setAfterCommit(home._txn, cacheKey, data)
-
-        if not data:
+                queryCacher.setAfterCommit(home._txn, cacheKey, rows)
+        
+        if not rows:
             returnValue(None)
-
-        resourceID, mode = data[0]
-        child = cls(home, name, resourceID, owned, mode)
+        
+        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage, ownerHomeID = rows[0] #@UnusedVariable
+        
+        if bindMode == _BIND_MODE_OWN:
+            ownerHome = home
+        else:
+            ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
+            
+        child = cls(
+            home=home,
+            name=name, resourceID=resourceID,
+            mode=bindMode, status=bindStatus,
+            message=bindMessage, ownerHome=ownerHome,
+        )
         yield child.initFromStore()
         returnValue(child)
 
 
     @classproperty
-    def _homeChildByIDQuery(cls): #@NoSelf
+    def _bindForResourceIDAndHomeID(cls): #@NoSelf
         """
         DAL query that looks up home child names / bind modes by home child
-        resouce ID and home resource ID.
+        resource ID and home resource ID.
         """
         bind = cls._bindSchema
-        return Select([bind.RESOURCE_NAME, bind.BIND_MODE],
-                      From=bind,
-                      Where=(bind.RESOURCE_ID == Parameter("resourceID")
-                            ).And(bind.HOME_RESOURCE_ID == Parameter("homeID")))
-
-
+        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                               )
+                               
+                               
     @classmethod
     @inlineCallbacks
     def objectWithID(cls, home, resourceID):
@@ -2459,12 +2646,25 @@
         @return: an L{CommonHomeChild} or C{None} if no such child
             exists.
         """
-        data = yield cls._homeChildByIDQuery.on(
+        rows = yield cls._bindForResourceIDAndHomeID.on(
             home._txn, resourceID=resourceID, homeID=home._resourceID)
-        if not data:
+        if not rows:
             returnValue(None)
-        name, mode = data[0]
-        child = cls(home, name, resourceID, mode == _BIND_MODE_OWN, mode)
+                
+        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+        
+        if bindMode == _BIND_MODE_OWN:
+            ownerHome = home
+        else:
+            ownerHomeID = (yield cls._ownerHomeWithResourceID.on(
+                            home._txn, resourceID=resourceID))[0][0]
+            ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
+        child = cls(
+            home=home,
+            name=resourceName, resourceID=resourceID,
+            mode=bindMode, status=bindStatus,
+            message=bindMessage,  ownerHome=ownerHome,
+        )
         yield child.initFromStore()
         returnValue(child)
 
@@ -2493,7 +2693,7 @@
     def _bindInsertQuery(cls, **kw): #@NoSelf
         """
         DAL statement to create a bind entry that connects a collection to its
-        owner's home.
+        home.
         """
         bind = cls._bindSchema
         return Insert({
@@ -2502,6 +2702,7 @@
             bind.RESOURCE_NAME: Parameter("name"),
             bind.BIND_MODE: Parameter("mode"),
             bind.BIND_STATUS: Parameter("bindStatus"),
+            bind.MESSAGE: Parameter("message"),
             bind.SEEN_BY_OWNER: Parameter("seenByOwner"),
             bind.SEEN_BY_SHAREE: Parameter("seenBySharee"),
         })
@@ -2510,9 +2711,12 @@
     @classmethod
     @inlineCallbacks
     def create(cls, home, name):
-        child = (yield cls.objectWithName(home, name, owned=True))
+        child = (yield cls.objectWithName(home, name))
         if child is not None:
             raise HomeChildNameAlreadyExistsError(name)
+        invite = (yield cls.invitedObjectWithName(home, name))
+        if invite is not None:
+            raise HomeChildNameAlreadyExistsError(name)
 
         if name.startswith("."):
             raise HomeChildNameNotAllowedError(name)
@@ -2530,11 +2734,12 @@
         yield cls._bindInsertQuery.on(
             home._txn, homeID=home._resourceID, resourceID=resourceID,
             name=name, mode=_BIND_MODE_OWN, seenByOwner=True,
-            seenBySharee=True, bindStatus=_BIND_STATUS_ACCEPTED
+            seenBySharee=True, bindStatus=_BIND_STATUS_ACCEPTED,
+            message=None,
         )
 
         # Initialize other state
-        child = cls(home, name, resourceID, True, _BIND_MODE_OWN)
+        child = cls(home, name, resourceID, _BIND_MODE_OWN, _BIND_STATUS_ACCEPTED)
         child._created = _created
         child._modified = _modified
         yield child._loadPropertyStore()
@@ -2601,10 +2806,6 @@
         return self._index
 
 
-    def retrieveOldInvites(self):
-        return self._invites
-
-
     def __repr__(self):
         return "<%s: %s>" % (self.__class__.__name__, self._resourceID)
 
@@ -2699,9 +2900,10 @@
 
     def ownerHome(self):
         """
-        (Don't use this method.  See interface documentation as to why.)
+        @see: L{ICalendar.ownerCalendarHome}
+        @see: L{IAddressbook.ownerAddessbookHome}
         """
-        return self._home
+        return self._ownerHome
 
 
     def viewerHome(self):
@@ -2713,7 +2915,7 @@
 
 
     @classproperty
-    def _ownerHomeFromResourceQuery(cls): #@NoSelf
+    def _ownerHomeWithResourceID(cls): #@NoSelf
         """
         DAL query to retrieve the home resource ID of the owner from the bound
         home-child ID.
@@ -2734,20 +2936,16 @@
         @return: a L{Deferred} that fires with the resource ID.
         @rtype: L{Deferred} firing L{int}
         """
-        if self._owned:
+        if self.owned():
             # If this was loaded by its owner then we can skip the query, since
             # we already know who the owner is.
             returnValue(self._home._resourceID)
         else:
-            rid = (yield self._ownerHomeFromResourceQuery.on(
+            rid = (yield self._ownerHomeWithResourceID.on(
                 self._txn, resourceID=self._resourceID))[0][0]
             returnValue(rid)
 
 
-    def setSharingUID(self, uid):
-        self.properties()._setPerUserUID(uid)
-
-
     @inlineCallbacks
     def objectResources(self):
         """
@@ -3034,6 +3232,7 @@
         if props is None:
             props = yield PropertyStore.load(
                 self.ownerHome().uid(),
+                self.viewerHome().uid(),
                 self._txn,
                 self._resourceID,
                 notifyCallback=self.notifyChanged
@@ -3218,7 +3417,7 @@
         if dataRows:
             # Get property stores for all these child resources (if any found)
             if parent.objectResourcesHaveProperties():
-                propertyStores =(yield PropertyStore.forMultipleResources(
+                propertyStores = (yield PropertyStore.forMultipleResources(
                     parent._home.uid(),
                     parent._txn,
                     cls._objectSchema.RESOURCE_ID,
@@ -3286,7 +3485,7 @@
         if dataRows:
             # Get property stores for all these child resources
             if parent.objectResourcesHaveProperties():
-                propertyStores =(yield PropertyStore.forMultipleResourcesWithResourceIDs(
+                propertyStores = (yield PropertyStore.forMultipleResourcesWithResourceIDs(
                     parent._home.uid(),
                     parent._txn,
                     tuple([row[0] for row in dataRows]),
@@ -3434,6 +3633,7 @@
         if props is None:
             if self._parentCollection.objectResourcesHaveProperties():
                 props = yield PropertyStore.load(
+                    self._parentCollection.viewerHome().uid(),
                     self._parentCollection.ownerHome().uid(),
                     self._txn,
                     self._resourceID,
@@ -3699,6 +3899,7 @@
     def _loadPropertyStore(self):
         self._propertyStore = yield PropertyStore.load(
             self._uid,
+            self._uid,
             self._txn,
             self._resourceID,
             notifyCallback=self.notifyChanged
@@ -3709,10 +3910,6 @@
         return ResourceType.notification #@UndefinedVariable
 
 
-    def retrieveOldIndex(self):
-        return PostgresLegacyNotificationsEmulator(self)
-
-
     def __repr__(self):
         return "<%s: %s>" % (self.__class__.__name__, self._resourceID)
 
@@ -3723,8 +3920,20 @@
 
     def uid(self):
         return self._uid
+    
 
+    def owned(self):
+        return True
 
+
+    def ownerHome(self):
+        return self._home
+    
+
+    def viewerHome(self):
+        return self._home
+
+
     @inlineCallbacks
     def notificationObjects(self):
         results = (yield NotificationObject.loadAllObjects(self))
@@ -3981,7 +4190,7 @@
 
         if dataRows:
             # Get property stores for all these child resources (if any found)
-            propertyStores =(yield PropertyStore.forMultipleResources(
+            propertyStores = (yield PropertyStore.forMultipleResources(
                 parent.uid(),
                 parent._txn,
                 schema.NOTIFICATION.RESOURCE_ID,

Modified: CalendarServer/trunk/txdav/common/datastore/sql_legacy.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_legacy.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/common/datastore/sql_legacy.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -29,25 +29,17 @@
 from twistedcaldav.config import config
 from twistedcaldav.dateops import normalizeForIndex, pyCalendarTodatetime
 from twistedcaldav.memcachepool import CachePoolUserMixIn
-from twistedcaldav.notifications import NotificationRecord
 from twistedcaldav.query import \
     calendarqueryfilter, calendarquery, addressbookquery, expression, \
     addressbookqueryfilter
 from twistedcaldav.query.sqlgenerator import sqlgenerator
-from twistedcaldav.sharing import Invite
-from twistedcaldav.sharing import SharedCollectionRecord
 
 from txdav.caldav.icalendarstore import TimeRangeLowerLimit, TimeRangeUpperLimit
 from txdav.common.icommondatastore import IndexedSearchException, \
     ReservationError, NoSuchObjectResourceError
 
-from txdav.common.datastore.sql_tables import (
-    _BIND_MODE_OWN, _BIND_MODE_READ, _BIND_MODE_WRITE, _BIND_MODE_DIRECT,
-    _BIND_STATUS_INVITED, _BIND_STATUS_ACCEPTED, _BIND_STATUS_DECLINED,
-    _BIND_STATUS_INVALID, CALENDAR_BIND_TABLE, CALENDAR_HOME_TABLE,
-    ADDRESSBOOK_HOME_TABLE, ADDRESSBOOK_BIND_TABLE, schema)
-from twext.enterprise.dal.syntax import Delete, Insert, Parameter, \
-    SavepointAction, Select, Update 
+from txdav.common.datastore.sql_tables import schema
+from twext.enterprise.dal.syntax import Parameter, Select 
 from twext.python.clsprop import classproperty
 from twext.python.log import Logger, LoggingMixIn
 
@@ -64,685 +56,6 @@
     4: 'T',
 }
 
-class PostgresLegacyNotificationsEmulator(object):
-    def __init__(self, notificationsCollection):
-        self._collection = notificationsCollection
-
-
-    @inlineCallbacks
-    def _recordForObject(self, notificationObject):
-        if notificationObject:
-            returnValue(
-                NotificationRecord(
-                    notificationObject.uid(),
-                    notificationObject.name(),
-                    (yield notificationObject.xmlType().toxml())
-                )
-            )
-        else:
-            returnValue(None)
-
-
-    def recordForName(self, name):
-        return self._recordForObject(
-            self._collection.notificationObjectWithName(name)
-        )
-
-
-    @inlineCallbacks
-    def recordForUID(self, uid):
-        returnValue((yield self._recordForObject(
-            (yield self._collection.notificationObjectWithUID(uid))
-        )))
-
-
-    def removeRecordForUID(self, uid):
-        return self._collection.removeNotificationObjectWithUID(uid)
-
-
-    def removeRecordForName(self, name):
-        return self._collection.removeNotificationObjectWithName(name)
-
-
-
-class SQLLegacyInvites(object):
-    """
-    Emulator for the implicit interface specified by
-    L{twistedcaldav.sharing.InvitesDatabase}.
-    """
-
-    _homeTable = None
-    _bindTable = None
-
-    _homeSchema = None
-    _bindSchema = None
-
-    def __init__(self, collection):
-        self._collection = collection
-
-        # Since we do multi-table requests we need a dict that combines tables
-        self._combinedTable = {}
-        for key, value in self._homeTable.iteritems():
-            self._combinedTable["HOME:%s" % (key,)] = value
-        for key, value in self._bindTable.iteritems():
-            self._combinedTable["BIND:%s" % (key,)] = value
-
-
-    @property
-    def _txn(self):
-        return self._collection._txn
-
-
-    def _getHomeWithUID(self, uid):
-        raise NotImplementedError()
-
-
-    def create(self):
-        "No-op, because the index implicitly always exists in the database."
-
-
-    def remove(self):
-        "No-op, because the index implicitly always exists in the database."
-
-
-    @classmethod
-    def _allColumnsQuery(cls, condition):
-        inv = schema.INVITE
-        home = cls._homeSchema
-        bind = cls._bindSchema
-        return Select(
-            [inv.INVITE_UID,
-             inv.NAME,
-             inv.RECIPIENT_ADDRESS,
-             home.OWNER_UID,
-             bind.BIND_MODE,
-             bind.BIND_STATUS,
-             bind.MESSAGE],
-            From=inv.join(home).join(bind),
-            Where=(
-                condition
-                .And(inv.RESOURCE_ID == bind.RESOURCE_ID)
-                .And(inv.HOME_RESOURCE_ID == home.RESOURCE_ID)
-                .And(inv.HOME_RESOURCE_ID == bind.HOME_RESOURCE_ID)),
-            OrderBy=inv.NAME, Ascending=True
-        )
-
-
-    @classproperty
-    def _allRecordsQuery(cls): #@NoSelf
-        """
-        DAL query for all invite records with a given resource ID.
-        """
-        inv = schema.INVITE
-        return cls._allColumnsQuery(inv.RESOURCE_ID == Parameter("resourceID"))
-
-
-    @inlineCallbacks
-    def allRecords(self):
-        values = []
-        rows = yield self._allRecordsQuery.on(
-            self._txn, resourceID=self._collection._resourceID
-        )
-        for row in rows:
-            values.append(self._makeInvite(row))
-        returnValue(values)
-
-
-    @classproperty
-    def _inviteForRecipientQuery(cls): #@NoSelf
-        """
-        DAL query to retrieve an invite record for a given recipient address.
-        """
-        inv = schema.INVITE
-        return cls._allColumnsQuery(
-            (inv.RESOURCE_ID == Parameter("resourceID")).And(inv.RECIPIENT_ADDRESS == Parameter("recipient"))
-        )
-
-
-    @inlineCallbacks
-    def recordForUserID(self, userid):
-        rows = yield self._inviteForRecipientQuery.on(
-            self._txn,
-            resourceID=self._collection._resourceID,
-            recipient=userid
-        )
-        returnValue(self._makeInvite(rows[0]) if rows else None)
-
-
-    @classproperty
-    def _inviteForPrincipalUIDQuery(cls): #@NoSelf
-        """
-        DAL query to retrieve an invite record for a given principal UID.
-        """
-        inv = schema.INVITE
-        home = cls._homeSchema
-        return cls._allColumnsQuery(
-            (inv.RESOURCE_ID == Parameter("resourceID")).And(home.OWNER_UID == Parameter("principalUID"))
-        )
-
-
-    @inlineCallbacks
-    def recordForPrincipalUID(self, principalUID):
-        rows = yield self._inviteForPrincipalUIDQuery.on(
-            self._txn,
-            resourceID=self._collection._resourceID,
-            principalUID=principalUID
-        )
-        returnValue(self._makeInvite(rows[0]) if rows else None)
-
-
-    @classproperty
-    def _inviteForUIDQuery(cls): #@NoSelf
-        """
-        DAL query to retrieve an invite record for a given recipient address.
-        """
-        inv = schema.INVITE
-        return cls._allColumnsQuery(inv.INVITE_UID == Parameter("uid"))
-
-
-    @inlineCallbacks
-    def recordForInviteUID(self, inviteUID):
-        rows = yield self._inviteForUIDQuery.on(self._txn, uid=inviteUID)
-        returnValue(self._makeInvite(rows[0]) if rows else None)
-
-
-    def _makeInvite(self, row):
-        [inviteuid, common_name, userid, ownerUID,
-            bindMode, bindStatus, summary] = row
-        # FIXME: this is really the responsibility of the protocol layer.
-        state = {
-            _BIND_STATUS_INVITED: "NEEDS-ACTION",
-            _BIND_STATUS_ACCEPTED: "ACCEPTED",
-            _BIND_STATUS_DECLINED: "DECLINED",
-            _BIND_STATUS_INVALID: "INVALID",
-        }[bindStatus]
-        access = {
-            _BIND_MODE_OWN: "own",
-            _BIND_MODE_READ: "read-only",
-            _BIND_MODE_WRITE: "read-write"
-        }[bindMode]
-        return Invite(
-            inviteuid, userid, ownerUID, common_name,
-            access, state, summary
-        )
-
-
-    @classproperty
-    def _updateBindQuery(cls): #@NoSelf
-        bind = cls._bindSchema
-
-        return Update({bind.BIND_MODE: Parameter("mode"),
-                       bind.BIND_STATUS: Parameter("status"),
-                       bind.MESSAGE: Parameter("message")},
-                      Where=
-                      (bind.RESOURCE_ID == Parameter("resourceID"))
-                      .And(bind.HOME_RESOURCE_ID == Parameter("homeID")))
-
-
-    @classproperty
-    def _idsForInviteUID(cls): #@NoSelf
-        inv = schema.INVITE
-        return Select([inv.RESOURCE_ID, inv.HOME_RESOURCE_ID],
-                      From=inv,
-                      Where=inv.INVITE_UID == Parameter("inviteuid"))
-
-
-    @classproperty
-    def _updateInviteQuery(cls): #@NoSelf
-        """
-        DAL query to update an invitation for a given recipient.
-        """
-        inv = schema.INVITE
-        return Update({inv.NAME: Parameter("name")},
-                      Where=inv.INVITE_UID == Parameter("uid"))
-
-
-    @classproperty
-    def _insertBindQuery(cls): #@NoSelf
-        bind = cls._bindSchema
-        return Insert(
-            {
-                bind.HOME_RESOURCE_ID: Parameter("homeID"),
-                bind.RESOURCE_ID: Parameter("resourceID"),
-                bind.BIND_MODE: Parameter("mode"),
-                bind.BIND_STATUS: Parameter("status"),
-                bind.MESSAGE: Parameter("message"),
-                bind.RESOURCE_NAME: Parameter("resourceName"),
-                bind.SEEN_BY_OWNER: False,
-                bind.SEEN_BY_SHAREE: False,
-            }
-        )
-
-
-    @classproperty
-    def _insertInviteQuery(cls): #@NoSelf
-        inv = schema.INVITE
-        return Insert(
-            {
-                inv.INVITE_UID: Parameter("uid"),
-                inv.NAME: Parameter("name"),
-                inv.HOME_RESOURCE_ID: Parameter("homeID"),
-                inv.RESOURCE_ID: Parameter("resourceID"),
-                inv.RECIPIENT_ADDRESS: Parameter("recipient")
-            }
-        )
-
-
-    @inlineCallbacks
-    def addOrUpdateRecord(self, record):
-        bindMode = {'read-only': _BIND_MODE_READ,
-                    'read-write': _BIND_MODE_WRITE}[record.access]
-        bindStatus = {
-            "NEEDS-ACTION": _BIND_STATUS_INVITED,
-            "ACCEPTED": _BIND_STATUS_ACCEPTED,
-            "DECLINED": _BIND_STATUS_DECLINED,
-            "INVALID": _BIND_STATUS_INVALID,
-        }[record.state]
-        shareeHome = yield self._getHomeWithUID(record.principalUID)
-        rows = yield self._idsForInviteUID.on(self._txn,
-                                              inviteuid=record.inviteuid)
-        
-        # FIXME: Do the BIND table query before the INVITE table query because BIND currently has proper
-        # constraints in place, whereas INVITE does not. Really we need to do this in a sub-transaction so
-        # we can roll back if any one query fails.
-        if rows:
-            [[resourceID, homeResourceID]] = rows
-            yield self._updateBindQuery.on(
-                self._txn,
-                mode=bindMode, status=bindStatus, message=record.summary,
-                resourceID=resourceID, homeID=homeResourceID
-            )
-            yield self._updateInviteQuery.on(
-                self._txn, name=record.name, uid=record.inviteuid
-            )
-        else:
-            yield self._insertBindQuery.on(
-                self._txn,
-                homeID=shareeHome._resourceID,
-                resourceID=self._collection._resourceID,
-                resourceName=record.inviteuid,
-                mode=bindMode,
-                status=bindStatus,
-                message=record.summary
-            )
-            yield self._insertInviteQuery.on(
-                self._txn, uid=record.inviteuid, name=record.name,
-                homeID=shareeHome._resourceID,
-                resourceID=self._collection._resourceID,
-                recipient=record.userid
-            )
-        
-        # Must send notification to ensure cache invalidation occurs
-        self._collection.notifyChanged()
-
-
-    @classmethod
-    def _deleteOneBindQuery(cls, constraint):
-        inv = schema.INVITE
-        bind = cls._bindSchema
-        return Delete(
-            From=bind, Where=(bind.HOME_RESOURCE_ID, bind.RESOURCE_ID) ==
-            Select([inv.HOME_RESOURCE_ID, inv.RESOURCE_ID],
-                   From=inv, Where=constraint))
-
-
-    @classmethod
-    def _deleteOneInviteQuery(cls, constraint):
-        inv = schema.INVITE
-        return Delete(From=inv, Where=constraint)
-
-
-    @classproperty
-    def _deleteBindByUID(cls): #@NoSelf
-        inv = schema.INVITE
-        return cls._deleteOneBindQuery(inv.INVITE_UID == Parameter("uid"))
-
-
-    @classproperty
-    def _deleteInviteByUID(cls): #@NoSelf
-        inv = schema.INVITE
-        return cls._deleteOneInviteQuery(inv.INVITE_UID == Parameter("uid"))
-
-
-    @inlineCallbacks
-    def removeRecordForInviteUID(self, inviteUID):
-        yield self._deleteBindByUID.on(self._txn, uid=inviteUID)
-        yield self._deleteInviteByUID.on(self._txn, uid=inviteUID)
-        
-        # Must send notification to ensure cache invalidation occurs
-        self._collection.notifyChanged()
-
-
-
-class SQLLegacyCalendarInvites(SQLLegacyInvites):
-    """
-    Emulator for the implicit interface specified by
-    L{twistedcaldav.sharing.InvitesDatabase}.
-    """
-
-    _homeTable = CALENDAR_HOME_TABLE
-    _bindTable = CALENDAR_BIND_TABLE
-
-    _homeSchema = schema.CALENDAR_HOME
-    _bindSchema = schema.CALENDAR_BIND
-
-    def _getHomeWithUID(self, uid):
-        return self._txn.calendarHomeWithUID(uid, create=True)
-
-
-
-class SQLLegacyAddressBookInvites(SQLLegacyInvites):
-    """
-    Emulator for the implicit interface specified by
-    L{twistedcaldav.sharing.InvitesDatabase}.
-    """
-
-    _homeTable = ADDRESSBOOK_HOME_TABLE
-    _bindTable = ADDRESSBOOK_BIND_TABLE
-
-    _homeSchema = schema.ADDRESSBOOK_HOME
-    _bindSchema = schema.ADDRESSBOOK_BIND
-
-    def _getHomeWithUID(self, uid):
-        return self._txn.addressbookHomeWithUID(uid, create=True)
-
-
-
-class SQLLegacyShares(object):
-
-    _homeTable = None
-    _bindTable = None
-    _urlTopSegment = None
-
-    _homeSchema = None
-    _bindSchema = None
-
-    def __init__(self, home):
-        self._home = home
-
-
-    @property
-    def _txn(self):
-        return self._home._txn
-
-
-    def _getHomeWithUID(self, uid):
-        raise NotImplementedError()
-
-
-    def create(self):
-        pass
-
-
-    def remove(self):
-        pass
-
-
-    @classproperty
-    def _allSharedToQuery(cls): #@NoSelf
-        bind = cls._bindSchema
-        return Select(
-            [bind.RESOURCE_ID, bind.RESOURCE_NAME,
-             bind.BIND_MODE, bind.MESSAGE],
-            From=bind,
-            Where=(bind.HOME_RESOURCE_ID == Parameter("homeID"))
-            .And(bind.BIND_MODE != _BIND_MODE_OWN)
-            .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
-        )
-
-
-    @classproperty
-    def _inviteUIDByResourceIDsQuery(cls): #@NoSelf
-        inv = schema.INVITE
-        return Select(
-            [inv.INVITE_UID], From=inv, Where=
-            (inv.RESOURCE_ID == Parameter("resourceID"))
-            .And(inv.HOME_RESOURCE_ID == Parameter("homeID"))
-        )
-
-
-    @classproperty
-    def _ownerHomeIDAndName(cls): #@NoSelf
-        bind = cls._bindSchema
-        return Select(
-            [bind.HOME_RESOURCE_ID, bind.RESOURCE_NAME], From=bind, Where=
-            (bind.RESOURCE_ID == Parameter("resourceID"))
-            .And(bind.BIND_MODE == _BIND_MODE_OWN)
-        )
-
-
-    @classproperty
-    def _ownerUIDFromHomeID(cls): #@NoSelf
-        home = cls._homeSchema
-        return Select(
-            [home.OWNER_UID], From=home,
-            Where=home.RESOURCE_ID == Parameter("homeID")
-        )
-
-
-
-
-    @inlineCallbacks
-    def allRecords(self):
-        # This should have been a smart join that got all these columns at
-        # once, but let's not bother to fix it, since the actual query we
-        # _want_ to do (just look for binds in a particular homes) is
-        # much simpler anyway; we should just do that.
-        all = []
-        shareRows = yield self._allSharedToQuery.on(
-            self._txn, homeID=self._home._resourceID)
-        for resourceID, resourceName, bindMode, summary in shareRows:
-            [[ownerHomeID, ownerResourceName]] = yield (
-                self._ownerHomeIDAndName.on(self._txn,
-                                            resourceID=resourceID))
-            [[ownerUID]] = yield self._ownerUIDFromHomeID.on(
-                self._txn, homeID=ownerHomeID)
-            hosturl = '/%s/__uids__/%s/%s' % (
-                self._urlTopSegment, ownerUID, ownerResourceName
-            )
-            localname = resourceName
-            if bindMode != _BIND_MODE_DIRECT:
-                sharetype = 'I'
-                [[shareuid]] = yield self._inviteUIDByResourceIDsQuery.on(
-                    self._txn, resourceID=resourceID,
-                    homeID=self._home._resourceID
-                )
-            else:
-                sharetype = 'D'
-                shareuid = "Direct-%s-%s" % (self._home._resourceID, resourceID,)
-            record = SharedCollectionRecord(
-                shareuid, sharetype, hosturl, localname, summary
-            )
-            all.append(record)
-        returnValue(all)
-
-    def directShareID(self, shareeHome, sharerCollection):
-        return "Direct-%s-%s" % (shareeHome._newStoreHome._resourceID, sharerCollection._newStoreObject._resourceID,)
-
-    @inlineCallbacks
-    def _search(self, **kw):
-        [[key, value]] = kw.items()
-        for record in (yield self.allRecords()):
-            if getattr(record, key) == value:
-                returnValue((record))
-
-
-    def recordForShareUID(self, shareUID):
-        return self._search(shareuid=shareUID)
-
-
-    @classproperty
-    def _updateBindName(cls): #@NoSelf
-        bind = cls._bindSchema
-        return Update({bind.RESOURCE_NAME: Parameter("localname")},
-                      Where=(bind.HOME_RESOURCE_ID == Parameter("homeID"))
-                      .And(bind.RESOURCE_ID == Parameter('resourceID')))
-
-
-    @classproperty
-    def _acceptDirectShareQuery(cls): #@NoSelf
-        bind = cls._bindSchema
-        return Insert({
-            bind.HOME_RESOURCE_ID: Parameter("homeID"),
-            bind.RESOURCE_ID: Parameter("resourceID"), 
-            bind.RESOURCE_NAME: Parameter("name"),
-            bind.MESSAGE: Parameter("message"),
-            bind.BIND_MODE: _BIND_MODE_DIRECT,
-            bind.BIND_STATUS: _BIND_STATUS_ACCEPTED,
-            bind.SEEN_BY_OWNER: True,
-            bind.SEEN_BY_SHAREE: True,
-        })
-
-
-    @inlineCallbacks
-    def addOrUpdateRecord(self, record):
-        # record.hosturl -> /.../__uids__/<uid>/<name>
-        splithost = record.hosturl.split('/')
-
-        # Double-check the path
-        if splithost[2] != "__uids__":
-            raise ValueError(
-                "Sharing URL must be a __uids__ path: %s" % (record.hosturl,))
-
-        ownerUID = splithost[3]
-        ownerCollectionName = splithost[4]
-        ownerHome = yield self._getHomeWithUID(ownerUID)
-        ownerCollection = yield ownerHome.childWithName(ownerCollectionName)
-        collectionResourceID = ownerCollection._resourceID
-
-        if record.sharetype == 'I':
-            # There needs to be a bind already, one that corresponds to the
-            # invitation.  The invitation's UID is the same as the share UID.  I
-            # just need to update its 'localname', i.e.
-            # XXX_BIND.XXX_RESOURCE_NAME.
-
-            yield self._updateBindName.on(
-                self._txn, localname=record.localname,
-                homeID=self._home._resourceID, resourceID=collectionResourceID
-            )
-        elif record.sharetype == 'D':
-            # There is no bind entry already so add one - but be aware of possible race to create
-
-            # Use savepoint so we can do a partial rollback if there is a race condition
-            # where this row has already been inserted
-            savepoint = SavepointAction("addOrUpdateRecord")
-            yield savepoint.acquire(self._txn)
-
-            try:
-                yield self._acceptDirectShareQuery.on(
-                    self._txn, homeID=self._home._resourceID,
-                    resourceID=collectionResourceID, name=record.localname,
-                    message=record.summary
-                )
-            except Exception: # FIXME: Really want to trap the pg.DatabaseError but in a non-DB specific manner
-                yield savepoint.rollback(self._txn)
-
-                # For now we will assume that the insert already done is the winner - so nothing more to do here
-            else:
-                yield savepoint.release(self._txn)
-
-        shareeCollection = yield self._home.sharedChildWithName(record.localname)
-        yield shareeCollection._initSyncToken()
-
-
-    @classproperty
-    def _unbindShareQuery(cls): #@NoSelf
-        bind = cls._bindSchema
-        return Update({
-            bind.BIND_STATUS: _BIND_STATUS_DECLINED
-        }, Where=(bind.RESOURCE_NAME == Parameter("name"))
-        .And(bind.HOME_RESOURCE_ID == Parameter("homeID")))
-
-
-    @inlineCallbacks
-    def removeRecordForLocalName(self, localname):
-        record = yield self.recordForLocalName(localname)
-        shareeCollection = yield self._home.sharedChildWithName(record.localname)
-        yield shareeCollection._deletedSyncToken(sharedRemoval=True)
-
-        result = yield self._unbindShareQuery.on(self._txn, name=localname,
-                                                 homeID=self._home._resourceID)
-        returnValue(result)
-
-
-    @classproperty
-    def _removeInviteShareQuery(cls): #@NoSelf
-        """
-        DAL query to remove a non-direct share by invite UID.
-        """
-        bind = cls._bindSchema
-        inv = schema.INVITE
-        return Update(
-            {bind.BIND_STATUS: _BIND_STATUS_DECLINED},
-            Where=(bind.HOME_RESOURCE_ID, bind.RESOURCE_ID) ==
-            Select([inv.HOME_RESOURCE_ID, inv.RESOURCE_ID],
-                   From=inv, Where=inv.INVITE_UID == Parameter("uid")))
-
-
-    @classproperty
-    def _removeDirectShareQuery(cls): #@NoSelf
-        """
-        DAL query to remove a direct share by its homeID and resourceID.
-        """
-        bind = cls._bindSchema
-        return Delete(From=bind,
-                      Where=(bind.HOME_RESOURCE_ID == Parameter("homeID"))
-                      .And(bind.RESOURCE_ID == Parameter("resourceID")))
-
-
-    @inlineCallbacks
-    def removeRecordForShareUID(self, shareUID):
-
-        record = yield self.recordForShareUID(shareUID)
-        shareeCollection = yield self._home.sharedChildWithName(record.localname)
-        yield shareeCollection._deletedSyncToken(sharedRemoval=True)
-
-        if not shareUID.startswith("Direct"):
-            yield self._removeInviteShareQuery.on(self._txn, uid=shareUID)
-        else:
-            # Extract pieces from synthesised UID
-            homeID, resourceID = shareUID[len("Direct-"):].split("-")
-            # Now remove the binding for the direct share
-            yield self._removeDirectShareQuery.on(
-                self._txn, homeID=homeID, resourceID=resourceID)
-
-
-class SQLLegacyCalendarShares(SQLLegacyShares):
-    """
-    Emulator for the implicit interface specified by
-    L{twistedcaldav.sharing.InvitesDatabase}.
-    """
-
-    _homeTable = CALENDAR_HOME_TABLE
-    _bindTable = CALENDAR_BIND_TABLE
-    _homeSchema = schema.CALENDAR_HOME
-    _bindSchema = schema.CALENDAR_BIND
-    _urlTopSegment = "calendars"
-
-
-    def _getHomeWithUID(self, uid):
-        return self._txn.calendarHomeWithUID(uid, create=True)
-
-
-
-class SQLLegacyAddressBookShares(SQLLegacyShares):
-    """
-    Emulator for the implicit interface specified by
-    L{twistedcaldav.sharing.InvitesDatabase}.
-    """
-
-    _homeTable = ADDRESSBOOK_HOME_TABLE
-    _bindTable = ADDRESSBOOK_BIND_TABLE
-    _homeSchema = schema.ADDRESSBOOK_HOME
-    _bindSchema = schema.ADDRESSBOOK_BIND
-    _urlTopSegment = "addressbooks"
-
-
-    def _getHomeWithUID(self, uid):
-        return self._txn.addressbookHomeWithUID(uid, create=True)
-
-
-
 class MemcachedUIDReserver(CachePoolUserMixIn, LoggingMixIn):
     def __init__(self, index, cachePool=None):
         self.index = index

Modified: CalendarServer/trunk/txdav/common/icommondatastore.py
===================================================================
--- CalendarServer/trunk/txdav/common/icommondatastore.py	2012-09-26 21:58:22 UTC (rev 9864)
+++ CalendarServer/trunk/txdav/common/icommondatastore.py	2012-09-27 00:06:04 UTC (rev 9865)
@@ -246,20 +246,3 @@
     A collection resource which may be shared.
     """
 
-    def setSharingUID(shareeUID):
-        """
-        This is a temporary shim method due to the way L{twistedcaldav.sharing}
-        works, which is that it expects to look in the 'sharesDB' object to
-        find what calendars are shared by whom, separately looks up the owner's
-        calendar home based on that information, then sets the sharee's UID on
-        that calendar, the main effect of which is to change the per-user uid
-        of the properties for that calendar object.
-
-        What I{should} be happening is that the calendars just show up in the
-        sharee's calendar home, and have a separate methods to determine the
-        sharee's and the owner's calendar homes, so the front end can tell it's
-        shared.
-
-        @param shareeUID: the UID of the sharee.
-        @type shareeUID: C{str}
-        """
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120926/ab0adb58/attachment-0001.html>


More information about the calendarserver-changes mailing list