<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[13866] CalendarServer/trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/13866">13866</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2014-08-11 14:31:01 -0700 (Mon, 11 Aug 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Tweak attendee group expansion to clean-up the parameters on the group attendee property.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkrequirementsdevtxt">CalendarServer/trunk/requirements-dev.txt</a></li>
<li><a href="#CalendarServertrunktwistedcaldavicalpy">CalendarServer/trunk/twistedcaldav/ical.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoreschedulingimplicitpy">CalendarServer/trunk/txdav/caldav/datastore/scheduling/implicit.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoreschedulingitippy">CalendarServer/trunk/txdav/caldav/datastore/scheduling/itip.py</a></li>
<li><a href="#CalendarServertrunktxdavwhotesttest_group_attendeespy">CalendarServer/trunk/txdav/who/test/test_group_attendees.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkrequirementsdevtxt"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/requirements-dev.txt (13865 => 13866)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -7,4 +7,4 @@
</span><span class="cx"> mockldap
</span><span class="cx"> q
</span><span class="cx"> --editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVClientLibrary/trunk@13420#egg=CalDAVClientLibrary
</span><del>---editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@13861#egg=CalDAVTester
</del><ins>+--editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@13865#egg=CalDAVTester
</ins></span></pre></div>
<a id="CalendarServertrunktwistedcaldavicalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/ical.py (13865 => 13866)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -2485,6 +2485,7 @@
</span><span class="cx">     def setParameterToValueForPropertyWithValue(self, paramname, paramvalue, propname, propvalue):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Add or change the parameter to the specified value on the property having the specified value.
</span><ins>+        If C{paramvalue} is L{None} remove the parameter.
</ins><span class="cx"> 
</span><span class="cx">         @param paramname: the parameter name
</span><span class="cx">         @type paramname: C{str}
</span><span class="lines">@@ -2496,12 +2497,37 @@
</span><span class="cx">         @type propvalue: C{str} or C{None}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><ins>+        self.setParametersForPropertyWithValue(
+            {paramname: paramvalue},
+            propname,
+            propvalue,
+        )
+
+
+    def setParametersForPropertyWithValue(self, params, propname, propvalue):
+        &quot;&quot;&quot;
+        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}
+        &quot;&quot;&quot;
+
</ins><span class="cx">         for component in self.subcomponents():
</span><span class="cx">             if component.name() in ignoredComponents:
</span><span class="cx">                 continue
</span><span class="cx">             for property in component.properties(propname):
</span><span class="cx">                 if propvalue is None or property.value() == propvalue:
</span><del>-                    property.setParameter(paramname, paramvalue)
</del><ins>+                    for paramname, paramvalue in params.items():
+                        if paramvalue is not None:
+                            property.setParameter(paramname, paramvalue)
+                        else:
+                            property.removeParameter(paramname)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def hasPropertyInAnyComponent(self, properties):
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoreschedulingimplicitpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/implicit.py (13865 => 13866)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -757,8 +757,13 @@
</span><span class="cx"> 
</span><span class="cx">         # Always set RSVP=TRUE for any NEEDS-ACTION
</span><span class="cx">         for attendee in self.calendar.getAllAttendeeProperties():
</span><del>-            if attendee.parameterValue(&quot;PARTSTAT&quot;, &quot;NEEDS-ACTION&quot;).upper() == &quot;NEEDS-ACTION&quot;:
-                attendee.setParameter(&quot;RSVP&quot;, &quot;TRUE&quot;)
</del><ins>+            if attendee.parameterValue(&quot;CUTYPE&quot;) != &quot;X-SERVER-GROUP&quot;:
+                if attendee.parameterValue(&quot;PARTSTAT&quot;, &quot;NEEDS-ACTION&quot;).upper() == &quot;NEEDS-ACTION&quot;:
+                    attendee.setParameter(&quot;RSVP&quot;, &quot;TRUE&quot;)
+            else:
+                # Always remove RSVP and PARTSTAT
+                attendee.removeParameter(&quot;RSVP&quot;)
+                attendee.removeParameter(&quot;PARTSTAT&quot;)
</ins><span class="cx"> 
</span><span class="cx">         # If processing a queue item, actually execute the scheduling operations, else queue it.
</span><span class="cx">         # Note a split is always queued, so we do not need to re-queue
</span><span class="lines">@@ -1157,114 +1162,16 @@
</span><span class="cx">             self.calendar.bumpiTIPInfo(oldcalendar=self.oldcalendar, doSequence=True)
</span><span class="cx"> 
</span><span class="cx">         # First process cancelled attendees
</span><del>-        total = (yield self.processQueuedCancels())
</del><ins>+        total = (yield self.processCancels(queued=True))
</ins><span class="cx"> 
</span><span class="cx">         # Process regular requests next
</span><span class="cx">         if self.action in (&quot;create&quot;, &quot;modify&quot;,):
</span><del>-            total += (yield self.processQueuedRequests())
</del><ins>+            total += (yield self.processRequests(queued=True))
</ins><span class="cx"> 
</span><span class="cx">         self.logItems[&quot;itip.requests&quot;] = total
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def processQueuedCancels(self):
-        &quot;&quot;&quot;
-        Set each ATTENDEE who would be scheduled to status to 1.2.
-        &quot;&quot;&quot;
-
-        # 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 == &quot;remove&quot;, 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(
-                    &quot;SCHEDULE-STATUS&quot;,
-                    iTIPRequestStatus.MESSAGE_DELIVERED_CODE,
-                    &quot;ATTENDEE&quot;,
-                    attendee,
-                )
-
-                count += 1
-
-        returnValue(count)
-
-
-    @inlineCallbacks
-    def processQueuedRequests(self):
-        &quot;&quot;&quot;
-        Set each ATTENDEE who would be scheduled to status to 1.2.
-        &quot;&quot;&quot;
-
-        # 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(
-                    &quot;SCHEDULE-STATUS&quot;,
-                    iTIPRequestStatus.MESSAGE_DELIVERED_CODE,
-                    &quot;ATTENDEE&quot;,
-                    attendee,
-                )
-
-                count += 1
-
-        returnValue(count)
-
-
-    @inlineCallbacks
</del><span class="cx">     def scheduleWithAttendees(self):
</span><span class="cx"> 
</span><span class="cx">         # First make sure we are allowed to schedule
</span><span class="lines">@@ -1282,8 +1189,16 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def processCancels(self):
</del><ins>+    def processCancels(self, queued=False):
+        &quot;&quot;&quot;
+        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.
</ins><span class="cx"> 
</span><ins>+        @param queued: whether actual processing will be done via the queue
+        @type queued: L{bool}
+        &quot;&quot;&quot;
+
</ins><span class="cx">         # TODO: a better policy here is to aggregate by attendees with the same set of instances
</span><span class="cx">         # being cancelled, but for now we will do one scheduling message per attendee.
</span><span class="cx"> 
</span><span class="lines">@@ -1307,7 +1222,7 @@
</span><span class="cx">                     continue
</span><span class="cx"> 
</span><span class="cx">             # Do not schedule with groups - ever
</span><del>-            if attendeeAddress.hosted() and attendeeAddress.getCUType() in (&quot;GROUP&quot;, &quot;X-SERVER-GROUP&quot;):
</del><ins>+            if attendeeAddress.hosted() and attendeeAddress.getCUType() == &quot;GROUP&quot;:
</ins><span class="cx">                 continue
</span><span class="cx"> 
</span><span class="cx">             # Generate an iTIP CANCEL message for this attendee, cancelling
</span><span class="lines">@@ -1323,13 +1238,22 @@
</span><span class="cx">             # Send scheduling message
</span><span class="cx">             if itipmsg:
</span><span class="cx"> 
</span><del>-                # Add split details if needed
-                if self.split_details is not None:
-                    rid, uid, newer_piece = self.split_details
-                    itipmsg.addProperty(Property(&quot;X-CALENDARSERVER-SPLIT-RID&quot;, rid))
-                    itipmsg.addProperty(Property(&quot;X-CALENDARSERVER-SPLIT-OLDER-UID&quot; if newer_piece else &quot;X-CALENDARSERVER-SPLIT-NEWER-UID&quot;, uid))
</del><ins>+                if queued:
+                    # Always make it look like scheduling succeeded when queuing
+                    self.calendar.setParameterToValueForPropertyWithValue(
+                        &quot;SCHEDULE-STATUS&quot;,
+                        iTIPRequestStatus.MESSAGE_DELIVERED_CODE,
+                        &quot;ATTENDEE&quot;,
+                        attendee,
+                    )
+                else:
+                    # Add split details if needed
+                    if self.split_details is not None:
+                        rid, uid, newer_piece = self.split_details
+                        itipmsg.addProperty(Property(&quot;X-CALENDARSERVER-SPLIT-RID&quot;, rid))
+                        itipmsg.addProperty(Property(&quot;X-CALENDARSERVER-SPLIT-OLDER-UID&quot; if newer_piece else &quot;X-CALENDARSERVER-SPLIT-NEWER-UID&quot;, uid))
</ins><span class="cx"> 
</span><del>-                yield self.processSend(attendee, itipmsg, count=count)
</del><ins>+                    yield self.processSend(attendee, itipmsg, count=count)
</ins><span class="cx"> 
</span><span class="cx">                 count += 1
</span><span class="cx"> 
</span><span class="lines">@@ -1337,8 +1261,18 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def processRequests(self, cancel_count=0):
</del><ins>+    def processRequests(self, cancel_count=0, queued=False):
+        &quot;&quot;&quot;
+        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.
</ins><span class="cx"> 
</span><ins>+        @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}
+        &quot;&quot;&quot;
+
</ins><span class="cx">         # TODO: a better policy here is to aggregate by attendees with the same set of instances
</span><span class="cx">         # being requested, but for now we will do one scheduling message per attendee.
</span><span class="cx"> 
</span><span class="lines">@@ -1370,7 +1304,12 @@
</span><span class="cx">                     continue
</span><span class="cx"> 
</span><span class="cx">             # Do not schedule with groups - ever
</span><del>-            if attendeeAddress.hosted() and attendeeAddress.getCUType() in (&quot;GROUP&quot;, &quot;X-SERVER-GROUP&quot;):
</del><ins>+            if attendeeAddress.hosted() and attendeeAddress.getCUType() == &quot;GROUP&quot;:
+                # Set SCHEDULE-STATUS to something appropriate
+                self.calendar.setParametersForPropertyWithValue(
+                    {&quot;SCHEDULE-STATUS&quot;: iTIPRequestStatus.REQUEST_FORWARDED_CODE if config.GroupAttendees.Enabled else iTIPRequestStatus.NO_USER_SUPPORT_CODE},
+                    &quot;ATTENDEE&quot;, attendee,
+                )
</ins><span class="cx">                 continue
</span><span class="cx"> 
</span><span class="cx">             itipmsg = iTipGenerator.generateAttendeeRequest(self.calendar, (attendee,), self.changed_rids)
</span><span class="lines">@@ -1378,13 +1317,22 @@
</span><span class="cx">             # Send scheduling message
</span><span class="cx">             if itipmsg is not None:
</span><span class="cx"> 
</span><del>-                # Add split details if needed
-                if self.split_details is not None:
-                    rid, uid, newer_piece = self.split_details
-                    itipmsg.addProperty(Property(&quot;X-CALENDARSERVER-SPLIT-RID&quot;, rid))
-                    itipmsg.addProperty(Property(&quot;X-CALENDARSERVER-SPLIT-OLDER-UID&quot; if newer_piece else &quot;X-CALENDARSERVER-SPLIT-NEWER-UID&quot;, uid))
</del><ins>+                if queued:
+                    # Always make it look like scheduling succeeded when queuing
+                    self.calendar.setParameterToValueForPropertyWithValue(
+                        &quot;SCHEDULE-STATUS&quot;,
+                        iTIPRequestStatus.MESSAGE_DELIVERED_CODE,
+                        &quot;ATTENDEE&quot;,
+                        attendee,
+                    )
+                else:
+                    # Add split details if needed
+                    if self.split_details is not None:
+                        rid, uid, newer_piece = self.split_details
+                        itipmsg.addProperty(Property(&quot;X-CALENDARSERVER-SPLIT-RID&quot;, rid))
+                        itipmsg.addProperty(Property(&quot;X-CALENDARSERVER-SPLIT-OLDER-UID&quot; if newer_piece else &quot;X-CALENDARSERVER-SPLIT-NEWER-UID&quot;, uid))
</ins><span class="cx"> 
</span><del>-                yield self.processSend(attendee, itipmsg, count=count + cancel_count)
</del><ins>+                    yield self.processSend(attendee, itipmsg, count=count + cancel_count)
</ins><span class="cx"> 
</span><span class="cx">                 count += 1
</span><span class="cx"> 
</span><span class="lines">@@ -1454,7 +1402,8 @@
</span><span class="cx">                     &quot;SCHEDULE-STATUS&quot;,
</span><span class="cx">                     status.split(&quot;;&quot;)[0],
</span><span class="cx">                     propname,
</span><del>-                    recipient)
</del><ins>+                    recipient,
+                )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -1592,7 +1541,8 @@
</span><span class="cx">                         &quot;SCHEDULE-STATUS&quot;,
</span><span class="cx">                         iTIPRequestStatus.NO_USER_SUPPORT_CODE,
</span><span class="cx">                         &quot;ORGANIZER&quot;,
</span><del>-                        self.organizer)
</del><ins>+                        self.organizer,
+                    )
</ins><span class="cx">                 returnValue(None)
</span><span class="cx"> 
</span><span class="cx">             else:
</span><span class="lines">@@ -1658,8 +1608,14 @@
</span><span class="cx"> 
</span><span class="cx">             # Check SCHEDULE-AGENT and coerce SERVER to NONE
</span><span class="cx">             if self.calendar.getOrganizerScheduleAgent():
</span><del>-                self.calendar.setParameterToValueForPropertyWithValue(&quot;SCHEDULE-AGENT&quot;, &quot;NONE&quot;, &quot;ORGANIZER&quot;, None)
-                self.calendar.setParameterToValueForPropertyWithValue(&quot;SCHEDULE-STATUS&quot;, iTIPRequestStatus.NO_USER_SUPPORT_CODE, &quot;ORGANIZER&quot;, None)
</del><ins>+                self.calendar.setParametersForPropertyWithValue(
+                    {
+                        &quot;SCHEDULE-AGENT&quot;: &quot;NONE&quot;,
+                        &quot;SCHEDULE-STATUS&quot;: iTIPRequestStatus.NO_USER_SUPPORT_CODE,
+                    },
+                    &quot;ORGANIZER&quot;,
+                    None,
+                )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def checkOrganizerScheduleAgent(self):
</span><span class="lines">@@ -1673,8 +1629,14 @@
</span><span class="cx">         if not config.Scheduling.iSchedule.Enabled and not local_organizer and is_server:
</span><span class="cx">             # Coerce ORGANIZER to SCHEDULE-AGENT=NONE
</span><span class="cx">             log.debug(&quot;Attendee '{attendee}' is not allowed to use SCHEDULE-AGENT=SERVER on organizer: UID:{uid}&quot;, attendee=self.attendeeAddress.record, uid=self.uid)
</span><del>-            self.calendar.setParameterToValueForPropertyWithValue(&quot;SCHEDULE-AGENT&quot;, &quot;NONE&quot;, &quot;ORGANIZER&quot;, None)
-            self.calendar.setParameterToValueForPropertyWithValue(&quot;SCHEDULE-STATUS&quot;, iTIPRequestStatus.NO_USER_SUPPORT_CODE, &quot;ORGANIZER&quot;, None)
</del><ins>+            self.calendar.setParametersForPropertyWithValue(
+                {
+                    &quot;SCHEDULE-AGENT&quot;: &quot;NONE&quot;,
+                    &quot;SCHEDULE-STATUS&quot;: iTIPRequestStatus.NO_USER_SUPPORT_CODE,
+                },
+                &quot;ORGANIZER&quot;,
+                None,
+            )
</ins><span class="cx">             is_server = False
</span><span class="cx"> 
</span><span class="cx">         return is_server
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoreschedulingitippy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/itip.py (13865 => 13866)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1091,6 +1091,7 @@
</span><span class="cx">     MESSAGE_DELIVERED_CODE = &quot;1.2&quot;
</span><span class="cx"> 
</span><span class="cx">     SUCCESS_CODE = &quot;2.0&quot;
</span><ins>+    REQUEST_FORWARDED_CODE = &quot;2.7&quot;
</ins><span class="cx"> 
</span><span class="cx">     INVALID_CALENDAR_USER_CODE = &quot;3.7&quot;
</span><span class="cx">     NO_AUTHORITY_CODE = &quot;3.8&quot;
</span><span class="lines">@@ -1105,6 +1106,7 @@
</span><span class="cx">     MESSAGE_DELIVERED = MESSAGE_DELIVERED_CODE + &quot;;Scheduling message has been delivered&quot;
</span><span class="cx"> 
</span><span class="cx">     SUCCESS = SUCCESS_CODE + &quot;;Success&quot;
</span><ins>+    REQUEST_FORWARDED = REQUEST_FORWARDED_CODE + &quot;;Success; request forwarded to Calendar User.&quot;
</ins><span class="cx"> 
</span><span class="cx">     INVALID_CALENDAR_USER = INVALID_CALENDAR_USER_CODE + &quot;;Invalid Calendar User&quot;
</span><span class="cx">     NO_AUTHORITY = NO_AUTHORITY_CODE + &quot;;No authority&quot;
</span></span></pre></div>
<a id="CalendarServertrunktxdavwhotesttest_group_attendeespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/who/test/test_group_attendees.py (13865 => 13866)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -100,6 +100,8 @@
</span><span class="cx">                             attendeeProp.removeParameterValue(&quot;MEMBER&quot;, paramterValue)
</span><span class="cx">                         attendeeProp.setParameter(&quot;MEMBER&quot;, sorted(parameterValues))
</span><span class="cx"> 
</span><ins>+            return event
+
</ins><span class="cx">         self.assertEqual(
</span><span class="cx">             orderMemberValues(Component.fromString(normalize_iCalStr(iCalStr1))),
</span><span class="cx">             orderMemberValues(Component.fromString(normalize_iCalStr(iCalStr2)))
</span><span class="lines">@@ -142,7 +144,7 @@
</span><span class="cx"> DTSTART:20140101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><del>-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;RSVP=TRUE:urn:x-uid:group02
</del><ins>+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
</ins><span class="cx"> ATTENDEE;CN=User 06;EMAIL=user06@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
</span><span class="cx"> ATTENDEE;CN=User 07;EMAIL=user07@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
</span><span class="cx"> ATTENDEE;CN=User 08;EMAIL=user08@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
</span><span class="lines">@@ -201,7 +203,7 @@
</span><span class="cx"> DTSTART:20140101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><del>-ATTENDEE;CUTYPE=X-SERVER-GROUP;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:uuid:FFFFFFFF-EEEE-DDDD-CCCC-BBBBBBBBBBBB
</del><ins>+ATTENDEE;CUTYPE=X-SERVER-GROUP;SCHEDULE-STATUS=3.7:urn:uuid:FFFFFFFF-EEEE-DDDD-CCCC-BBBBBBBBBBBB
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 01;EMAIL=user01@example.com:urn:x-uid:user01
</span><span class="cx"> SUMMARY:event 1
</span><span class="lines">@@ -253,7 +255,7 @@
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 01;EMAIL=user01@example.com:urn:x-uid:user01
</span><span class="cx"> SUMMARY:event 1
</span><span class="lines">@@ -308,7 +310,7 @@
</span><span class="cx"> DTSTART:20140101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><del>-ATTENDEE;CN=Group 04;CUTYPE=X-SERVER-GROUP;RSVP=TRUE:urn:x-uid:group04
</del><ins>+ATTENDEE;CN=Group 04;CUTYPE=X-SERVER-GROUP;SCHEDULE-STATUS=2.7:urn:x-uid:group04
</ins><span class="cx"> ATTENDEE;CN=User 06;EMAIL=user06@example.com;MEMBER=&quot;urn:x-uid:group04&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
</span><span class="cx"> ATTENDEE;CN=User 07;EMAIL=user07@example.com;MEMBER=&quot;urn:x-uid:group04&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
</span><span class="cx"> ATTENDEE;CN=User 08;EMAIL=user08@example.com;MEMBER=&quot;urn:x-uid:group04&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
</span><span class="lines">@@ -376,9 +378,9 @@
</span><span class="cx"> DTSTART:20140101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;RSVP=TRUE:urn:x-uid:group03
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
</ins><span class="cx"> ATTENDEE;CN=User 06;EMAIL=user06@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
</span><span class="cx"> ATTENDEE;CN=User 07;EMAIL=user07@example.com;MEMBER=&quot;urn:x-uid:group02&quot;,&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
</span><span class="cx"> ATTENDEE;CN=User 08;EMAIL=user08@example.com;MEMBER=&quot;urn:x-uid:group02&quot;,&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
</span><span class="lines">@@ -435,7 +437,7 @@
</span><span class="cx"> DTSTART:20140101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;MEMBER=&quot;urn:x-uid:group01&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
</span><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="lines">@@ -499,7 +501,7 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="cx"> SUMMARY:event 1
</span><span class="lines">@@ -516,7 +518,7 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;MEMBER=&quot;urn:x-uid:group01&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
</span><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="lines">@@ -535,7 +537,7 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="cx"> SEQUENCE:2
</span><span class="lines">@@ -638,7 +640,7 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 0{0};EMAIL=user0{0}@example.com;RSVP=TRUE:urn:x-uid:user0{0}
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 0{0};EMAIL=user0{0}@example.com:urn:x-uid:user0{0}
</span><span class="cx"> SUMMARY:event {0}
</span><span class="lines">@@ -655,7 +657,7 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 0{0};EMAIL=user0{0}@example.com;RSVP=TRUE:urn:x-uid:user0{0}
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;MEMBER=&quot;urn:x-uid:group01&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
</span><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 0{0};EMAIL=user0{0}@example.com:urn:x-uid:user0{0}
</span><span class="lines">@@ -674,7 +676,7 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 0{0};EMAIL=user0{0}@example.com;RSVP=TRUE:urn:x-uid:user0{0}
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 0{0};EMAIL=user0{0}@example.com:urn:x-uid:user0{0}
</span><span class="cx"> SEQUENCE:2
</span><span class="lines">@@ -800,7 +802,7 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;MEMBER=&quot;urn:x-uid:group01&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
</span><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="lines">@@ -818,7 +820,7 @@
</span><span class="cx"> DTSTART:20140101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="cx"> SEQUENCE:1
</span><span class="lines">@@ -959,7 +961,7 @@
</span><span class="cx"> DTSTART:20120101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;MEMBER=&quot;urn:x-uid:group01&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
</span><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="lines">@@ -978,7 +980,7 @@
</span><span class="cx"> DTSTART:20120101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="cx"> RRULE:FREQ=DAILY;UNTIL=20140101T100000
</span><span class="lines">@@ -1087,7 +1089,7 @@
</span><span class="cx"> DTSTART:20120101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;MEMBER=&quot;urn:x-uid:group01&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
</span><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="lines">@@ -1105,7 +1107,7 @@
</span><span class="cx"> UID:event1@ninevah.local
</span><span class="cx"> {start}DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="cx"> {relatedTo}RRULE:FREQ=DAILY;UNTIL=20240101T100000
</span><span class="lines">@@ -1122,7 +1124,7 @@
</span><span class="cx"> {uid}DTSTART:20120101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;MEMBER=&quot;urn:x-uid:group01&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
</span><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="lines">@@ -1234,7 +1236,7 @@
</span><span class="cx"> DTSTART:20120101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="cx"> RRULE:FREQ=DAILY;UNTIL=20240101T100000
</span><span class="lines">@@ -1251,7 +1253,7 @@
</span><span class="cx"> UID:event1@ninevah.local
</span><span class="cx"> {start}DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;MEMBER=&quot;urn:x-uid:group01&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
</span><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="lines">@@ -1269,7 +1271,7 @@
</span><span class="cx"> {uid}DTSTART:20120101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 02;EMAIL=user02@example.com;RSVP=TRUE:urn:x-uid:user02
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> ORGANIZER;CN=User 02;EMAIL=user02@example.com:urn:x-uid:user02
</span><span class="cx"> {relatedTo}{rule}SEQUENCE:1
</span><span class="lines">@@ -1395,9 +1397,9 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;RSVP=TRUE:urn:x-uid:group03
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
</ins><span class="cx"> ATTENDEE;CN=User 06;EMAIL=user06@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
</span><span class="cx"> ATTENDEE;CN=User 07;EMAIL=user07@example.com;MEMBER=&quot;urn:x-uid:group02&quot;,&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
</span><span class="cx"> ATTENDEE;CN=User 08;EMAIL=user08@example.com;MEMBER=&quot;urn:x-uid:group02&quot;,&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
</span><span class="lines">@@ -1417,9 +1419,9 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;RSVP=TRUE:urn:x-uid:group03
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;SCHEDULE-STATUS=3.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
</ins><span class="cx"> ATTENDEE;CN=User 07;EMAIL=user07@example.com;MEMBER=&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
</span><span class="cx"> ATTENDEE;CN=User 08;EMAIL=user08@example.com;MEMBER=&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
</span><span class="cx"> ATTENDEE;CN=User 09;EMAIL=user09@example.com;MEMBER=&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user09
</span><span class="lines">@@ -1440,9 +1442,9 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><del>-ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;RSVP=TRUE:urn:x-uid:group01
-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;RSVP=TRUE:urn:x-uid:group03
</del><ins>+ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
</ins><span class="cx"> ATTENDEE;CN=User 06;EMAIL=user06@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
</span><span class="cx"> ATTENDEE;CN=User 07;EMAIL=user07@example.com;MEMBER=&quot;urn:x-uid:group02&quot;,&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
</span><span class="cx"> ATTENDEE;CN=User 08;EMAIL=user08@example.com;MEMBER=&quot;urn:x-uid:group02&quot;,&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
</span><span class="lines">@@ -1573,8 +1575,8 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><del>-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;RSVP=TRUE:urn:x-uid:group02
-ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;RSVP=TRUE:urn:x-uid:group03
</del><ins>+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
+ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
</ins><span class="cx"> ATTENDEE;CN=User 06;EMAIL=user06@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
</span><span class="cx"> ATTENDEE;CN=User 07;EMAIL=user07@example.com;MEMBER=&quot;urn:x-uid:group02&quot;,&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
</span><span class="cx"> ATTENDEE;CN=User 08;EMAIL=user08@example.com;MEMBER=&quot;urn:x-uid:group02&quot;,&quot;urn:x-uid:group03&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
</span><span class="lines">@@ -1611,7 +1613,7 @@
</span><span class="cx"> DTSTART:20240101T100000Z
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=User 01;EMAIL=user01@example.com;RSVP=TRUE:urn:x-uid:user01
</span><del>-ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;RSVP=TRUE:urn:x-uid:group02
</del><ins>+ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02@example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
</ins><span class="cx"> ATTENDEE;CN=User 06;EMAIL=user06@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
</span><span class="cx"> ATTENDEE;CN=User 07;EMAIL=user07@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
</span><span class="cx"> ATTENDEE;CN=User 08;EMAIL=user08@example.com;MEMBER=&quot;urn:x-uid:group02&quot;;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
</span></span></pre>
</div>
</div>

</body>
</html>