[CalendarServer-changes] [4090] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Apr 27 09:14:20 PDT 2009


Revision: 4090
          http://trac.macosforge.org/projects/calendarserver/changeset/4090
Author:   cdaboo at apple.com
Date:     2009-04-27 09:14:20 -0700 (Mon, 27 Apr 2009)
Log Message:
-----------
New schedule-changes XML schema and tests.

Modified Paths:
--------------
    CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.txt
    CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.xml
    CalendarServer/trunk/run
    CalendarServer/trunk/twistedcaldav/customxml.py
    CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
    CalendarServer/trunk/twistedcaldav/scheduling/implicit.py
    CalendarServer/trunk/twistedcaldav/scheduling/itip.py
    CalendarServer/trunk/twistedcaldav/scheduling/processing.py
    CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py

Modified: CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.txt
===================================================================
--- CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.txt	2009-04-27 16:13:04 UTC (rev 4089)
+++ CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.txt	2009-04-27 16:14:20 UTC (rev 4090)
@@ -3,7 +3,7 @@
 
 Calendar Server Extension                                       C. Daboo
                                                                    Apple
-                                                       February 28, 2009
+                                                          April 26, 2009
 
 
        Change Indicators for Processed CalDAV Scheduling Messages
@@ -25,16 +25,17 @@
    4.  New features  . . . . . . . . . . . . . . . . . . . . . . . . . 3
      4.1.  CalDAV Changes  . . . . . . . . . . . . . . . . . . . . . . 3
        4.1.1.  Change Indicator WebDAV Property  . . . . . . . . . . . 3
-       4.1.2.  CS:schedule-changes XML element . . . . . . . . . . . . 5
-         4.1.2.1.  CS:dtstamp XML Element  . . . . . . . . . . . . . . 5
-         4.1.2.2.  CS:action XML Element . . . . . . . . . . . . . . . 5
-         4.1.2.3.  CS:changes XML Element  . . . . . . . . . . . . . . 6
-         4.1.2.4.  CS:recurrences XML Element  . . . . . . . . . . . . 7
-   5.  Security Considerations . . . . . . . . . . . . . . . . . . . . 7
-   6.  IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 7
-   7.  Normative References  . . . . . . . . . . . . . . . . . . . . . 7
-   Appendix A.  Acknowledgments  . . . . . . . . . . . . . . . . . . . 8
-   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . . . 8
+       4.1.2.  CS:schedule-changes XML element . . . . . . . . . . . . 6
+         4.1.2.1.  CS:dtstamp XML Element  . . . . . . . . . . . . . . 6
+         4.1.2.2.  CS:action XML Element . . . . . . . . . . . . . . . 6
+         4.1.2.3.  CS:recurrence XML Element . . . . . . . . . . . . . 7
+         4.1.2.4.  CS:changes XML Element  . . . . . . . . . . . . . . 8
+   5.  Security Considerations . . . . . . . . . . . . . . . . . . . . 8
+   6.  IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 8
+   7.  Normative References  . . . . . . . . . . . . . . . . . . . . . 8
+   Appendix A.  Acknowledgments  . . . . . . . . . . . . . . . . . . . 9
+   Appendix B.  Change History . . . . . . . . . . . . . . . . . . . . 9
+   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . . . 9
 
 
 
@@ -51,10 +52,9 @@
 
 
 
-
 Daboo                                                           [Page 1]
 
-                   CalDAV Scheduling Change Indicators     February 2009
+                   CalDAV Scheduling Change Indicators        April 2009
 
 
 1.  Introduction
@@ -110,7 +110,7 @@
 
 Daboo                                                           [Page 2]
 
-                   CalDAV Scheduling Change Indicators     February 2009
+                   CalDAV Scheduling Change Indicators        April 2009
 
 
    create an XML data value (as described next) and store that in the
@@ -166,7 +166,7 @@
 
 Daboo                                                           [Page 3]
 
-                   CalDAV Scheduling Change Indicators     February 2009
+                   CalDAV Scheduling Change Indicators        April 2009
 
 
        <!ELEMENT schedule-changes
@@ -181,83 +181,139 @@
        <!ELEMENT create EMPTY>
        <!-- New calendar object was created -->
 
-       <!ELEMENT update (changes, recurrences?)>
+       <!ELEMENT update (recurrence+)>
        <!-- Calendar object was changed -->
 
-       <!ELEMENT cancel (recurrences?)>
-       <!-- Calendar object or instances were cancelled -->
+       <!ELEMENT cancel (recurrence*)>
+       <!-- Calendar object was cancelled -->
 
-       <!ELEMENT reply (attendee, partstat?, private-comment?,
-                        recurrences?)>
+       <!ELEMENT reply (attendee, recurrence+)>
        <!-- Reply received from attendee -->
 
-       <!ELEMENT attendee CDATA>
-       <!-- ATTENDEE iCalendar property value -->
+       <!ELEMENT recurrence
+           ((master | recurrenceid), changes)>
+       <!-- Which instances were affected by the change,
+            and details on the per-instance changes -->
 
-       <!ELEMENT partstat EMPTY>
-       <!-- ATTENDEE PARTSTAT property parameter value changed -->
+       <!ELEMENT master EMPTY>
+       <!-- The "master" instance was affected -->
 
-       <!ELEMENT private-comment EMPTY>
-       <!-- X-CALENDARSERVER-PRIVATE-COMMENT property value
-            changed -->
+       <!ELEMENT recurrenceid CDATA>
+       <!-- RECURRENCE-ID value for the affected instance -->
 
        <!ELEMENT changes changed-property*>
+       <!-- Detailed changes in the iCalendar data -->
+
+       <!ELEMENT changed-property changed-parameter*>
        <!ATTLIST changed-property name PCDATA>
+       <!-- An iCalendar property changed -->
 
-       <!ELEMENT changed-property changed-parameter*>
+       <!ELEMENT changed-parameter EMPTY>
        <!ATTLIST changed-parameter name PCDATA>
+       <!-- An iCalendar property parameter changed -->
 
-       <!ELEMENT recurrences (master?, recurrenceid*)>
-       <!-- Which instances were affected by the change -->
+       <!ELEMENT attendee CDATA>
+       <!-- ATTENDEE iCalendar property value -->
 
-       <!ELEMENT master EMPTY>
-       <!-- The "master" instance was affected -->
 
-       <!ELEMENT recurrenceid CDATA>
-       <!-- RECURRENCE-ID value for the affected instance -->
 
 
 
 
-
 Daboo                                                           [Page 4]
 
-                   CalDAV Scheduling Change Indicators     February 2009
+                   CalDAV Scheduling Change Indicators        April 2009
 
 
-   Example:
+   Example:  This example indicates that a new calendar component was
+      created.
 
    <CS:schedule-changes
         xmlns:CS="http://calendarserver.org/ns/">
      <CS:dtstamp>20080818T223423Z</CS:dtstamp>
