<!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>[15328] 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/15328">15328</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2015-11-17 16:56:59 -0800 (Tue, 17 Nov 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>Support cross-pod scheduling between v5 and v8 servers.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkconfcaldavdtestpodAplist">CalendarServer/trunk/conf/caldavd-test-podA.plist</a></li>
<li><a href="#CalendarServertrunkconfcaldavdtestpodBplist">CalendarServer/trunk/conf/caldavd-test-podB.plist</a></li>
<li><a href="#CalendarServertrunkconflocalserversdtd">CalendarServer/trunk/conf/localservers.dtd</a></li>
<li><a href="#CalendarServertrunktwistedcaldavicalpy">CalendarServer/trunk/twistedcaldav/ical.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavtesttest_icalendarpy">CalendarServer/trunk/twistedcaldav/test/test_icalendar.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoreschedulingischeduledeliverypy">CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/delivery.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoreschedulingischedulelocalserverspy">CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/localservers.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoreschedulingischeduleremoteserverspy">CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/remoteservers.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoreschedulingischeduletesttest_deliverypy">CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/test/test_delivery.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoreschedulingischeduletesttest_localserverspy">CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/test/test_localservers.py</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkconfcaldavdtestpodAplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/conf/caldavd-test-podA.plist (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/conf/caldavd-test-podA.plist        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/conf/caldavd-test-podA.plist        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -106,8 +106,6 @@
</span><span class="cx">          <string>./conf/localservers-test.xml</string>
</span><span class="cx">          <key>MaxClients</key>
</span><span class="cx">          <integer>5</integer>
</span><del>-         <key>InboxName</key>
-         <string>podding</string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx"> <key>Notifications</key>
</span></span></pre></div>
<a id="CalendarServertrunkconfcaldavdtestpodBplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/conf/caldavd-test-podB.plist (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/conf/caldavd-test-podB.plist        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/conf/caldavd-test-podB.plist        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -106,8 +106,6 @@
</span><span class="cx">          <string>./conf/localservers-test.xml</string>
</span><span class="cx">          <key>MaxClients</key>
</span><span class="cx">          <integer>5</integer>
</span><del>-         <key>InboxName</key>
-         <string>podding</string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx"> <key>Notifications</key>
</span></span></pre></div>
<a id="CalendarServertrunkconflocalserversdtd"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/conf/localservers.dtd (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/conf/localservers.dtd        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/conf/localservers.dtd        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -17,7 +17,7 @@
</span><span class="cx"> <!ELEMENT servers (server*) >
</span><span class="cx">
</span><span class="cx">         <!ELEMENT server (id, uri, allowed-from*, shared-secret?) >
</span><del>-                <!ATTLIST server implicit (yes|no) "yes">
</del><ins>+                <!ATTLIST server v5 (yes|no) "no">
</ins><span class="cx">
</span><span class="cx">                 <!ELEMENT id (#PCDATA) >
</span><span class="cx">                 <!ELEMENT uri (#PCDATA) >
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavicalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/ical.py (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/ical.py        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/twistedcaldav/ical.py        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -3463,7 +3463,7 @@
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def normalizeCalendarUserAddresses(
</span><del>- self, lookupFunction, recordFunction, toCanonical=True
</del><ins>+ self, lookupFunction, recordFunction, toCanonical=True, toURN_UUID=False,
</ins><span class="cx"> ):
</span><span class="cx"> """
</span><span class="cx"> Do the ORGANIZER/ATTENDEE property normalization.
</span><span class="lines">@@ -3477,10 +3477,14 @@
</span><span class="cx"> @param toCanonical: whether to convert to the canonical CUA form (True)
</span><span class="cx"> or to the mailto: form (False)
</span><span class="cx"> @type toCanonical: L{bool}
</span><ins>+
+ @param toURN_UUID: whether to convert to urn:x-uid to urn:uuid: for
+ compatibility with older servers
+ @type toURN_UUID: L{bool}
</ins><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> # Keep a cache of records because events with lots of recurrence overrides can contain
</span><del>- # the same attendee cu-address multuiple times
</del><ins>+ # the same attendee cu-address multiple times
</ins><span class="cx"> cache = {}
</span><span class="cx">
</span><span class="cx"> for component in self.subcomponents(ignore=True):
</span><span class="lines">@@ -3513,6 +3517,10 @@
</span><span class="cx"> # Always re-write value to urn:x-uid
</span><span class="cx"> prop.setValue("urn:x-uid:{uid}".format(uid=uid))
</span><span class="cx">
</span><ins>+ # Look for urn:x-uid: -> urn:uuid: conversion
+ elif toURN_UUID and cuaddr.startswith("urn:x-uid:"):
+ prop.setValue(cuaddr.replace("urn:x-uid:", "urn:uuid:"))
+
</ins><span class="cx"> # If it is already a non-x-uid address leave it be
</span><span class="cx"> elif (cuaddr.startswith("urn:x-uid:") or cuaddr.startswith("urn:uuid:")):
</span><span class="cx">
</span><span class="lines">@@ -3910,7 +3918,7 @@
</span><span class="cx"> # #
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>-def normalizeCUAddress(cuaddr, lookupFunction, recordFunction, toCanonical=True):
</del><ins>+def normalizeCUAddress(cuaddr, lookupFunction, recordFunction, toCanonical=True, toURN_UUID=False):
</ins><span class="cx"> # Check that we can lookup this calendar user address - if not
</span><span class="cx"> # we cannot do anything with it
</span><span class="cx"> _ignore_name, uid, _ignore_cuType, cuaddrs = (yield lookupFunction(normalizeCUAddr(cuaddr), recordFunction, config))
</span><span class="lines">@@ -3920,6 +3928,10 @@
</span><span class="cx"> if uid:
</span><span class="cx"> returnValue("urn:x-uid:{0}".format(uid,))
</span><span class="cx">
</span><ins>+ # Look for urn:x-uid: -> urn:uuid: conversion
+ elif toURN_UUID and cuaddr.startswith("urn:x-uid:"):
+ returnValue(cuaddr.replace("urn:x-uid:", "urn:uuid:"))
+
</ins><span class="cx"> # If it is already a non-x-uid address leave it be
</span><span class="cx"> elif (cuaddr.startswith("urn:x-uid:") or cuaddr.startswith("urn:uuid:")):
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavtesttest_icalendarpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -8191,6 +8191,76 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><ins>+ def test_normalizeCalendarUserAddressesFromCanonical_URN_UUID(self):
+ """
+ Ensure mailto is preferred, followed by path form, then http form.
+ """
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+DTSTART:20071114T000000Z
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20071114T000000Z
+ATTENDEE:urn:x-uid:foo
+ATTENDEE:urn:x-uid:bar
+ATTENDEE:urn:x-uid:baz
+ATTENDEE:urn:x-uid:buz
+DTSTAMP:20071114T000000Z
+END:VEVENT
+END:VCALENDAR
+"""
+
+ component = Component.fromString(data)
+
+
+ def lookupFunction(cuaddr, ignored1, ignored2):
+ return succeed(
+ {
+ "urn:x-uid:foo" : (
+ "Foo",
+ "foo",
+ "INDIVIDUAL",
+ ("urn:x-uid:foo", "urn:uuid:foo", "http://example.com/foo", "/foo")
+ ),
+ "urn:x-uid:bar" : (
+ "Bar",
+ "bar",
+ "INDIVIDUAL",
+ ("urn:x-uid:bar", "urn:uuid:bar", "mailto:bar@example.com", "http://example.com/bar", "/bar")
+ ),
+ "urn:x-uid:baz" : (
+ "Baz",
+ "baz",
+ "INDIVIDUAL",
+ ("urn:x-uid:baz", "urn:uuid:baz", "http://example.com/baz")
+ ),
+ "urn:x-uid:buz" : (
+ "Buz",
+ "buz",
+ "INDIVIDUAL",
+ ("urn:x-uid:buz", "urn:uuid:buz", "http://example.com/buz")
+ ),
+ }[cuaddr]
+ )
+
+ yield component.normalizeCalendarUserAddresses(lookupFunction, None, toCanonical=False, toURN_UUID=True)
+
+ self.assertEquals(
+ "urn:uuid:foo",
+ component.getAttendeeProperty(("urn:uuid:foo",)).value())
+ self.assertEquals(
+ "urn:uuid:bar",
+ component.getAttendeeProperty(("urn:uuid:bar",)).value())
+ self.assertEquals(
+ "urn:uuid:baz",
+ component.getAttendeeProperty(("urn:uuid:baz",)).value())
+ self.assertEquals(
+ "urn:uuid:buz",
+ component.getAttendeeProperty(("urn:uuid:buz",)).value())
+
+
+ @inlineCallbacks
</ins><span class="cx"> def test_normalizeCalendarUserAddressesAndLocationChange(self):
</span><span class="cx"> """
</span><span class="cx"> Ensure http(s) and /path CUA values are tucked away into the property
</span><span class="lines">@@ -9174,6 +9244,82 @@
</span><span class="cx"> self.assertEquals(new_cuaddr, result)
</span><span class="cx">
</span><span class="cx">
</span><ins>+ @inlineCallbacks
+ def test_normalizeCUAddressFromCanonical_URN_UUID(self):
+ """
+ Ensure mailto is preferred, followed by path form, then http form.
+ """
+
+ data = (
+ ("urn:uuid:foo", "/foo"),
+ ("urn:uuid:bar", "mailto:bar@example.com",),
+ ("urn:uuid:baz", "http://example.com/baz",),
+ ("urn:uuid:buz", "urn:x-uid:buz",),
+ ("urn:x-uid:foo", "urn:uuid:foo"),
+ ("urn:x-uid:bar", "urn:uuid:bar",),
+ ("urn:x-uid:baz", "urn:uuid:baz",),
+ ("urn:x-uid:buz", "urn:uuid:buz",),
+ )
+
+ def lookupFunction(cuaddr, ignored1, ignored2):
+ return succeed(
+ {
+ "urn:uuid:foo" : (
+ "Foo",
+ "foo",
+ "INDIVIDUAL",
+ ("urn:x-uid:foo", "urn:uuid:foo", "http://example.com/foo", "/foo")
+ ),
+ "urn:uuid:bar" : (
+ "Bar",
+ "bar",
+ "INDIVIDUAL",
+ ("urn:x-uid:bar", "urn:uuid:bar", "mailto:bar@example.com", "http://example.com/bar", "/bar")
+ ),
+ "urn:uuid:baz" : (
+ "Baz",
+ "baz",
+ "INDIVIDUAL",
+ ("urn:x-uid:baz", "urn:uuid:baz", "http://example.com/baz")
+ ),
+ "urn:uuid:buz" : (
+ "Buz",
+ "buz",
+ "INDIVIDUAL",
+ ("urn:x-uid:buz", "urn:uuid:buz",)
+ ),
+ "urn:x-uid:foo" : (
+ "Foo",
+ "foo",
+ "INDIVIDUAL",
+ ("urn:x-uid:foo", "urn:uuid:foo", "http://example.com/foo", "/foo")
+ ),
+ "urn:x-uid:bar" : (
+ "Bar",
+ "bar",
+ "INDIVIDUAL",
+ ("urn:x-uid:bar", "urn:uuid:bar", "mailto:bar@example.com", "http://example.com/bar", "/bar")
+ ),
+ "urn:x-uid:baz" : (
+ "Baz",
+ "baz",
+ "INDIVIDUAL",
+ ("urn:x-uid:baz", "urn:uuid:baz", "http://example.com/baz")
+ ),
+ "urn:x-uid:buz" : (
+ "Buz",
+ "buz",
+ "INDIVIDUAL",
+ ("urn:x-uid:buz", "urn:uuid:buz",)
+ ),
+ }[cuaddr]
+ )
+
+ for cuaddr, result in data:
+ new_cuaddr = yield normalizeCUAddress(cuaddr, lookupFunction, None, toCanonical=False, toURN_UUID=True)
+ self.assertEquals(new_cuaddr, result)
+
+
</ins><span class="cx"> def test_hasPropertyWithParameterMatch(self):
</span><span class="cx">
</span><span class="cx"> data = (
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoreschedulingischeduledeliverypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/delivery.py (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/delivery.py        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/delivery.py        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -193,7 +193,7 @@
</span><span class="cx"> if serverURI not in self.otherServers:
</span><span class="cx"> self.otherServers[serverURI] = IScheduleServerRecord(
</span><span class="cx"> uri=joinURL(serverURI, config.Servers.InboxName),
</span><del>- unNormalizeAddresses=not recipient.record.server().isImplicit,
</del><ins>+ rewriteCUAddresses=recipient.record.server().v5,
</ins><span class="cx"> moreHeaders=[recipient.record.server().secretHeader(), ],
</span><span class="cx"> podding=True,
</span><span class="cx"> )
</span><span class="lines">@@ -379,13 +379,28 @@
</span><span class="cx">
</span><span class="cx"> # The Originator must be the ORGANIZER (for a request) or ATTENDEE (for a reply)
</span><span class="cx"> originator = self.scheduler.organizer.cuaddr if self.scheduler.isiTIPRequest else self.scheduler.attendee
</span><del>- if self.server.unNormalizeAddresses:
- originator = yield normalizeCUAddress(originator, normalizationLookup, self.scheduler.txn.directoryService().recordWithCalendarUserAddress, toCanonical=False)
</del><ins>+ if self.server.rewriteCUAddresses:
+ originator = yield normalizeCUAddress(
+ originator,
+ normalizationLookup,
+ self.scheduler.txn.directoryService().recordWithCalendarUserAddress,
+ toCanonical=False,
+ toURN_UUID=self.server.podding(),
+ )
</ins><span class="cx"> self.headers.addRawHeader("Originator", utf8String(originator))
</span><span class="cx"> self.sign_headers.append("Originator")
</span><span class="cx">
</span><span class="cx"> for recipient in self.recipients:
</span><del>- self.headers.addRawHeader("Recipient", utf8String(recipient.cuaddr))
</del><ins>+ cuaddr = recipient.cuaddr
+ if self.server.rewriteCUAddresses and self.server.podding():
+ cuaddr = yield normalizeCUAddress(
+ cuaddr,
+ normalizationLookup,
+ self.scheduler.txn.directoryService().recordWithCalendarUserAddress,
+ toCanonical=False,
+ toURN_UUID=True,
+ )
+ self.headers.addRawHeader("Recipient", utf8String(cuaddr))
</ins><span class="cx">
</span><span class="cx"> # Only one Recipient header as they get concatenated in ischedule-relaxed canonicalization
</span><span class="cx"> self.sign_headers.append("Recipient")
</span><span class="lines">@@ -434,11 +449,13 @@
</span><span class="cx"> # Need to remap cuaddrs from urn:uuid
</span><span class="cx"> normalizedCalendar = self.scheduler.calendar.duplicate()
</span><span class="cx"> self.original_organizer = normalizedCalendar.getOrganizer()
</span><del>- if self.server.unNormalizeAddresses:
</del><ins>+ if self.server.rewriteCUAddresses:
</ins><span class="cx"> yield normalizedCalendar.normalizeCalendarUserAddresses(
</span><span class="cx"> normalizationLookup,
</span><span class="cx"> self.scheduler.txn.directoryService().recordWithCalendarUserAddress,
</span><del>- toCanonical=False)
</del><ins>+ toCanonical=False,
+ toURN_UUID=self.server.podding(),
+ )
</ins><span class="cx">
</span><span class="cx"> # For VFREEBUSY we need to strip out ATTENDEEs that do not match the recipient list
</span><span class="cx"> if self.scheduler.isfreebusy:
</span><span class="lines">@@ -524,7 +541,7 @@
</span><span class="cx"> calendar_data = response.childOfType(CalendarData)
</span><span class="cx"> if calendar_data:
</span><span class="cx"> calendar_data = str(calendar_data)
</span><del>- if self.server.unNormalizeAddresses and self.original_organizer is not None:
</del><ins>+ if self.server.rewriteCUAddresses and self.original_organizer is not None:
</ins><span class="cx"> # Need to restore original ORGANIZER value if it got unnormalized
</span><span class="cx"> calendar = Component.fromString(calendar_data)
</span><span class="cx"> organizers = calendar.getAllPropertiesInAnyComponent("ORGANIZER", depth=1)
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoreschedulingischedulelocalserverspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/localservers.py (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/localservers.py        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/localservers.py        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -148,7 +148,7 @@
</span><span class="cx"> self.ips = set()
</span><span class="cx"> self.allowed_from_ips = set()
</span><span class="cx"> self.shared_secret = sharedSecret
</span><del>- self.isImplicit = True
</del><ins>+ self.v5 = False # Needs old style urn:uuid cu-address
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def details(self):
</span><span class="lines">@@ -274,7 +274,7 @@
</span><span class="cx"> ELEMENT_URI = "uri"
</span><span class="cx"> ELEMENT_ALLOWED_FROM = "allowed-from"
</span><span class="cx"> ELEMENT_SHARED_SECRET = "shared-secret"
</span><del>-ATTR_IMPLICIT = "implicit"
</del><ins>+ATTR_V5 = "v5"
</ins><span class="cx"> ATTR_VALUE_YES = "yes"
</span><span class="cx"> ATTR_VALUE_NO = "no"
</span><span class="cx">
</span><span class="lines">@@ -299,7 +299,7 @@
</span><span class="cx"> raise RuntimeError("Unknown server type: '{}' in servers file: '{}'".format(child.tag, xmlFile,))
</span><span class="cx">
</span><span class="cx"> server = Server()
</span><del>- server.isImplicit = child.get(ATTR_IMPLICIT, ATTR_VALUE_YES) == ATTR_VALUE_YES
</del><ins>+ server.v5 = child.get(ATTR_V5, ATTR_VALUE_NO) == ATTR_VALUE_YES
</ins><span class="cx">
</span><span class="cx"> for node in child:
</span><span class="cx"> if node.tag == ELEMENT_ID:
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoreschedulingischeduleremoteserverspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/remoteservers.py (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/remoteservers.py        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/remoteservers.py        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -138,7 +138,7 @@
</span><span class="cx"> """
</span><span class="cx"> Contains server-to-server details.
</span><span class="cx"> """
</span><del>- def __init__(self, uri=None, unNormalizeAddresses=True, moreHeaders=[], podding=False):
</del><ins>+ def __init__(self, uri=None, rewriteCUAddresses=True, moreHeaders=[], podding=False):
</ins><span class="cx"> """
</span><span class="cx"> @param recordType: record type for directory entry.
</span><span class="cx"> """
</span><span class="lines">@@ -148,7 +148,7 @@
</span><span class="cx"> self.allow_to = True
</span><span class="cx"> self.domains = []
</span><span class="cx"> self.client_hosts = []
</span><del>- self.unNormalizeAddresses = unNormalizeAddresses
</del><ins>+ self.rewriteCUAddresses = rewriteCUAddresses
</ins><span class="cx"> self.moreHeaders = moreHeaders
</span><span class="cx"> self._podding = podding
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoreschedulingischeduletesttest_deliverypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/test/test_delivery.py (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/test/test_delivery.py        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/test/test_delivery.py        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -20,11 +20,17 @@
</span><span class="cx"> from twisted.trial import unittest
</span><span class="cx"> from twistedcaldav.stdconfig import config
</span><span class="cx"> from txdav.caldav.datastore.scheduling.ischedule import utils
</span><del>-from txdav.caldav.datastore.scheduling.ischedule.delivery import ScheduleViaISchedule
</del><ins>+from txdav.caldav.datastore.scheduling.ischedule.delivery import ScheduleViaISchedule, \
+ IScheduleRequest
+from txdav.caldav.datastore.scheduling.ischedule.remoteservers import IScheduleServerRecord
+from txdav.caldav.datastore.scheduling.cuaddress import CalendarUser
+from txdav.common.datastore.test.util import CommonCommonTests
+import txweb2.dav.test.util
+from twistedcaldav.ical import Component
</ins><span class="cx">
</span><del>-class CalDAV (unittest.TestCase):
</del><ins>+class TestiSchedule (unittest.TestCase):
</ins><span class="cx"> """
</span><del>- txdav.caldav.datastore.scheduling.caldav tests
</del><ins>+ txdav.caldav.datastore.scheduling.ischedule tests
</ins><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> def tearDown(self):
</span><span class="lines">@@ -71,3 +77,219 @@
</span><span class="cx"> self.patch(config.Scheduling.iSchedule, "Enabled", False)
</span><span class="cx"> result = yield ScheduleViaISchedule.matchCalendarUserAddress("mailto:user@example.com")
</span><span class="cx"> self.assertFalse(result)
</span><ins>+
+
+
+class TestIScheduleRequest (CommonCommonTests, txweb2.dav.test.util.TestCase):
+ """
+ txdav.caldav.datastore.scheduling.ischedule tests
+ """
+
+ class FakeScheduler(object):
+ def __init__(self, txn, organizer, caldata=None):
+ self.txn = txn
+ self.organizer = CalendarUser(organizer)
+ self.calendar = Component.fromString(caldata) if caldata else None
+ self.isiTIPRequest = True
+ self.isfreebusy = False
+
+
+ @inlineCallbacks
+ def setUp(self):
+ yield super(TestIScheduleRequest, self).setUp()
+ yield self.buildStoreAndDirectory()
+
+
+ @inlineCallbacks
+ def test_prepareHeaders_podding(self):
+ """
+ Make sure Originator header is properly re-written.
+ """
+
+ txn = self.transactionUnderTest()
+ server = IScheduleServerRecord("https://calendar.example.com", rewriteCUAddresses=False, podding=True)
+ request = IScheduleRequest(
+ self.FakeScheduler(txn, "urn:x-uid:user01"),
+ server,
+ (CalendarUser("urn:x-uid:user02"),),
+ None, False,
+ )
+ _ignore_ssl, host, port, _ignore_path = server.details()
+ yield request._prepareHeaders(host, port, "VEVENT", "REQUEST")
+ yield txn.commit()
+
+ self.assertEqual(request.headers.getRawHeaders("Originator")[0], "urn:x-uid:user01")
+ self.assertEqual(request.headers.getRawHeaders("Recipient")[0], "urn:x-uid:user02")
+
+
+ @inlineCallbacks
+ def test_prepareHeaders_podding_with_rewrite(self):
+ """
+ Make sure Originator header is properly re-written.
+ """
+
+ txn = self.transactionUnderTest()
+ server = IScheduleServerRecord("https://calendar.example.com", rewriteCUAddresses=True, podding=True)
+ request = IScheduleRequest(
+ self.FakeScheduler(txn, "urn:x-uid:user01"),
+ server,
+ (CalendarUser("urn:x-uid:user02"),),
+ None, False,
+ )
+ _ignore_ssl, host, port, _ignore_path = server.details()
+ yield request._prepareHeaders(host, port, "VEVENT", "REQUEST")
+ yield txn.commit()
+
+ self.assertEqual(request.headers.getRawHeaders("Originator")[0], "urn:uuid:user01")
+ self.assertEqual(request.headers.getRawHeaders("Recipient")[0], "urn:uuid:user02")
+
+
+ @inlineCallbacks
+ def test_prepareHeaders_nopodding_with_rewrite(self):
+ """
+ Make sure Originator header is properly re-written.
+ """
+
+ txn = self.transactionUnderTest()
+ server = IScheduleServerRecord("https://calendar.example.com", rewriteCUAddresses=True, podding=False)
+ request = IScheduleRequest(
+ self.FakeScheduler(txn, "urn:x-uid:user01"),
+ server,
+ (CalendarUser("mailto:user02@example.com"),),
+ None, False,
+ )
+ _ignore_ssl, host, port, _ignore_path = server.details()
+ yield request._prepareHeaders(host, port, "VEVENT", "REQUEST")
+ yield txn.commit()
+
+ self.assertEqual(request.headers.getRawHeaders("Originator")[0], "mailto:user01@example.com")
+ self.assertEqual(request.headers.getRawHeaders("Recipient")[0], "mailto:user02@example.com")
+
+
+ @inlineCallbacks
+ def test_prepareData_podding(self):
+ """
+ Make sure Originator header is properly re-written.
+ """
+
+ txn = self.transactionUnderTest()
+ server = IScheduleServerRecord("https://calendar.example.com", rewriteCUAddresses=False, podding=True)
+ request = IScheduleRequest(
+ self.FakeScheduler(
+ txn, "urn:x-uid:user01",
+ """BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20051222T205953Z
+CREATED:20060101T150000Z
+DTSTART:20060101T100000Z
+DURATION:PT1H
+SUMMARY:event 1
+UID:deadlocked
+ORGANIZER:urn:x-uid:user01
+ATTENDEE;PARTSTAT=ACCEPTED:urn:x-uid:user01
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
+END:VEVENT
+END:VCALENDAR
+""",
+ ),
+ server,
+ (), None, False,
+ )
+ yield request._prepareData()
+ yield txn.commit()
+
+ ical = Component.fromString(request.data)
+ self.assertEqual(ical.masterComponent().getOrganizer(), "urn:x-uid:user01")
+ self.assertEqual(
+ set([attendee.value() for attendee in ical.getAllAttendeeProperties()]),
+ set(("urn:x-uid:user01", "urn:x-uid:user02")),
+ )
+
+
+ @inlineCallbacks
+ def test_prepareData_podding_with_rewrite(self):
+ """
+ Make sure Originator header is properly re-written.
+ """
+
+ txn = self.transactionUnderTest()
+ server = IScheduleServerRecord("https://calendar.example.com", rewriteCUAddresses=True, podding=True)
+ request = IScheduleRequest(
+ self.FakeScheduler(
+ txn, "urn:x-uid:user01",
+ """BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20051222T205953Z
+CREATED:20060101T150000Z
+DTSTART:20060101T100000Z
+DURATION:PT1H
+SUMMARY:event 1
+UID:deadlocked
+ORGANIZER:urn:x-uid:user01
+ATTENDEE;PARTSTAT=ACCEPTED:urn:x-uid:user01
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
+END:VEVENT
+END:VCALENDAR
+""",
+ ),
+ server,
+ (), None, False,
+ )
+ yield request._prepareData()
+ yield txn.commit()
+
+ ical = Component.fromString(request.data)
+ self.assertEqual(ical.masterComponent().getOrganizer(), "urn:uuid:user01")
+ self.assertEqual(
+ set([attendee.value() for attendee in ical.getAllAttendeeProperties()]),
+ set(("urn:uuid:user01", "urn:uuid:user02")),
+ )
+
+
+ @inlineCallbacks
+ def test_prepareData_nopodding_with_rewrite(self):
+ """
+ Make sure Originator header is properly re-written.
+ """
+
+ txn = self.transactionUnderTest()
+ server = IScheduleServerRecord("https://calendar.example.com", rewriteCUAddresses=True, podding=False)
+ request = IScheduleRequest(
+ self.FakeScheduler(
+ txn, "urn:x-uid:user01",
+ """BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20051222T205953Z
+CREATED:20060101T150000Z
+DTSTART:20060101T100000Z
+DURATION:PT1H
+SUMMARY:event 1
+UID:deadlocked
+ORGANIZER:urn:x-uid:user01
+ATTENDEE;PARTSTAT=ACCEPTED:urn:x-uid:user01
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
+END:VEVENT
+END:VCALENDAR
+""",
+ ),
+ server,
+ (), None, False,
+ )
+ yield request._prepareData()
+ yield txn.commit()
+
+ ical = Component.fromString(request.data)
+ self.assertEqual(ical.masterComponent().getOrganizer(), "mailto:user01@example.com")
+ self.assertEqual(
+ set([attendee.value() for attendee in ical.getAllAttendeeProperties()]),
+ set(("mailto:user01@example.com", "mailto:user02@example.com")),
+ )
</ins></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoreschedulingischeduletesttest_localserverspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/test/test_localservers.py (15327 => 15328)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/test/test_localservers.py        2015-11-18 00:27:31 UTC (rev 15327)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/ischedule/test/test_localservers.py        2015-11-18 00:56:59 UTC (rev 15328)
</span><span class="lines">@@ -59,6 +59,26 @@
</span><span class="cx"> </servers>
</span><span class="cx"> """
</span><span class="cx">
</span><ins>+ data_v5 = """<?xml version="1.0" encoding="utf-8"?>
+<servers>
+ <server>
+ <id>00001</id>
+ <uri>http://caldav1.example.com:8008</uri>
+ <allowed-from>127.0.0.1</allowed-from>
+ <shared-secret>foobar</shared-secret>
+ </server>
+ <server v5='yes'>
+ <id>00002</id>
+ <uri>https://caldav2.example.com:8843</uri>
+ </server>
+ <server v5='no'>
+ <id>00003</id>
+ <uri>https://caldav3.example.com:8943</uri>
+ </server>
+</servers>
+"""
+
+
</ins><span class="cx"> def _setupServers(self, data=data1):
</span><span class="cx"> self.patch(config, "ServerHostName", "caldav1.example.com")
</span><span class="cx"> self.patch(config, "HTTPPort", 8008)
</span><span class="lines">@@ -178,3 +198,12 @@
</span><span class="cx">
</span><span class="cx"> request = SimpleRequest(None, "POST", "/ischedule")
</span><span class="cx"> self.assertTrue(servers.getServerById("00002").checkSharedSecret(request.headers))
</span><ins>+
+
+ def test_urn_uuid(self):
+
+ servers = self._setupServers(self.data_v5)
+
+ self.assertFalse(servers.getServerById("00001").v5)
+ self.assertTrue(servers.getServerById("00002").v5)
+ self.assertFalse(servers.getServerById("00003").v5)
</ins></span></pre>
</div>
</div>
</body>
</html>