[CalendarServer-changes] [13866] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Aug 11 14:31:02 PDT 2014


Revision: 13866
          http://trac.calendarserver.org//changeset/13866
Author:   cdaboo at apple.com
Date:     2014-08-11 14:31:01 -0700 (Mon, 11 Aug 2014)
Log Message:
-----------
Tweak attendee group expansion to clean-up the parameters on the group attendee property.

Modified Paths:
--------------
    CalendarServer/trunk/requirements-dev.txt
    CalendarServer/trunk/twistedcaldav/ical.py
    CalendarServer/trunk/txdav/caldav/datastore/scheduling/implicit.py
    CalendarServer/trunk/txdav/caldav/datastore/scheduling/itip.py
    CalendarServer/trunk/txdav/who/test/test_group_attendees.py

Modified: CalendarServer/trunk/requirements-dev.txt
===================================================================
--- CalendarServer/trunk/requirements-dev.txt	2014-08-11 21:26:39 UTC (rev 13865)
+++ CalendarServer/trunk/requirements-dev.txt	2014-08-11 21:31:01 UTC (rev 13866)
@@ -7,4 +7,4 @@
 mockldap
 q
 --editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVClientLibrary/trunk@13420#egg=CalDAVClientLibrary
---editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@13861#egg=CalDAVTester
+--editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@13865#egg=CalDAVTester

Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py	2014-08-11 21:26:39 UTC (rev 13865)
+++ CalendarServer/trunk/twistedcaldav/ical.py	2014-08-11 21:31:01 UTC (rev 13866)
@@ -2485,6 +2485,7 @@
     def setParameterToValueForPropertyWithValue(self, paramname, paramvalue, propname, propvalue):
         """
         Add or change the parameter to the specified value on the property having the specified value.
+        If C{paramvalue} is L{None} remove the parameter.
 
         @param paramname: the parameter name
         @type paramname: C{str}
@@ -2496,12 +2497,37 @@
         @type propvalue: C{str} or C{None}
         """
 
+        self.setParametersForPropertyWithValue(
+            {paramname: paramvalue},
+            propname,
+            propvalue,
+        )
+
+
+    def setParametersForPropertyWithValue(self, params, propname, propvalue):
+        """
+        Add, change or remove a set of parameters to the specified value on the property
+        having the specified value. Parameters are specified in a name:value L{dict}. If
+        the value is L{None} the parameter will be removed.
+
+        @param params: the parameter name/value pairs to set/remove
+        @type params: C{dict}
+        @param propname: the property name
+        @type propname: C{str}
+        @param propvalue: the property value to test
+        @type propvalue: C{str} or C{None}
+        """
+
         for component in self.subcomponents():
             if component.name() in ignoredComponents:
                 continue
             for property in component.properties(propname):
                 if propvalue is None or property.value() == propvalue:
-                    property.setParameter(paramname, paramvalue)
+                    for paramname, paramvalue in params.items():
+                        if paramvalue is not None:
+                            property.setParameter(paramname, paramvalue)
+                        else:
+                            property.removeParameter(paramname)
 
 
     def hasPropertyInAnyComponent(self, properties):

Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/implicit.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/implicit.py	2014-08-11 21:26:39 UTC (rev 13865)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/implicit.py	2014-08-11 21:31:01 UTC (rev 13866)
@@ -757,8 +757,13 @@
 
         # Always set RSVP=TRUE for any NEEDS-ACTION
         for attendee in self.calendar.getAllAttendeeProperties():
-            if attendee.parameterValue("PARTSTAT", "NEEDS-ACTION").upper() == "NEEDS-ACTION":
-                attendee.setParameter("RSVP", "TRUE")
+            if attendee.parameterValue("CUTYPE") != "X-SERVER-GROUP":
+                if attendee.parameterValue("PARTSTAT", "NEEDS-ACTION").upper() == "NEEDS-ACTION":
+                    attendee.setParameter("RSVP", "TRUE")
+            else:
+                # Always remove RSVP and PARTSTAT
+                attendee.removeParameter("RSVP")
+                attendee.removeParameter("PARTSTAT")
 
         # If processing a queue item, actually execute the scheduling operations, else queue it.
         # Note a split is always queued, so we do not need to re-queue
@@ -1157,114 +1162,16 @@
             self.calendar.bumpiTIPInfo(oldcalendar=self.oldcalendar, doSequence=True)
 
         # First process cancelled attendees