-     <CS:action><CS:create/></CS:action>
+     <CS:action>
+       <CS:create/>
+     </CS:action>
    </CS:schedule-changes>
 
-   Example:
+   Example:  This example indicates that a non-recurring component, or
+      the master component in a recurring component, was changed and
+      that the change was to the "SUMMARY" iCalendar property.
 
    <CS:schedule-changes
         xmlns:CS="http://calendarserver.org/ns/">
      <CS:dtstamp>20080818T223423Z</CS:dtstamp>
      <CS:action>
        <CS:update>
-         <CS:changes>
-           <CS:changed-property name="SUMMARY"/>
-         </CS:changes>
-         <CS:recurrences/>
+         <CS:recurrence>
+           <CS:master/>
+           <CS:changes>
+             <CS:changed-property name="SUMMARY"/>
+           </CS:changes>
+         <CS:recurrence/>
        </CS:update>
      </CS:action>
    </CS:schedule-changes>
 
+   Example:  This example indicates that two recurrence instances were
+      cancelled from a recurring component.
+
+   <CS:schedule-changes
+        xmlns:CS="http://calendarserver.org/ns/">
+     <CS:dtstamp>20080818T223423Z</CS:dtstamp>
+     <CS:action>
+       <CS:cancel>
+         <CS:recurrence>
+           <CS:recurrence-id>20090101T010000Z</CS:recurrence-id>
+         <CS:recurrence/>
+         <CS:recurrence>
+           <CS:recurrence-id>20090102T010000Z</CS:recurrence-id>
+         <CS:recurrence/>
+       </CS:update>
+     </CS:action>
+   </CS:schedule-changes>
+
+
+
+
+Daboo                                                           [Page 5]
+
+                   CalDAV Scheduling Change Indicators        April 2009
+
+
+   Example:  This example indicates that the Attendee with calendar user
+      address "mailto:cyrus at example.com" replied to the Organizer and
+      changed their "PARTSTAT" iCalendar property parameter on one
+      recurrence instance.
+
+   <CS:schedule-changes
+        xmlns:CS="http://calendarserver.org/ns/">
+     <CS:dtstamp>20080818T223423Z</CS:dtstamp>
+     <CS:action>
+       <CS:reply>
+         <CS:attendee>mailto:cyrus at example.com</CS:attendee>
+         <CS:recurrence>
+           <CS:recurrence-id>20090101T010000Z</CS:recurrence-id>
+           <CS:changes>
+             <CS:changed-property name="ATTENDEE">
+               <CS:changed-parameter name="PARTSTAT"/>
+             </CS:changed-property>
+           </CS:changes>
+         <CS:recurrence/>
+       </CS:update>
+     </CS:action>
+   </CS:schedule-changes>
+
 4.1.2.  CS:schedule-changes XML element
 
    The CS:schedule-changes XML element is used to indicate what changes
    were made when the server automatically processed a scheduling
-   message.  There are four child elements that can appear, and each is
+   message.  There are two child elements that can appear, and each is
    described next.
 
 4.1.2.1.  CS:dtstamp XML Element
 
-   This elements contains a text value in the form of an iCalendar Date-
+   This element contains a text value in the form of an iCalendar Date-
    Time value in UTC.  This value is the time at which the automatic
    processing took place.
 
@@ -276,9 +332,9 @@
 
 
 
-Daboo                                                           [Page 5]
+Daboo                                                           [Page 6]
 
-                   CalDAV Scheduling Change Indicators     February 2009
+                   CalDAV Scheduling Change Indicators        April 2009
 
 
    +-----------+-------------------------------------------------------+
@@ -288,79 +344,84 @@
    | CS:create | A new calendar object was created in the default      |
    |           | calendar of the recipient.                            |
    |           |                                                       |
-   | CS:update | An update to an existing calendar object occurred.    |
-   |           | The CS:changes and CS:recurrences child elements      |
-   |           | indicate what the changes were and which instances    |
-   |           | were affected.  If the calendar object is not         |
-   |           | recurring, CS:recurrences MUST NOT be present.  If    |
-   |           | all or any individual instances of a recurring        |
-   |           | calendar object were affected, then CS:recurrences    |
-   |           | MUST be present and indicate which instances were     |
-   |           | affected.                                             |
+   | CS:update | An update to an existing calendar object occurred.  A |
+   |           | CS:recurrence element is included for each recurrence |
+   |           | instance changed.  Each CS:recurrence element         |
+   |           | indicates the specific instance that was changes as   |
+   |           | well as details on which properties or parameters     |
+   |           | changed.                                              |
    |           |                                                       |
    | CS:cancel | A cancellation scheduling message was processed.  If  |
    |           | the calendar object is not recurring or all instances |
-   |           | are being removed, then CS:recurrences MUST NOT be    |
-   |           | present.  If any individual instances of a recurring  |
-   |           | calendar object were affected, then CS:recurrences    |
-   |           | MUST be present and indicate which instances were     |
-   |           | affected.                                             |
+   |           | are being removed, then there MUST NOT be any         |
+   |           | CS:recurrence element present.  If any individual     |
+   |           | instances of a recurring calendar object were         |
+   |           | affected, then a CS:recurrence element MUST be        |
+   |           | present and indicate which instances were affected.   |
    |           |                                                       |
    | CS:reply  | An Attendee's reply was processed.  The CS:attendee,  |
-   |           | CS:partstat and CS:private-comment elements indicate  |
-   |           | which Attendee replied, whether their "PARTSTAT"      |
-   |           | changed, and whether any private comment was changed. |
-   |           | The CS:partstat and CS:private-comment child elements |
-   |           | MUST only be present if the relevant properties or    |
-   |           | parameters were changed.  If the calendar object is   |
-   |           | not recurring, CS:recurrences MUST NOT be present.    |
-   |           | If all or any individual instances of a recurring     |
-   |           | calendar object were affected, then CS:recurrences    |
-   |           | MUST be present and indicate which instances were     |
-   |           | affected..                                            |
+   |           | element indicates which Attendee replied.  The        |
+   |           | CS:recurrence element indicates which recurrence      |
+   |           | instance was changed and whether the change was to    |
+   |           | the Attendee's PARTSTAT parameter or                  |
+   |           | X-CALENDARSERVER-PRIVATE-COMMENT property.            |
    +-----------+-------------------------------------------------------+
 
-4.1.2.3.  CS:changes XML Element
+4.1.2.3.  CS:recurrence XML Element
 
