<!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"> """
</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"> """
</span><span class="cx">
</span><ins>+ 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}
+ """
+
</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("PARTSTAT", "NEEDS-ACTION").upper() == "NEEDS-ACTION":
- attendee.setParameter("RSVP", "TRUE")
</del><ins>+ 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")
</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 ("create", "modify",):
</span><del>- total += (yield self.processQueuedRequests())
</del><ins>+ total += (yield self.processRequests(queued=True))
</ins><span class="cx">
</span><span class="cx"> self.logItems["itip.requests"] = total
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- 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
</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):
+ """
+ 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}
+ """
+
</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 ("GROUP", "X-SERVER-GROUP"):
</del><ins>+ if attendeeAddress.hosted() and attendeeAddress.getCUType() == "GROUP":
</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("X-CALENDARSERVER-SPLIT-RID", rid))
- itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-OLDER-UID" if newer_piece else "X-CALENDARSERVER-SPLIT-NEWER-UID", uid))
</del><ins>+ 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))
</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):
+ """
+ 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}
+ """
+
</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 ("GROUP", "X-SERVER-GROUP"):
</del><ins>+ 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,
+ )
</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("X-CALENDARSERVER-SPLIT-RID", rid))
- itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-OLDER-UID" if newer_piece else "X-CALENDARSERVER-SPLIT-NEWER-UID", uid))
</del><ins>+ 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))
</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"> "SCHEDULE-STATUS",
</span><span class="cx"> status.split(";")[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"> "SCHEDULE-STATUS",
</span><span class="cx"> iTIPRequestStatus.NO_USER_SUPPORT_CODE,
</span><span class="cx"> "ORGANIZER",
</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("SCHEDULE-AGENT", "NONE", "ORGANIZER", None)
- self.calendar.setParameterToValueForPropertyWithValue("SCHEDULE-STATUS", iTIPRequestStatus.NO_USER_SUPPORT_CODE, "ORGANIZER", None)
</del><ins>+ self.calendar.setParametersForPropertyWithValue(
+ {
+ "SCHEDULE-AGENT": "NONE",
+ "SCHEDULE-STATUS": iTIPRequestStatus.NO_USER_SUPPORT_CODE,
+ },
+ "ORGANIZER",
+ 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("Attendee '{attendee}' is not allowed to use SCHEDULE-AGENT=SERVER on organizer: UID:{uid}", attendee=self.attendeeAddress.record, uid=self.uid)
</span><del>- self.calendar.setParameterToValueForPropertyWithValue("SCHEDULE-AGENT", "NONE", "ORGANIZER", None)
- self.calendar.setParameterToValueForPropertyWithValue("SCHEDULE-STATUS", iTIPRequestStatus.NO_USER_SUPPORT_CODE, "ORGANIZER", None)
</del><ins>+ self.calendar.setParametersForPropertyWithValue(
+ {
+ "SCHEDULE-AGENT": "NONE",
+ "SCHEDULE-STATUS": iTIPRequestStatus.NO_USER_SUPPORT_CODE,
+ },
+ "ORGANIZER",
+ 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 = "1.2"
</span><span class="cx">
</span><span class="cx"> SUCCESS_CODE = "2.0"
</span><ins>+ REQUEST_FORWARDED_CODE = "2.7"
</ins><span class="cx">
</span><span class="cx"> INVALID_CALENDAR_USER_CODE = "3.7"
</span><span class="cx"> NO_AUTHORITY_CODE = "3.8"
</span><span class="lines">@@ -1105,6 +1106,7 @@
</span><span class="cx"> MESSAGE_DELIVERED = MESSAGE_DELIVERED_CODE + ";Scheduling message has been delivered"
</span><span class="cx">
</span><span class="cx"> SUCCESS = SUCCESS_CODE + ";Success"
</span><ins>+ REQUEST_FORWARDED = REQUEST_FORWARDED_CODE + ";Success; request forwarded to Calendar User."
</ins><span class="cx">
</span><span class="cx"> INVALID_CALENDAR_USER = INVALID_CALENDAR_USER_CODE + ";Invalid Calendar User"
</span><span class="cx"> NO_AUTHORITY = NO_AUTHORITY_CODE + ";No authority"
</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("MEMBER", paramterValue)
</span><span class="cx"> attendeeProp.setParameter("MEMBER", 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="urn:x-uid:group02";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="urn:x-uid:group02";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="urn:x-uid:group02";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="urn:x-uid:group04";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="urn:x-uid:group04";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="urn:x-uid:group04";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="urn:x-uid:group02";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="urn:x-uid:group02","urn:x-uid:group03";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="urn:x-uid:group02","urn:x-uid:group03";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="urn:x-uid:group01";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="urn:x-uid:group01";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="urn:x-uid:group01";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="urn:x-uid:group01";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="urn:x-uid:group01";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="urn:x-uid:group01";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="urn:x-uid:group01";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="urn:x-uid:group01";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="urn:x-uid:group02";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="urn:x-uid:group02","urn:x-uid:group03";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="urn:x-uid:group02","urn:x-uid:group03";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="urn:x-uid:group03";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="urn:x-uid:group03";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="urn:x-uid:group03";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="urn:x-uid:group02";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="urn:x-uid:group02","urn:x-uid:group03";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="urn:x-uid:group02","urn:x-uid:group03";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="urn:x-uid:group02";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="urn:x-uid:group02","urn:x-uid:group03";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="urn:x-uid:group02","urn:x-uid:group03";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="urn:x-uid:group02";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="urn:x-uid:group02";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="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
</span></span></pre>
</div>
</div>
</body>
</html>