-        total = (yield self.processQueuedCancels())
+        total = (yield self.processCancels(queued=True))
 
         # Process regular requests next
         if self.action in ("create", "modify",):
-            total += (yield self.processQueuedRequests())
+            total += (yield self.processRequests(queued=True))
 
         self.logItems["itip.requests"] = total
 
 
     @inlineCallbacks
-    def processQueuedCancels(self):
-        """
-        Set each ATTENDEE who would be scheduled to status to 1.2.
-        """
-
-        # Do one per attendee
-        aggregated = {}
-        for attendee, rid in self.cancelledAttendees:
-            aggregated.setdefault(attendee, []).append(rid)
-
-        count = 0
-        for attendee, rids in aggregated.iteritems():
-
-            # Don't send message back to the ORGANIZER
-            if attendee in self.organizerAddress.record.calendarUserAddresses:
-                continue
-
-            # Handle split by not scheduling local attendees
-            if self.split_details is not None:
-                attendeeAddress = (yield calendarUserFromCalendarUserAddress(attendee, self.txn))
-                if type(attendeeAddress) is LocalCalendarUser:
-                    continue
-
-            # Test whether an iTIP CANCEL message for this attendee would be generated
-            if None in rids:
-                # One big CANCEL will do
-                itipmsg = iTipGenerator.generateCancel(self.oldcalendar, (attendee,), None, self.action == "remove", test_only=True)
-            else:
-                # Multiple CANCELs
-                itipmsg = iTipGenerator.generateCancel(self.oldcalendar, (attendee,), rids, test_only=True)
-
-            # Send scheduling message
-            if itipmsg:
-
-                # Always make it look like scheduling succeeded when queuing
-                self.calendar.setParameterToValueForPropertyWithValue(
-                    "SCHEDULE-STATUS",
-                    iTIPRequestStatus.MESSAGE_DELIVERED_CODE,
-                    "ATTENDEE",
-                    attendee,
-                )
-
-                count += 1
-
-        returnValue(count)
-
-
-    @inlineCallbacks
-    def processQueuedRequests(self):
-        """
-        Set each ATTENDEE who would be scheduled to status to 1.2.
-        """
-
-        # Do one per attendee
-        count = 0
-        for attendee in self.attendees:
-
-            # Don't send message back to the ORGANIZER
-            if attendee in self.organizerAddress.record.calendarUserAddresses:
-                continue
-
-            # Don't send message to specified attendees
-            if attendee in self.except_attendees:
-                continue
-
-            # Only send to specified attendees
-            if self.only_refresh_attendees is not None and attendee not in self.only_refresh_attendees:
-                continue
-
-            # If SCHEDULE-FORCE-SEND only change, only send message to those Attendees
-            if self.reinvites and attendee not in self.reinvites:
-                continue
-
-            # Handle split by not scheduling local attendees
-            if self.split_details is not None:
-                attendeeAddress = (yield calendarUserFromCalendarUserAddress(attendee, self.txn))
-                if type(attendeeAddress) is LocalCalendarUser:
-                    continue
-
-            itipmsg = iTipGenerator.generateAttendeeRequest(self.calendar, (attendee,), self.changed_rids, test_only=True)
-
-            # Send scheduling message
-            if itipmsg is not None:
-
-                # Always make it look like scheduling succeeded when queuing
-                self.calendar.setParameterToValueForPropertyWithValue(
-                    "SCHEDULE-STATUS",
-                    iTIPRequestStatus.MESSAGE_DELIVERED_CODE,
-                    "ATTENDEE",
-                    attendee,
-                )
-
-                count += 1
-
-        returnValue(count)
-
-
-    @inlineCallbacks
     def scheduleWithAttendees(self):
 
         # First make sure we are allowed to schedule
@@ -1282,8 +1189,16 @@
 
 
     @inlineCallbacks
-    def processCancels(self):
+    def processCancels(self, queued=False):
+        """
+        Process iTIP CANCEL messages for a set of attendees. For a queue operation we
+        simply set the ATTENDEE's SCHEDULE-STATUS to 1.2. For non-queued we do the
+        actual iTIP message send and process the result of that.
 
+        @param queued: whether actual processing will be done via the queue
+        @type queued: L{bool}
+        """
+
         # TODO: a better policy here is to aggregate by attendees with the same set of instances
         # being cancelled, but for now we will do one scheduling message per attendee.
 