-   This element indicates the key changes that took place.  The child
-   element CS:changed-property lists all the properties in all instances
-   that changed, with the name attribute on each element indicating
-   which iCalendar property changed.  There MUST only be one CD:changed-
-   property element for a specific name attribute value, i.e. if
-   multiple properties of the same name changed, only one CS:changed-
-   property will appear.
-
-
-
-Daboo                                                           [Page 6]
-
-                   CalDAV Scheduling Change Indicators     February 2009
-
-
-   For each CD:changed-property element, if any parameters were changed
-   on the corresponding properties, then those should be includes as
-   child elements CD:changed-parameter, with the name attribute on those
-   elements containing the name of the parameter changed.  As with CS:
-   changed-proeprties, there MUST only be one CS:changed-parameter
-   element for each iCalendar parameter that changed.
-
-4.1.2.4.  CS:recurrences XML Element
-
    This element indicates which instances were affected by a change:
 
    +-----------------+-------------------------------------------------+
    | Child Element   | Description                                     |
    +-----------------+-------------------------------------------------+
    | CS:master       | The "master" component defining the recurrence  |
-   |                 | pattern was changed.                            |
+   |                 | pattern was changed, or a non-recurring         |
+   |                 | component was changed.                          |
    |                 |                                                 |
    | CS:recurrenceid | The instance with the specified "RECURRENCE-ID" |
    |                 | value was changed.                              |
+   |                 |                                                 |
+   | CS:changes      | Detailed changes - see next section.  This      |
+   |                 | element is not present when processing a        |
+   |                 | "CANCEL".                                       |
    +-----------------+-------------------------------------------------+
 
-   If no child elements were specified, then all instances were changed.
 
 
+Daboo                                                           [Page 7]
+
+                   CalDAV Scheduling Change Indicators        April 2009
+
+
+4.1.2.4.  CS:changes XML Element
+
+   This element indicates the key changes that took place.
+
+   +---------------------+---------------------------------------------+
+   | Child Element       | Description                                 |
+   +---------------------+---------------------------------------------+
+   | CS:changed-property | Indicates which iCalendar property changed. |
+   |                     | The "name" attribute on the XML element is  |
+   |                     | the name of the iCalendar property that     |
+   |                     | changed.  There MUST only be one            |
+   |                     | CS:changed-property element for a specific  |
+   |                     | name attribute value, i.e. if multiple      |
+   |                     | properties of the same name changed, only   |
+   |                     | one CS:changed-property will appear.  For   |
+   |                     | each CS:changed-property element, if any    |
+   |                     | property parameters were changed on the     |
+   |                     | corresponding properties, then those should |
+   |                     | be included as CS:changed-parameter child   |
+   |                     | elements, with the "name" attribute on      |
+   |                     | those elements containing the name of the   |
+   |                     | iCalendar property parameter changed.  As   |
+   |                     | with CS:changed-property, there MUST only   |
+   |                     | be one CS:changed-parameter element for     |
+   |                     | each iCalendar property parameter that      |
+   |                     | changed.                                    |
+   +---------------------+---------------------------------------------+
+
+
 5.  Security Considerations
 
    TODO:
@@ -381,18 +442,17 @@
    [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
               Requirement Levels", BCP 14, RFC 2119, March 1997.
 
-   [RFC2445]  Dawson, F. and Stenerson, D., "Internet Calendaring and
-              Scheduling Core Object Specification (iCalendar)",
-              RFC 2445, November 1998.
 
 
+Daboo                                                           [Page 8]
+
+                   CalDAV Scheduling Change Indicators        April 2009
 
 
-Daboo                                                           [Page 7]
-
-                   CalDAV Scheduling Change Indicators     February 2009
+   [RFC2445]  Dawson, F. and Stenerson, D., "Internet Calendaring and
+              Scheduling Core Object Specification (iCalendar)",
+              RFC 2445, November 1998.
 
-
    [RFC2446]  Silverberg, S., Mansour, S., Dawson, F., and R. Hopson,
               "iCalendar Transport-Independent Interoperability Protocol
               (iTIP) Scheduling Events, BusyTime, To-dos and Journal
@@ -412,6 +472,19 @@
    calendar server and client teams.
 
 
+Appendix B.  Change History
+
+   Changes in -03
+
+   1.  Re-worked XML schema to allow for per-instance changes to be
+       indicated.
+
+   Changes in -02
+
+   1.  CS:changes element changed to use CS:changed-property child
+       elements for more detailed information.
+
+
 Author's Address
 
    Cyrus Daboo
@@ -427,22 +500,5 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Daboo                                                           [Page 8]
+Daboo                                                           [Page 9]
 

Modified: CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.xml
===================================================================
--- CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.xml	2009-04-27 16:13:04 UTC (rev 4089)
+++ CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.xml	2009-04-27 16:14:20 UTC (rev 4090)
@@ -17,7 +17,7 @@
 <?rfc compact="yes"?>
 <?rfc subcompact="no"?>
 <?rfc private="Calendar Server Extension"?>
-<rfc ipr="none" docName='caldav-schedulingchanges-02'>
+<rfc ipr="none" docName='caldav-schedulingchanges-03'>
     <front>
         <title abbrev="CalDAV Scheduling Change Indicators">Change Indicators for Processed CalDAV Scheduling Messages</title> 
         <author initials="C." surname="Daboo" fullname="Cyrus Daboo">
@@ -109,56 +109,59 @@
     <!ELEMENT create EMPTY>
     <!-- New calendar object was created -->
 
-    <!ELEMENT update (changes, recurrences?)>
+    <!ELEMENT update (recurrence+)>
     <!-- Calendar object was changed -->
 
-    <!ELEMENT cancel (recurrences?)>
-    <!-- Calendar object or instances were cancelled -->
+    <!ELEMENT cancel (recurrence*)>
+    <!-- Calendar object was cancelled -->
 
-    <!ELEMENT reply (attendee, partstat?, private-comment?,
-                     recurrences?)>
+    <!ELEMENT reply (attendee, recurrence+)>
     <!-- Reply received from attendee -->
 
-    <!ELEMENT attendee CDATA>
-    <!-- ATTENDEE iCalendar property value -->
+    <!ELEMENT recurrence
+        ((master | recurrenceid), changes)>
+    <!-- Which instances were affected by the change,
+         and details on the per-instance changes -->
 
-    <!ELEMENT partstat EMPTY>
-    <!-- ATTENDEE PARTSTAT property parameter value changed -->
+    <!ELEMENT master EMPTY>
+    <!-- The "master" instance was affected -->
 
-    <!ELEMENT private-comment EMPTY>
-    <!-- X-CALENDARSERVER-PRIVATE-COMMENT property value
-         changed -->
+    <!ELEMENT recurrenceid CDATA>
+    <!-- RECURRENCE-ID value for the affected instance -->
 
     <!ELEMENT changes changed-property*>
+    <!-- Detailed changes in the iCalendar data -->
+
+    <!ELEMENT changed-property changed-parameter*>
     <!ATTLIST changed-property name PCDATA>
+    <!-- An iCalendar property changed -->
 
-    <!ELEMENT changed-property changed-parameter*>
+    <!ELEMENT changed-parameter EMPTY>
     <!ATTLIST changed-parameter name PCDATA>
+    <!-- An iCalendar property parameter changed -->
 
-    <!ELEMENT recurrences (master?, recurrenceid*)>
-    <!-- Which instances were affected by the change -->
+    <!ELEMENT attendee CDATA>
+    <!-- ATTENDEE iCalendar property value -->
 
-    <!ELEMENT master EMPTY>
-    <!-- The "master" instance was affected -->
-
-    <!ELEMENT recurrenceid CDATA>
-    <!-- RECURRENCE-ID value for the affected instance -->
-
                    ]]></artwork>
                             </figure>
                         </t>
                         <t hangText="Example:">
+                           This example indicates that a new calendar component was created.
                             <figure>
                                 <artwork><![CDATA[
 <CS:schedule-changes
      xmlns:CS="http://calendarserver.org/ns/">
   <CS:dtstamp>20080818T223423Z</CS:dtstamp>
-  <CS:action><CS:create/></CS:action>
+  <CS:action>
+    <CS:create/>
+  </CS:action>
 </CS:schedule-changes>
                    ]]></artwork>
                             </figure>
                         </t>
                         <t hangText="Example:">
+                          This example indicates that a non-recurring component, or the master component in a recurring component, was changed and that the change was to the "SUMMARY" iCalendar property.
                             <figure>
                                 <artwork><![CDATA[
 <CS:schedule-changes
@@ -166,24 +169,71 @@
   <CS:dtstamp>20080818T223423Z</CS:dtstamp>
   <CS:action>
     <CS:update>
-      <CS:changes>
-        <CS:changed-property name="SUMMARY"/>
-      </CS:changes>
-      <CS:recurrences/>
+      <CS:recurrence>
+        <CS:master/>
+        <CS:changes>
+          <CS:changed-property name="SUMMARY"/>
+        </CS:changes>
+      <CS:recurrence/>
     </CS:update>
   </CS:action>
 </CS:schedule-changes>
                    ]]></artwork>
                             </figure>
                         </t>
+                        <t hangText="Example:">
+                          This example indicates that two recurrence instances were cancelled from a recurring component.
+                            <figure>
+                                <artwork><![CDATA[
+<CS:schedule-changes
+     xmlns:CS="http://calendarserver.org/ns/">
+  <CS:dtstamp>20080818T223423Z</CS:dtstamp>
+  <CS:action>
+    <CS:cancel>
+      <CS:recurrence>
+        <CS:recurrence-id>20090101T010000Z</CS:recurrence-id>
+      <CS:recurrence/>
+      <CS:recurrence>
+        <CS:recurrence-id>20090102T010000Z</CS:recurrence-id>
+      <CS:recurrence/>
+    </CS:update>
+  </CS:action>
+</CS:schedule-changes>
+                   ]]></artwork>
+                            </figure>
+                        </t>
+                        <t hangText="Example:">
+                          This example indicates that the Attendee with calendar user address "mailto:cyrus at example.com" replied to the Organizer and changed their "PARTSTAT" iCalendar property parameter on one recurrence instance.
+                            <figure>
+                                <artwork><![CDATA[
+<CS:schedule-changes
+     xmlns:CS="http://calendarserver.org/ns/">
+  <CS:dtstamp>20080818T223423Z</CS:dtstamp>
+  <CS:action>
+    <CS:reply>
+      <CS:attendee>mailto:cyrus at example.com</CS:attendee>
+      <CS:recurrence>
+        <CS:recurrence-id>20090101T010000Z</CS:recurrence-id>
+        <CS:changes>
+          <CS:changed-property name="ATTENDEE">
+            <CS:changed-parameter name="PARTSTAT"/>
+          </CS:changed-property>
+        </CS:changes>
+      <CS:recurrence/>
+    </CS:update>
+  </CS:action>
+</CS:schedule-changes>
+                   ]]></artwork>
+                            </figure>
+                        </t>
                     </list>
 <?rfc compact="yes" ?>
                 </t>
                 </section>
                 <section title="CS:schedule-changes XML element">
-                  <t>The CS:schedule-changes XML element is used to indicate what changes were made when the server automatically processed a scheduling message. There are four child elements that can appear, and each is described next.</t>
+                  <t>The CS:schedule-changes XML element is used to indicate what changes were made when the server automatically processed a scheduling message. There are two child elements that can appear, and each is described next.</t>
                   <section title="CS:dtstamp XML Element">
-                    <t>This elements contains a text value in the form of an iCalendar Date-Time value in UTC. This value is the time at which the automatic processing took place.</t>
+                    <t>This element contains a text value in the form of an iCalendar Date-Time value in UTC. This value is the time at which the automatic processing took place.</t>
                   </section>
                   <section title="CS:action XML Element">
                     <t>This element indicates the nature of the changes that took place:</t>
@@ -198,42 +248,54 @@
                         <c>&nbsp;</c>
 
                         <c>CS:update</c>
-                        <c>An update to an existing calendar object occurred. The CS:changes and CS:recurrences child elements indicate what the changes were and which instances were affected. If the calendar object is not recurring, CS:recurrences MUST NOT be present. If all or any individual instances of a recurring calendar object were affected, then CS:recurrences MUST be present and indicate which instances were affected.</c>
+                        <c>An update to an existing calendar object occurred.
+                        A CS:recurrence element is included for each recurrence instance changed. Each CS:recurrence element indicates the specific instance that was changes as well as details on which properties or parameters changed.</c>
                         
                         <c>&nbsp;</c>
                         <c>&nbsp;</c>
                         
                         <c>CS:cancel</c>
-                        <c>A cancellation scheduling message was processed. If the calendar object is not recurring or all instances are being removed, then CS:recurrences MUST NOT be present. If any individual instances of a recurring calendar object were affected, then CS:recurrences MUST be present and indicate which instances were affected.</c>
+                        <c>A cancellation scheduling message was processed. If the calendar object is not recurring or all instances are being removed, then there MUST NOT be any CS:recurrence element present. If any individual instances of a recurring calendar object were affected, then a CS:recurrence element MUST be present and indicate which instances were affected.</c>
                         
                         <c>&nbsp;</c>
                         <c>&nbsp;</c>
                         
                         <c>CS:reply</c>
-                        <c>An Attendee's reply was processed. The CS:attendee, CS:partstat and CS:private-comment elements indicate which Attendee replied, whether their "PARTSTAT" changed, and whether any private comment was changed. The CS:partstat and CS:private-comment child elements MUST only be present if the relevant properties or parameters were changed. If the calendar object is not recurring, CS:recurrences MUST NOT be present. If all or any individual instances of a recurring calendar object were affected, then CS:recurrences MUST be present and indicate which instances were affected..</c>
+                        <c>An Attendee's reply was processed. The CS:attendee, element indicates which Attendee replied. The CS:recurrence element indicates which recurrence instance was changed and whether the change was to the Attendee's PARTSTAT parameter or X-CALENDARSERVER-PRIVATE-COMMENT property.</c>
                     </texttable>
                   </section>