@@ -1307,7 +1222,7 @@
                     continue
 
             # Do not schedule with groups - ever
-            if attendeeAddress.hosted() and attendeeAddress.getCUType() in ("GROUP", "X-SERVER-GROUP"):
+            if attendeeAddress.hosted() and attendeeAddress.getCUType() == "GROUP":
                 continue
 
             # Generate an iTIP CANCEL message for this attendee, cancelling
@@ -1323,13 +1238,22 @@
             # Send scheduling message
             if itipmsg:
 
-                # Add split details if needed
-                if self.split_details is not None:
-                    rid, uid, newer_piece = self.split_details
-                    itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-RID", rid))
-                    itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-OLDER-UID" if newer_piece else "X-CALENDARSERVER-SPLIT-NEWER-UID", uid))
+                if queued:
+                    # Always make it look like scheduling succeeded when queuing
+                    self.calendar.setParameterToValueForPropertyWithValue(
+                        "SCHEDULE-STATUS",
+                        iTIPRequestStatus.MESSAGE_DELIVERED_CODE,
+                        "ATTENDEE",
+                        attendee,
+                    )
+                else:
+                    # Add split details if needed
+                    if self.split_details is not None:
+                        rid, uid, newer_piece = self.split_details
+                        itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-RID", rid))
+                        itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-OLDER-UID" if newer_piece else "X-CALENDARSERVER-SPLIT-NEWER-UID", uid))
 
-                yield self.processSend(attendee, itipmsg, count=count)
+                    yield self.processSend(attendee, itipmsg, count=count)
 
                 count += 1
 
@@ -1337,8 +1261,18 @@
 
 
     @inlineCallbacks
-    def processRequests(self, cancel_count=0):
+    def processRequests(self, cancel_count=0, queued=False):
+        """
+        Process iTIP REQUEST messages for a set of attendees. For a queue operation we
+        simply set the ATTENDEE's SCHEDULE-STATUS to 1.2. For non-queued we do the
+        actual iTIP message send and process the result of that.
 
+        @param cancel_count: number of CANCELs already sent
+        @type cancel_count: L{int}
+        @param queued: whether actual processing will be done via the queue
+        @type queued: L{bool}
+        """
+
         # TODO: a better policy here is to aggregate by attendees with the same set of instances
         # being requested, but for now we will do one scheduling message per attendee.
 
@@ -1370,7 +1304,12 @@
                     continue
 
             # Do not schedule with groups - ever
-            if attendeeAddress.hosted() and attendeeAddress.getCUType() in ("GROUP", "X-SERVER-GROUP"):
+            if attendeeAddress.hosted() and attendeeAddress.getCUType() == "GROUP":
+                # Set SCHEDULE-STATUS to something appropriate
+                self.calendar.setParametersForPropertyWithValue(
+                    {"SCHEDULE-STATUS": iTIPRequestStatus.REQUEST_FORWARDED_CODE if config.GroupAttendees.Enabled else iTIPRequestStatus.NO_USER_SUPPORT_CODE},
+                    "ATTENDEE", attendee,
+                )
                 continue
 
             itipmsg = iTipGenerator.generateAttendeeRequest(self.calendar, (attendee,), self.changed_rids)
@@ -1378,13 +1317,22 @@
             # Send scheduling message
             if itipmsg is not None:
 
-                # Add split details if needed
-                if self.split_details is not None:
-                    rid, uid, newer_piece = self.split_details
-                    itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-RID", rid))
-                    itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-OLDER-UID" if newer_piece else "X-CALENDARSERVER-SPLIT-NEWER-UID", uid))
+                if queued:
+                    # Always make it look like scheduling succeeded when queuing
+                    self.calendar.setParameterToValueForPropertyWithValue(
+                        "SCHEDULE-STATUS",
+                        iTIPRequestStatus.MESSAGE_DELIVERED_CODE,
+                        "ATTENDEE",
+                        attendee,
+                    )
+                else:
+                    # Add split details if needed
+                    if self.split_details is not None:
+                        rid, uid, newer_piece = self.split_details
+                        itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-RID", rid))
+                        itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-OLDER-UID" if newer_piece else "X-CALENDARSERVER-SPLIT-NEWER-UID", uid))
 
-                yield self.processSend(attendee, itipmsg, count=count + cancel_count)
+                    yield self.processSend(attendee, itipmsg, count=count + cancel_count)
 
                 count += 1
 