-                  <section title="CS:changes XML Element">
-                    <t>This element indicates the key changes that took place. The child element CS:changed-property lists all the properties in all instances that changed, with the name attribute on each element indicating which iCalendar property changed. There MUST only be one CD:changed-property element for a specific name attribute value, i.e. if multiple properties of the same name changed, only one CS:changed-property will appear.</t>
-                    <t>For each CD:changed-property element, if any parameters were changed on the corresponding properties, then those should be includes as child elements CD:changed-parameter, with the name attribute on those elements containing the name of the parameter changed. As with CS:changed-proeprties, there MUST only be one CS:changed-parameter element for each iCalendar parameter that changed.</t>
-                  </section>
-                  <section title="CS:recurrences XML Element">
+                  <section title="CS:recurrence XML Element">
                     <t>This element indicates which instances were affected by a change:</t>
                     <texttable>
                         <ttcol>Child Element</ttcol>
                         <ttcol>Description</ttcol>
                         
                         <c>CS:master</c>
-                        <c>The "master" component defining the recurrence pattern was changed.</c>
+                        <c>The "master" component defining the recurrence pattern was changed, or a non-recurring component was changed.</c>
                         
                         <c>&nbsp;</c>
                         <c>&nbsp;</c>
 
                         <c>CS:recurrenceid</c>
                         <c>The instance with the specified "RECURRENCE-ID" value was changed.</c>
+                        
+                        <c>&nbsp;</c>
+                        <c>&nbsp;</c>
+
+                        <c>CS:changes</c>
+                        <c>Detailed changes - see next section. This element is not present when processing a "CANCEL".</c>
                     </texttable>
-                    <t>If no child elements were specified, then all instances were changed.</t>
                   </section>
+                  <section title="CS:changes XML Element">
+                    <t>This element indicates the key changes that took place.</t>
+                    <texttable>
+                        <ttcol>Child Element</ttcol>
+                        <ttcol>Description</ttcol>
+                        
+                        <c>CS:changed-property</c>
+                        <c>Indicates which iCalendar property changed. The "name" attribute on the XML element is the name of the iCalendar property that changed. There MUST only be one CS:changed-property element for a specific name attribute value, i.e. if multiple properties of the same name changed, only one CS:changed-property will appear. For each CS:changed-property element, if any property parameters were changed on the corresponding properties, then those should be included as CS:changed-parameter child elements, with the "name" attribute on those elements containing the name of the iCalendar property parameter changed. As with CS:changed-property, there MUST only be one CS:changed-parameter element for each iCalendar property parameter that changed.</c>
+                    </texttable>
+                  </section>
                 </section>
             </section>
         </section>
@@ -265,14 +327,17 @@
                 This specification is the result of discussions between the Apple calendar server and client teams.
             </t>
         </section>
-        <!--
         <section title='Change History'>
-          <t>Changes since -00
+          <t>Changes in -03
             <list style='numbers'>
-              <t></t>
+              <t>Re-worked XML schema to allow for per-instance changes to be indicated.</t>
             </list>
           </t>
+          <t>Changes in -02
+            <list style='numbers'>
+              <t>CS:changes element changed to use CS:changed-property child elements for more detailed information.</t>
+            </list>
+          </t>
         </section>
-        -->
     </back>
 </rfc>

Modified: CalendarServer/trunk/run
===================================================================
--- CalendarServer/trunk/run	2009-04-27 16:13:04 UTC (rev 4089)
+++ CalendarServer/trunk/run	2009-04-27 16:14:20 UTC (rev 4090)
@@ -724,7 +724,7 @@
 
 caldavtester="${top}/CalDAVTester";
 
-svn_get "CalDAVTester" "${caldavtester}" "${svn_uri_base}/CalDAVTester/trunk" 4075;
+svn_get "CalDAVTester" "${caldavtester}" "${svn_uri_base}/CalDAVTester/trunk" 4088;
 
 #
 # PyFlakes

Modified: CalendarServer/trunk/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/customxml.py	2009-04-27 16:13:04 UTC (rev 4089)
+++ CalendarServer/trunk/twistedcaldav/customxml.py	2009-04-27 16:14:20 UTC (rev 4090)
@@ -463,8 +463,7 @@
     namespace = calendarserver_namespace
     name = "update"
     allowed_children = {
-        (calendarserver_namespace, "changes" )     : (1, 1),
-        (calendarserver_namespace, "recurrences" ) : (0, 1),
+        (calendarserver_namespace, "recurrence" ) : (1, None),
     }
 
 class Cancel (davxml.WebDAVElement):
@@ -474,7 +473,7 @@
     namespace = calendarserver_namespace
     name = "cancel"
     allowed_children = {
-        (calendarserver_namespace, "recurrences" ) : (0, 1),
+        (calendarserver_namespace, "recurrence" ) : (0, 1),
     }
 
 class Reply (davxml.WebDAVElement):
@@ -485,30 +484,34 @@
     name = "reply"
     allowed_children = {
         (calendarserver_namespace, "attendee" )        : (1, 1),
-        (calendarserver_namespace, "partstat" )        : (0, 1),
-        (calendarserver_namespace, "private-comment" ) : (0, 1),
+        (calendarserver_namespace, "recurrence" )      : (1, None),
     }
 
-class Attendee (davxml.WebDAVTextElement):
+class Recurrence (davxml.WebDAVElement):
     """
-    An attendee calendar user address.
+    Changes to an event.
     """
     namespace = calendarserver_namespace
-    name = "attendee"
+    name = "recurrence"
+    allowed_children = {
+        (calendarserver_namespace, "master" )       : (0, 1),
+        (calendarserver_namespace, "recurrenceid" ) : (0, None),
+        (calendarserver_namespace, "changes" )      : (0, 1),
+    }
 
-class PartStat (davxml.WebDAVEmptyElement):
+class Master (davxml.WebDAVEmptyElement):
     """
-    An attendee partstat.
+    Master instance changed.
     """
     namespace = calendarserver_namespace
-    name = "partstat"
+    name = "master"
 
-class PrivateComment (davxml.WebDAVEmptyElement):
+class RecurrenceID (davxml.WebDAVTextElement):
     """
-    An attendee private comment.
+    A recurrence instance changed.
     """
     namespace = calendarserver_namespace
-    name = "private-comment"
+    name = "recurrenceid"
 
 class Changes (davxml.WebDAVElement):
     """
@@ -546,31 +549,13 @@
         "name" : True,
     }
 
-class Recurrences (davxml.WebDAVElement):
+class Attendee (davxml.WebDAVTextElement):
     """
-    Changes to an event.
+    An attendee calendar user address.
     """
     namespace = calendarserver_namespace
-    name = "recurrences"
-    allowed_children = {
-        (calendarserver_namespace, "master" )       : (0, 1),
-        (calendarserver_namespace, "recurrenceid" ) : (0, None),
-    }
+    name = "attendee"
 
-class Master (davxml.WebDAVEmptyElement):
-    """
-    Master instance changed.
-    """
-    namespace = calendarserver_namespace
-    name = "master"
-
-class RecurrenceID (davxml.WebDAVTextElement):
-    """
-    A recurrence instance changed.
-    """
-    namespace = calendarserver_namespace
-    name = "recurrenceid"
-
 class RecordType (davxml.WebDAVTextElement):
     """
     Exposes the type of a record

Modified: CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py	2009-04-27 16:13:04 UTC (rev 4089)
+++ CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py	2009-04-27 16:14:20 UTC (rev 4090)
@@ -589,8 +589,7 @@
                 map[(name, uid, rid,)] = component
             return map
         
-        props_changed = {}
-        rids = set()
+        rids = {}
 
         map1 = mapComponents(self.calendar1)
         set1 = set(map1.keys())
@@ -601,7 +600,7 @@
         for key in (set1 & set2):
             component1 = map1[key]
             component2 = map2[key]
-            self._diffComponents(component1, component2, props_changed, rids)
+            self._diffComponents(component1, component2, rids)
         
         # Now verify that each additional component in set1 matches a derived component in set2
         for key in set1 - set2:
@@ -609,7 +608,7 @@
             component2 = self.calendar2.deriveInstance(key[2])
             if component2 is None:
                 continue
-            self._diffComponents(component1, component2, props_changed, rids)
+            self._diffComponents(component1, component2, rids)
         
         # Now verify that each additional component in set1 matches a derived component in set2
         for key in set2 - set1:
@@ -617,11 +616,9 @@
             if component1 is None:
                 continue
             component2 = map2[key]
-            self._diffComponents(component1, component2, props_changed, rids)
+            self._diffComponents(component1, component2, rids)
         
-        if not self.calendar1.isRecurring() and not self.calendar2.isRecurring() or not props_changed:
-            rids = None
-        return props_changed, rids
+        return rids
 
     def _attendeeDuplicateAndNormalize(self, calendar):
         calendar = calendar.duplicate()
@@ -632,7 +629,7 @@
         iTipGenerator.prepareSchedulingMessage(calendar, reply=True)
         return calendar
 
-    def _diffComponents(self, comp1, comp2, changed, rids):
+    def _diffComponents(self, comp1, comp2, rids):
         
         assert isinstance(comp1, Component) and isinstance(comp2, Component)
         
@@ -648,6 +645,7 @@
         comp2.transformAllToNative()
         addedChanges = False
         
+        propsChanged = {}
         for prop in propdiff:
             if prop.name() in (
                 "TRANSP",
@@ -658,7 +656,7 @@
                 "X-CALENDARSERVER-PRIVATE-COMMENT",
             ):
                 continue
-            changed.setdefault(prop.name(), set())
+            propsChanged.setdefault(prop.name(), set())
             addedChanges = True
             prop1s = tuple(comp1.properties(prop.name()))
             prop2s = tuple(comp2.properties(prop.name()))
@@ -666,14 +664,14 @@
                 param1s = set(["%s=%s" % (name, value) for name, value in prop1s[0].params().iteritems()])
                 param2s = set(["%s=%s" % (name, value) for name, value in prop2s[0].params().iteritems()])
                 paramDiffs = param1s ^ param2s
-                changed[prop.name()].update([param.split("=")[0] for param in paramDiffs])
-            if "ORIGINAL-TZID" in changed[prop.name()]:
-                changed[prop.name()].remove("ORIGINAL-TZID")
-                changed[prop.name()].add("TZID")
+                propsChanged[prop.name()].update([param.split("=")[0] for param in paramDiffs])
+            if "ORIGINAL-TZID" in propsChanged[prop.name()]:
+                propsChanged[prop.name()].remove("ORIGINAL-TZID")
+                propsChanged[prop.name()].add("TZID")
         
         if addedChanges:
             rid = comp1.getRecurrenceIDUTC()
-            rids.add(toString(rid) if rid is not None else "")
+            rids[toString(rid) if rid is not None else ""] = propsChanged
 
     def _logDiffError(self, title):
 

Modified: CalendarServer/trunk/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/implicit.py	2009-04-27 16:13:04 UTC (rev 4089)
+++ CalendarServer/trunk/twistedcaldav/scheduling/implicit.py	2009-04-27 16:14:20 UTC (rev 4090)
@@ -496,7 +496,7 @@
         differ = iCalDiff(self.oldcalendar, self.calendar, self.do_smart_merge)
         no_change = differ.organizerDiff()
         if not no_change:
-            _ignore_props, rids = differ.whatIsDifferent()
+            rids = set(differ.whatIsDifferent().keys())
         else:
             # Special case of RSVP added to attendees and no other change
             rsvps = set()

Modified: CalendarServer/trunk/twistedcaldav/scheduling/itip.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/itip.py	2009-04-27 16:13:04 UTC (rev 4089)
+++ CalendarServer/trunk/twistedcaldav/scheduling/itip.py	2009-04-27 16:14:20 UTC (rev 4090)
@@ -91,7 +91,7 @@
         
         # Merge Organizer data with Attendee's own changes (VALARMs, Comment only for now).
         from twistedcaldav.scheduling.icaldiff import iCalDiff
-        props_changed, rids = iCalDiff(calendar, itip_message, False).whatIsDifferent()
+        rids = iCalDiff(calendar, itip_message, False).whatIsDifferent()
 
         # Different behavior depending on whether a master component is present or not
         current_master = calendar.masterComponent()
@@ -135,7 +135,7 @@
                             iTipProcessing.transferItems(calendar, master_valarms, private_comments, transps, new_component)
             
             # Replace the entire object
-            return new_calendar, props_changed, rids
+            return new_calendar, rids
 
         else:
             # Need existing tzids
@@ -155,7 +155,7 @@
                         iTipProcessing.fixForiCal3((component,), recipient, config.Scheduling.CalDAV.OldDraftCompatibility)
 
             # Write back the modified object
-            return calendar, props_changed, rids
+            return calendar, rids
 
     @staticmethod
     def processCancel(itip_message, calendar, autoprocessing=False):
@@ -274,16 +274,12 @@
         old_master = calendar.masterComponent()
         new_master = itip_message.masterComponent()
         attendees = set()
-        partstat_changed = False
-        private_comment_changed = False
-        rids = set() if old_master.isRecurring() else None
+        rids = set()
         if new_master:
             attendee, partstat, private_comment = iTipProcessing.updateAttendeeData(new_master, old_master)
             attendees.add(attendee)