@@ -1454,7 +1402,8 @@
                     "SCHEDULE-STATUS",
                     status.split(";")[0],
                     propname,
-                    recipient)
+                    recipient,
+                )
 
 
     @inlineCallbacks
@@ -1592,7 +1541,8 @@
                         "SCHEDULE-STATUS",
                         iTIPRequestStatus.NO_USER_SUPPORT_CODE,
                         "ORGANIZER",
-                        self.organizer)
+                        self.organizer,
+                    )
                 returnValue(None)
 
             else:
@@ -1658,8 +1608,14 @@
 
             # Check SCHEDULE-AGENT and coerce SERVER to NONE
             if self.calendar.getOrganizerScheduleAgent():
-                self.calendar.setParameterToValueForPropertyWithValue("SCHEDULE-AGENT", "NONE", "ORGANIZER", None)
-                self.calendar.setParameterToValueForPropertyWithValue("SCHEDULE-STATUS", iTIPRequestStatus.NO_USER_SUPPORT_CODE, "ORGANIZER", None)
+                self.calendar.setParametersForPropertyWithValue(
+                    {
+                        "SCHEDULE-AGENT": "NONE",
+                        "SCHEDULE-STATUS": iTIPRequestStatus.NO_USER_SUPPORT_CODE,
+                    },
+                    "ORGANIZER",
+                    None,
+                )
 
 
     def checkOrganizerScheduleAgent(self):
@@ -1673,8 +1629,14 @@
         if not config.Scheduling.iSchedule.Enabled and not local_organizer and is_server:
             # Coerce ORGANIZER to SCHEDULE-AGENT=NONE
             log.debug("Attendee '{attendee}' is not allowed to use SCHEDULE-AGENT=SERVER on organizer: UID:{uid}", attendee=self.attendeeAddress.record, uid=self.uid)
-            self.calendar.setParameterToValueForPropertyWithValue("SCHEDULE-AGENT", "NONE", "ORGANIZER", None)
-            self.calendar.setParameterToValueForPropertyWithValue("SCHEDULE-STATUS", iTIPRequestStatus.NO_USER_SUPPORT_CODE, "ORGANIZER", None)
+            self.calendar.setParametersForPropertyWithValue(
+                {
+                    "SCHEDULE-AGENT": "NONE",
+                    "SCHEDULE-STATUS": iTIPRequestStatus.NO_USER_SUPPORT_CODE,
+                },
+                "ORGANIZER",
+                None,
+            )
             is_server = False
 
         return is_server

Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/itip.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/itip.py	2014-08-11 21:26:39 UTC (rev 13865)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/itip.py	2014-08-11 21:31:01 UTC (rev 13866)
@@ -1091,6 +1091,7 @@
     MESSAGE_DELIVERED_CODE = "1.2"
 
     SUCCESS_CODE = "2.0"
+    REQUEST_FORWARDED_CODE = "2.7"
 
     INVALID_CALENDAR_USER_CODE = "3.7"
     NO_AUTHORITY_CODE = "3.8"
@@ -1105,6 +1106,7 @@
     MESSAGE_DELIVERED = MESSAGE_DELIVERED_CODE + ";Scheduling message has been delivered"
 
     SUCCESS = SUCCESS_CODE + ";Success"
+    REQUEST_FORWARDED = REQUEST_FORWARDED_CODE + ";Success; request forwarded to Calendar User."
 
     INVALID_CALENDAR_USER = INVALID_CALENDAR_USER_CODE + ";Invalid Calendar User"
     NO_AUTHORITY = NO_AUTHORITY_CODE + ";No authority"

Modified: CalendarServer/trunk/txdav/who/test/test_group_attendees.py
===================================================================
--- CalendarServer/trunk/txdav/who/test/test_group_attendees.py	2014-08-11 21:26:39 UTC (rev 13865)
+++ CalendarServer/trunk/txdav/who/test/test_group_attendees.py	2014-08-11 21:31:01 UTC (rev 13866)
@@ -100,6 +100,8 @@
                             attendeeProp.removeParameterValue("MEMBER", paramterValue)
                         attendeeProp.setParameter("MEMBER", sorted(parameterValues))
 