-            partstat_changed = partstat_changed or partstat
-            private_comment_changed = private_comment_changed or private_comment
-            if rids is not None and (partstat_changed or private_comment_changed):
-                rids.add("")
+            if partstat or private_comment:
+                rids.add(("", partstat, private_comment,))
 
         # Now do all overridden ones (sort by RECURRENCE-ID)
         sortedComponents = []
@@ -311,12 +307,11 @@
 
             attendee, partstat, private_comment = iTipProcessing.updateAttendeeData(itip_component, match_component)
             attendees.add(attendee)
-            partstat_changed = partstat_changed or partstat
-            private_comment_changed = private_comment_changed or private_comment
             if rids is not None and (partstat or private_comment):
-                rids.add(toString(rid))
+                rids.add((toString(rid), partstat, private_comment,))
 
-        return True, (attendees, partstat_changed, private_comment_changed, rids)
+        assert len(attendees) == 1, "ATTENDEE property in a REPLY must be the same in all components\n%s" % (str(itip_message),)
+        return True, (attendees.pop(), rids)
 
     @staticmethod
     def updateAttendeeData(from_component, to_component):

Modified: CalendarServer/trunk/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/processing.py	2009-04-27 16:13:04 UTC (rev 4089)
+++ CalendarServer/trunk/twistedcaldav/scheduling/processing.py	2009-04-27 16:14:20 UTC (rev 4090)
@@ -162,18 +162,24 @@
             recipient_calendar_resource = (yield self.writeCalendarResource(self.recipient_calendar_collection_uri, self.recipient_calendar_collection, self.recipient_calendar_name, self.recipient_calendar))
             
             # Build the schedule-changes XML element
-            processed_attendees, partstat_changed, private_comment_changed, rids = processed
-            reply_details = (customxml.Attendee.fromString(tuple(processed_attendees)[0]),)
-            if partstat_changed:
-                reply_details += (customxml.PartStat(),)
-            if private_comment_changed:
-                reply_details += (customxml.PrivateComment(),)
-            if rids is not None:
-                recurrences = []
-                if "" in rids:
-                    recurrences.append(customxml.Master())
-                recurrences.extend([customxml.RecurrenceID.fromString(rid) for rid in rids if rid != ""])
-                reply_details += (customxml.Recurrences(*recurrences),)
+            attendeeReplying, rids = processed
+            partstatChanged = False
+            reply_details = (customxml.Attendee.fromString(attendeeReplying),)
+            
+            for rid, partstatChanged, privateCommentChanged in sorted(rids):
+                recurrence = []
+                if rid == "":
+                    recurrence.append(customxml.Master())
+                else:
+                    recurrence.append(customxml.RecurrenceID.fromString(rid))
+                changes = []
+                if partstatChanged:
+                    changes.append(customxml.ChangedProperty(customxml.ChangedParameter(name="PARTSTAT"), name="ATTENDEE" ))
+                    partstatChanged = True
+                if privateCommentChanged:
+                    changes.append(customxml.ChangedProperty(name="X-CALENDARSERVER-PRIVATE-COMMENT"))
+                recurrence.append(customxml.Changes(*changes))
+                reply_details += (customxml.Recurrence(*recurrence),)
 
             changes = customxml.ScheduleChanges(
                 customxml.DTStamp(),
@@ -183,8 +189,8 @@
             )
 
             # Only update other attendees when the partstat was changed by the reply
-            if partstat_changed:
-                self.updateAllAttendeesExceptSome(recipient_calendar_resource, processed_attendees)
+            if partstatChanged:
+                self.updateAllAttendeesExceptSome(recipient_calendar_resource, (attendeeReplying,))
 
             result = (True, False, changes,)
 
@@ -293,7 +299,7 @@
         else:
             # Processing update to existing event
             autoprocessed = (yield self.recipient.principal.getAutoSchedule())
-            new_calendar, props_changed, rids = iTipProcessing.processRequest(self.message, self.recipient_calendar, self.recipient.cuaddr, autoprocessing=autoprocessed)
+            new_calendar, rids = iTipProcessing.processRequest(self.message, self.recipient_calendar, self.recipient.cuaddr, autoprocessing=autoprocessed)
             if new_calendar:
      
                 # Handle auto-reply behavior
@@ -308,18 +314,20 @@
                     reactor.callLater(2.0, self.sendAttendeeAutoReply, *(new_calendar, new_resource, partstat))
 
                 # Build the schedule-changes XML element
-                changes = []
-                if props_changed:
+                update_details = []
+                for rid, props_changed in sorted(rids.iteritems(), key=lambda x:x[0]):
+                    recurrence = []
+                    if rid == "":
+                        recurrence.append(customxml.Master())
+                    else:
+                        recurrence.append(customxml.RecurrenceID.fromString(rid))
+                    changes = []
                     for propName, paramNames in sorted(props_changed.iteritems(), key=lambda x:x[0]):
                         params = tuple([customxml.ChangedParameter(name=param) for param in paramNames])
                         changes.append(customxml.ChangedProperty(*params, **{"name":propName}))
-                update_details = (customxml.Changes(*changes),)
-                if rids is not None:
-                    recurrences = []
-                    if "" in rids:
-                        recurrences.append(customxml.Master())
-                    recurrences.extend([customxml.RecurrenceID.fromString(rid) for rid in rids if rid != ""])
-                    update_details += (customxml.Recurrences(*recurrences),)
+                    recurrence.append(customxml.Changes(*changes))
+                    update_details += (customxml.Recurrence(*recurrence),)
+
                 changes = customxml.ScheduleChanges(
                     customxml.DTStamp(),
                     customxml.Action(
@@ -378,14 +386,15 @@
                     yield self.writeCalendarResource(self.recipient_calendar_collection_uri, self.recipient_calendar_collection, self.recipient_calendar_name, self.recipient_calendar)
 
                     # Build the schedule-changes XML element
-                    actions = (customxml.Cancel(),)
                     if rids:
-                        actions += (customxml.Recurrences(
-                            *[customxml.RecurrenceID.fromString(rid) for rid in rids]
-                        ),)
+                        action = customxml.Cancel(
+                            *[customxml.Recurrence(customxml.RecurrenceID.fromString(rid)) for rid in sorted(rids)]
+                        )
+                    else:
+                        action = customxml.Cancel()
                     changes = customxml.ScheduleChanges(
                         customxml.DTStamp(),
-                        customxml.Action(*actions),
+                        customxml.Action(action),
                     )
                     result = (True, autoprocessed, changes)
             else:

Modified: CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py	2009-04-27 16:13:04 UTC (rev 4089)
+++ CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py	2009-04-27 16:14:20 UTC (rev 4090)
@@ -2277,7 +2277,6 @@
 END:VCALENDAR
 """,
                 {},
-                (),
             ),
             (
                 "#1.2 Simple component, one property change",
@@ -2303,8 +2302,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"SUMMARY":set(),},
-                (),
+                {"":{"SUMMARY":set(),}},
             ),
             (
                 "#1.3 Simple component, one property change, one addition, one removal",
@@ -2332,8 +2330,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"SUMMARY":set(), "LOCATION":set(), "DESCRIPTION":set(),},
-                (),
+                {"":{"SUMMARY":set(), "LOCATION":set(), "DESCRIPTION":set(),}},
             ),
             (
                 "#1.4 Simple component, add attendee",
@@ -2366,8 +2363,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"ATTENDEE":set(),},
-                (),
+                {"":{"ATTENDEE":set(),}},
             ),
             (
                 "#1.5 Simple component, remove attendee",
@@ -2398,8 +2394,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"ATTENDEE":set(),},
-                (),
+                {"":{"ATTENDEE":set(),}},
             ),
             (
                 "#1.6 Simple component, attendee PARTSTAT only",
@@ -2431,8 +2426,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"ATTENDEE":set(),},
-                (),
+                {"":{"ATTENDEE":set(),}},
             ),
             (
                 "#1.7 Simple component, attendee PARTSTAT and addition",
@@ -2465,8 +2459,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"ATTENDEE":set(),},
-                (),
+                {"":{"ATTENDEE":set(),}},
             ),
             (
                 "#1.8 Simple component, attendee RSVP only",
@@ -2498,8 +2491,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"ATTENDEE":set(),},
-                (),
+                {"":{"ATTENDEE":set(),}},
             ),
             (
                 "#1.9 Simple component, DTSTART/DTEND VALUE",
@@ -2531,8 +2523,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"DTEND":set(("VALUE",)), "DTSTART":set(("VALUE",)),},
-                (),
+                {"":{"DTEND":set(("VALUE",)), "DTSTART":set(("VALUE",)),}},
             ),
             (
                 "#1.10 Simple component, DTSTART/DTEND TZID",
@@ -2600,8 +2591,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"DTEND":set(("TZID",)), "DTSTART":set(("TZID",)),},
-                (),
+                {"":{"DTEND":set(("TZID",)), "DTSTART":set(("TZID",)),}},
             ),
         )
         
@@ -2639,7 +2629,6 @@
 END:VCALENDAR
 """,
                 {},
-                (),
             ),
             (
                 "#2.2 Simple component, one property change",
@@ -2667,8 +2656,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"SUMMARY":set(),},
-                ("",),
+                {"":{"SUMMARY":set(),}},
             ),
             (
                 "#2.3 Simple component, one property change, one addition, one removal",
@@ -2698,8 +2686,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"SUMMARY":set(), "LOCATION":set(), "DESCRIPTION":set(),},
-                ("",),
+                {"":{"SUMMARY":set(), "LOCATION":set(), "DESCRIPTION":set(),}},
             ),
             (
                 "#2.4 Simple component, add attendee",
@@ -2734,8 +2721,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"ATTENDEE":set(),},
-                ("",),
+                {"":{"ATTENDEE":set(),}},
             ),
             (
                 "#2.5 Simple component, remove attendee",
@@ -2768,8 +2754,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"ATTENDEE":set(),},
-                ("",),
+                {"":{"ATTENDEE":set(),}},
             ),
             (
                 "#2.6 Simple component, attendee PARTSTAT only",
@@ -2803,8 +2788,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"ATTENDEE":set(),},
-                ("",),
+                {"":{"ATTENDEE":set(),}},
             ),
             (
                 "#2.7 Simple component, attendee PARTSTAT and addition",
@@ -2839,8 +2823,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"ATTENDEE":set(),},
-                ("",),
+                {"":{"ATTENDEE":set(),}},
             ),
         )
         
@@ -2898,7 +2881,6 @@
 END:VCALENDAR
 """,
                 {},
-                (),
             ),
             (
                 "#3.2 Simple component, one property change in instance",
@@ -2946,8 +2928,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"SUMMARY":set(),},
-                ("20080602T120000Z",),
+                {"20080602T120000Z":{"SUMMARY":set(),}},
             ),
             (
                 "#3.3 Simple component, one property change in master",
@@ -2995,8 +2976,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"SUMMARY":set(),},
-                ("",),
+                {"":{"SUMMARY":set(),}},
             ),
             (
                 "#3.4 Simple component, one property change in master and instance",
@@ -3044,8 +3024,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"SUMMARY":set(),},
-                ("", "20080602T120000Z",),
+                {"":{"SUMMARY":set(),}, "20080602T120000Z":{"SUMMARY":set(),}},
             ),
             (
                 "#3.5 Simple component, different property change in master and instance",
@@ -3094,8 +3073,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"SUMMARY":set(), "DESCRIPTION":set()},
-                ("", "20080602T120000Z",),
+                {"":{"SUMMARY":set()}, "20080602T120000Z":{"DESCRIPTION":set()}},
             ),
             (
                 "#3.6 Simple component, instance added no change",
@@ -3131,7 +3109,6 @@
 END:VCALENDAR
 """,
                 {},
-                (),
             ),
             (
                 "#3.7 Simple component, instance added time change",
@@ -3166,8 +3143,7 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"DTSTART":set(), "DTEND":set(), },
-                ("20080602T120000Z",),
+                {"20080602T120000Z":{"DTSTART":set(), "DTEND":set(), }},
             ),
             (
                 "#3.8 Simple component, instance removed no change",
@@ -3203,7 +3179,6 @@
 END:VCALENDAR
 """,
                 {},
-                (),
             ),
             (
                 "#3.9 Simple component, instance removed time change",
@@ -3238,18 +3213,14 @@
 END:VEVENT
 END:VCALENDAR
 """,
-                {"DTSTART":set(), "DTEND":set(), },
-                ("20080602T120000Z",),
+                {"20080602T120000Z":{"DTSTART":set(), "DTEND":set(), }},
             ),
         )
         
-        for description, calendar1, calendar2, changes, rids in itertools.chain(data1, data2, data3,):
+        for description, calendar1, calendar2, rids in itertools.chain(data1, data2, data3,):
             differ = iCalDiff(Component.fromString(calendar1), Component.fromString(calendar2), False)
-            expected_changes = changes
-            expected_rids = set(rids) if rids else None
-            got_changes, got_rids = differ.whatIsDifferent()
-            self.assertEqual(got_changes, expected_changes, msg="%s expected changes: '%s', got: '%s'" % (description, expected_changes, got_changes,))
-            self.assertEqual(got_rids, expected_rids, msg="%s expected R-IDs: '%s', got: '%s'" % (description, expected_rids, got_rids,))
+            got_rids = differ.whatIsDifferent()
+            self.assertEqual(got_rids, rids, msg="%s expected R-IDs: '%s', got: '%s'" % (description, rids, got_rids,))
         
     def test_organizer_smart_merge(self):
         
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090427/bdc0e17b/attachment-0001.html>


More information about the calendarserver-changes mailing list