+            return event
+
         self.assertEqual(
             orderMemberValues(Component.fromString(normalize_iCalStr(iCalStr1))),
             orderMemberValues(Component.fromString(normalize_iCalStr(iCalStr2)))
@@ -142,7 +144,7 @@
 DTSTART:20140101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;RSVP=TRUE:urn:x-uid:group02
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
 ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
 ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
@@ -201,7 +203,7 @@
 DTSTART:20140101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
-ATTENDEE;CUTYPE=X-SERVER-GROUP;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:uuid:FFFFFFFF-EEEE-DDDD-CCCC-BBBBBBBBBBBB
+ATTENDEE;CUTYPE=X-SERVER-GROUP;SCHEDULE-STATUS=3.7:urn:uuid:FFFFFFFF-EEEE-DDDD-CCCC-BBBBBBBBBBBB
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 01;EMAIL=user01 at example.com:urn:x-uid:user01
 SUMMARY:event 1
@@ -253,7 +255,7 @@
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 01;EMAIL=user01 at example.com:urn:x-uid:user01
 SUMMARY:event 1
@@ -308,7 +310,7 @@
 DTSTART:20140101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
-ATTENDEE;CN=Group 04;CUTYPE=X-SERVER-GROUP;RSVP=TRUE:urn:x-uid:group04
+ATTENDEE;CN=Group 04;CUTYPE=X-SERVER-GROUP;SCHEDULE-STATUS=2.7:urn:x-uid:group04
 ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:group04";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:group04";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
 ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:group04";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
@@ -376,9 +378,9 @@
 DTSTART:20140101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;RSVP=TRUE:urn:x-uid:group03
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
 ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
 ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
@@ -435,7 +437,7 @@
 DTSTART:20140101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
@@ -499,7 +501,7 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
 SUMMARY:event 1
@@ -516,7 +518,7 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
@@ -535,7 +537,7 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
 SEQUENCE:2
@@ -638,7 +640,7 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 0{0};EMAIL=user0{0}@example.com;RSVP=TRUE:urn:x-uid:user0{0}
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 0{0};EMAIL=user0{0}@example.com:urn:x-uid:user0{0}
 SUMMARY:event {0}
@@ -655,7 +657,7 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 0{0};EMAIL=user0{0}@example.com;RSVP=TRUE:urn:x-uid:user0{0}
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 0{0};EMAIL=user0{0}@example.com:urn:x-uid:user0{0}
@@ -674,7 +676,7 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 0{0};EMAIL=user0{0}@example.com;RSVP=TRUE:urn:x-uid:user0{0}
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 0{0};EMAIL=user0{0}@example.com:urn:x-uid:user0{0}
 SEQUENCE:2
@@ -800,7 +802,7 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
@@ -818,7 +820,7 @@
 DTSTART:20140101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
 SEQUENCE:1
@@ -959,7 +961,7 @@
 DTSTART:20120101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
@@ -978,7 +980,7 @@
 DTSTART:20120101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
 RRULE:FREQ=DAILY;UNTIL=20140101T100000
@@ -1087,7 +1089,7 @@
 DTSTART:20120101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
@@ -1105,7 +1107,7 @@
 UID:event1 at ninevah.local
 {start}DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
 {relatedTo}RRULE:FREQ=DAILY;UNTIL=20240101T100000
@@ -1122,7 +1124,7 @@
 {uid}DTSTART:20120101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
@@ -1234,7 +1236,7 @@
 DTSTART:20120101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
 RRULE:FREQ=DAILY;UNTIL=20240101T100000
@@ -1251,7 +1253,7 @@
 UID:event1 at ninevah.local
 {start}DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
@@ -1269,7 +1271,7 @@
 {uid}DTSTART:20120101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
 {relatedTo}{rule}SEQUENCE:1
@@ -1395,9 +1397,9 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;RSVP=TRUE:urn:x-uid:group03
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
 ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
 ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
@@ -1417,9 +1419,9 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;RSVP=TRUE:urn:x-uid:group03
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=3.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
 ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
 ATTENDEE;CN=User 09;EMAIL=user09 at example.com;MEMBER="urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user09
@@ -1440,9 +1442,9 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;RSVP=TRUE:urn:x-uid:group01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;RSVP=TRUE:urn:x-uid:group03
+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
 ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
 ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
@@ -1573,8 +1575,8 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;RSVP=TRUE:urn:x-uid:group03
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
 ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
 ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
@@ -1611,7 +1613,7 @@
 DTSTART:20240101T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;RSVP=TRUE:urn:x-uid:group02
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
 ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
 ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140811/3d63b787/attachment-0001.html>


More information about the calendarserver-changes mailing list