<!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>[14174] CalendarServer/branches/release/CalendarServer-6.0-dev</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/14174">14174</a></dd>
<dt>Author</dt> <dd>wsanchez@apple.com</dd>
<dt>Date</dt> <dd>2014-11-14 13:08:05 -0800 (Fri, 14 Nov 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Pulled up <a href="http://trac.calendarserver.org//changeset/14164">r14164</a> <a href="http://trac.calendarserver.org//changeset/14172">r14172</a> from trunk.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavstdconfigpy">CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/stdconfig.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavstorebridgepy">CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/storebridge.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavtesttest_collectioncontentspy">CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/test/test_collectioncontents.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavtesttest_utilpy">CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/test/test_util.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavutilpy">CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/util.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoreschedulingicaldiffpy">CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/icaldiff.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoreschedulingimplicitpy">CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/implicit.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoreschedulingtesttest_icaldiffpy">CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/test/test_icaldiff.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoresqlpy">CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoresql_externalpy">CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/sql_external.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavicalendarstorepy">CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/icalendarstore.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtxdavcarddavdatastoresqlpy">CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/carddav/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60devtxdavcommondatastoresqlpy">CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/common/datastore/sql.py</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#CalendarServerbranchesreleaseCalendarServer60dev">CalendarServer/branches/release/CalendarServer-6.0-dev/</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServerbranchesreleaseCalendarServer60dev"></a>
<div class="propset"><h4>Property changes: CalendarServer/branches/release/CalendarServer-6.0-dev</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4>Modified: svn:mergeinfo</h4></div>
<span class="cx">/CalendarServer/branches/config-separation:4379-4443
</span><span class="cx">/CalendarServer/branches/egg-info-351:4589-4625
</span><span class="cx">/CalendarServer/branches/generic-sqlstore:6167-6191
</span><span class="cx">/CalendarServer/branches/new-store:5594-5934
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile:5911-5935
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-5.1-dev:11846
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-5.2-dev:11972,12357-12358,12794,12814
</span><span class="cx">/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
</span><span class="cx">/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
</span><span class="cx">/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
</span><span class="cx">/CalendarServer/branches/users/cdaboo/cross-pod-sharing:12038-12191
</span><span class="cx">/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
</span><span class="cx">/CalendarServer/branches/users/cdaboo/fix-no-ischedule:11607-11871
</span><span class="cx">/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
</span><span class="cx">/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
</span><span class="cx">/CalendarServer/branches/users/cdaboo/json:11622-11912
</span><span class="cx">/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
</span><span class="cx">/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
</span><span class="cx">/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
</span><span class="cx">/CalendarServer/branches/users/cdaboo/performance-tweaks:11824-11836
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pods:7297-7377
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycard:7227-7237
</span><span class="cx">/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
</span><span class="cx">/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
</span><span class="cx">/CalendarServer/branches/users/cdaboo/reverse-proxy-pods:11875-11900
</span><span class="cx">/CalendarServer/branches/users/cdaboo/scheduling-queue-refresh:11783-12557
</span><span class="cx">/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
</span><span class="cx">/CalendarServer/branches/users/cdaboo/sharing-in-the-store:11935-12016
</span><span class="cx">/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
</span><span class="cx">/CalendarServer/branches/users/cdaboo/timezones:7443-7699
</span><span class="cx">/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
</span><span class="cx">/CalendarServer/branches/users/gaya/cleanrevisions:12152-12334
</span><span class="cx">/CalendarServer/branches/users/gaya/groupsharee2:13669-13773
</span><span class="cx">/CalendarServer/branches/users/gaya/sharedgroupfixes:12120-12142
</span><span class="cx">/CalendarServer/branches/users/gaya/sharedgroups-3:11088-11204
</span><span class="cx">/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
</span><span class="cx">/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
</span><span class="cx">/CalendarServer/branches/users/glyph/conn-limit:6574-6577
</span><span class="cx">/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
</span><span class="cx">/CalendarServer/branches/users/glyph/dalify:6932-7023
</span><span class="cx">/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
</span><span class="cx">/CalendarServer/branches/users/glyph/deploybuild:7563-7572
</span><span class="cx">/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
</span><span class="cx">/CalendarServer/branches/users/glyph/disable-quota:7718-7727
</span><span class="cx">/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
</span><span class="cx">/CalendarServer/branches/users/glyph/enforce-max-requests:11640-11643
</span><span class="cx">/CalendarServer/branches/users/glyph/hang-fix:11465-11491
</span><span class="cx">/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
</span><span class="cx">/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
</span><span class="cx">/CalendarServer/branches/users/glyph/launchd-wrapper-bis:11413-11436
</span><span class="cx">/CalendarServer/branches/users/glyph/linux-tests:6893-6900
</span><span class="cx">/CalendarServer/branches/users/glyph/log-cleanups:11691-11731
</span><span class="cx">/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
</span><span class="cx">/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
</span><span class="cx">/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
</span><span class="cx">/CalendarServer/branches/users/glyph/new-export:7444-7485
</span><span class="cx">/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle:7106-7155
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
</span><span class="cx">/CalendarServer/branches/users/glyph/other-html:8062-8091
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
</span><span class="cx">/CalendarServer/branches/users/glyph/q:9560-9688
</span><span class="cx">/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
</span><span class="cx">/CalendarServer/branches/users/glyph/quota:7604-7637
</span><span class="cx">/CalendarServer/branches/users/glyph/sendfdport:5388-5424
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
</span><span class="cx">/CalendarServer/branches/users/glyph/sharedpool:6490-6550
</span><span class="cx">/CalendarServer/branches/users/glyph/sharing-api:9192-9205
</span><span class="cx">/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
</span><span class="cx">/CalendarServer/branches/users/glyph/sql-store:5929-6073
</span><span class="cx">/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
</span><span class="cx">/CalendarServer/branches/users/glyph/subtransactions:7248-7258
</span><span class="cx">/CalendarServer/branches/users/glyph/table-alias:8651-8664
</span><span class="cx">/CalendarServer/branches/users/glyph/uidexport:7673-7676
</span><span class="cx">/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
</span><span class="cx">/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
</span><span class="cx">/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
</span><span class="cx">/CalendarServer/branches/users/glyph/warning-cleanups:11347-11357
</span><span class="cx">/CalendarServer/branches/users/glyph/whenNotProposed:11881-11897
</span><span class="cx">/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
</span><span class="cx">/CalendarServer/branches/users/sagen/applepush:8126-8184
</span><span class="cx">/CalendarServer/branches/users/sagen/inboxitems:7380-7381
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources:5032-5051
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who:12819-12860
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who-2:12861-12898
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who-3:12899-12913
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who-4:12914-13157
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who-5:13158-13163
</span><span class="cx">/CalendarServer/branches/users/sagen/newcua:13309-13327
</span><span class="cx">/CalendarServer/branches/users/sagen/newcua-1:13328-13330
</span><span class="cx">/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
</span><span class="cx">/CalendarServer/branches/users/sagen/recordtypes:13648-13656
</span><span class="cx">/CalendarServer/branches/users/sagen/recordtypes-2:13657
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
</span><span class="cx">/CalendarServer/branches/users/sagen/resources-2:5084-5093
</span><span class="cx">/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
</span><span class="cx">/CalendarServer/branches/users/wsanchez/transations:5515-5593
</span><span class="cx">/CalendarServer/trunk:14095,14117-14119
</span><span class="cx">   + /CalDAVTester/trunk:11193-11198
</span><span class="cx">/CalendarServer/branches/config-separation:4379-4443
</span><span class="cx">/CalendarServer/branches/egg-info-351:4589-4625
</span><span class="cx">/CalendarServer/branches/generic-sqlstore:6167-6191
</span><span class="cx">/CalendarServer/branches/new-store:5594-5934
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile:5911-5935
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-5.1-dev:11846
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-5.2-dev:11972,12357-12358,12794,12814
</span><span class="cx">/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
</span><span class="cx">/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
</span><span class="cx">/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
</span><span class="cx">/CalendarServer/branches/users/cdaboo/cross-pod-sharing:12038-12191
</span><span class="cx">/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
</span><span class="cx">/CalendarServer/branches/users/cdaboo/fix-no-ischedule:11607-11871
</span><span class="cx">/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
</span><span class="cx">/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
</span><span class="cx">/CalendarServer/branches/users/cdaboo/json:11622-11912
</span><span class="cx">/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
</span><span class="cx">/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
</span><span class="cx">/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
</span><span class="cx">/CalendarServer/branches/users/cdaboo/performance-tweaks:11824-11836
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pods:7297-7377
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycard:7227-7237
</span><span class="cx">/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
</span><span class="cx">/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
</span><span class="cx">/CalendarServer/branches/users/cdaboo/reverse-proxy-pods:11875-11900
</span><span class="cx">/CalendarServer/branches/users/cdaboo/scheduling-queue-refresh:11783-12557
</span><span class="cx">/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
</span><span class="cx">/CalendarServer/branches/users/cdaboo/sharing-in-the-store:11935-12016
</span><span class="cx">/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
</span><span class="cx">/CalendarServer/branches/users/cdaboo/timezones:7443-7699
</span><span class="cx">/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
</span><span class="cx">/CalendarServer/branches/users/gaya/cleanrevisions:12152-12334
</span><span class="cx">/CalendarServer/branches/users/gaya/groupsharee2:13669-13773
</span><span class="cx">/CalendarServer/branches/users/gaya/sharedgroupfixes:12120-12142
</span><span class="cx">/CalendarServer/branches/users/gaya/sharedgroups-3:11088-11204
</span><span class="cx">/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
</span><span class="cx">/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
</span><span class="cx">/CalendarServer/branches/users/glyph/conn-limit:6574-6577
</span><span class="cx">/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
</span><span class="cx">/CalendarServer/branches/users/glyph/dalify:6932-7023
</span><span class="cx">/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
</span><span class="cx">/CalendarServer/branches/users/glyph/deploybuild:7563-7572
</span><span class="cx">/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
</span><span class="cx">/CalendarServer/branches/users/glyph/disable-quota:7718-7727
</span><span class="cx">/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
</span><span class="cx">/CalendarServer/branches/users/glyph/enforce-max-requests:11640-11643
</span><span class="cx">/CalendarServer/branches/users/glyph/hang-fix:11465-11491
</span><span class="cx">/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
</span><span class="cx">/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
</span><span class="cx">/CalendarServer/branches/users/glyph/launchd-wrapper-bis:11413-11436
</span><span class="cx">/CalendarServer/branches/users/glyph/linux-tests:6893-6900
</span><span class="cx">/CalendarServer/branches/users/glyph/log-cleanups:11691-11731
</span><span class="cx">/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
</span><span class="cx">/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
</span><span class="cx">/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
</span><span class="cx">/CalendarServer/branches/users/glyph/new-export:7444-7485
</span><span class="cx">/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle:7106-7155
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
</span><span class="cx">/CalendarServer/branches/users/glyph/other-html:8062-8091
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
</span><span class="cx">/CalendarServer/branches/users/glyph/q:9560-9688
</span><span class="cx">/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
</span><span class="cx">/CalendarServer/branches/users/glyph/quota:7604-7637
</span><span class="cx">/CalendarServer/branches/users/glyph/sendfdport:5388-5424
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
</span><span class="cx">/CalendarServer/branches/users/glyph/sharedpool:6490-6550
</span><span class="cx">/CalendarServer/branches/users/glyph/sharing-api:9192-9205
</span><span class="cx">/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
</span><span class="cx">/CalendarServer/branches/users/glyph/sql-store:5929-6073
</span><span class="cx">/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
</span><span class="cx">/CalendarServer/branches/users/glyph/subtransactions:7248-7258
</span><span class="cx">/CalendarServer/branches/users/glyph/table-alias:8651-8664
</span><span class="cx">/CalendarServer/branches/users/glyph/uidexport:7673-7676
</span><span class="cx">/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
</span><span class="cx">/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
</span><span class="cx">/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
</span><span class="cx">/CalendarServer/branches/users/glyph/warning-cleanups:11347-11357
</span><span class="cx">/CalendarServer/branches/users/glyph/whenNotProposed:11881-11897
</span><span class="cx">/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
</span><span class="cx">/CalendarServer/branches/users/sagen/applepush:8126-8184
</span><span class="cx">/CalendarServer/branches/users/sagen/inboxitems:7380-7381
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources:5032-5051
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who:12819-12860
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who-2:12861-12898
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who-3:12899-12913
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who-4:12914-13157
</span><span class="cx">/CalendarServer/branches/users/sagen/move2who-5:13158-13163
</span><span class="cx">/CalendarServer/branches/users/sagen/newcua:13309-13327
</span><span class="cx">/CalendarServer/branches/users/sagen/newcua-1:13328-13330
</span><span class="cx">/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
</span><span class="cx">/CalendarServer/branches/users/sagen/recordtypes:13648-13656
</span><span class="cx">/CalendarServer/branches/users/sagen/recordtypes-2:13657
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
</span><span class="cx">/CalendarServer/branches/users/sagen/resources-2:5084-5093
</span><span class="cx">/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
</span><span class="cx">/CalendarServer/branches/users/wsanchez/transations:5515-5593
</span><span class="cx">/CalendarServer/trunk:14095,14117-14119,14164,14172
</span><a id="CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavstdconfigpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/stdconfig.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/stdconfig.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/stdconfig.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -839,6 +839,17 @@
</span><span class="cx">     &quot;MaxPrincipalSearchReportResults&quot;: 500,
</span><span class="cx"> 
</span><span class="cx">     #
</span><ins>+    # Client fixes per user-agent match
+    #
+    &quot;ClientFixes&quot; : {
+        &quot;ForceAttendeeTRANSP&quot; : [
+            &quot;iOS/8\\.0(\\..*)?&quot;,
+            &quot;iOS/8\\.1(\\..*)?&quot;,
+            &quot;iOS/8\\.2(\\..*)?&quot;,
+        ],
+    },
+
+    #
</ins><span class="cx">     # Localization
</span><span class="cx">     #
</span><span class="cx">     &quot;Localization&quot; : {
</span><span class="lines">@@ -1458,6 +1469,19 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+def _updateClientFixes(configDict, reloading=False):
+    #
+    # Compile ClientFixes expressions for speed
+    #
+    try:
+        configDict.ClientFixesCompiled = {}
+        for key, expressions in configDict.ClientFixes.items():
+            configDict.ClientFixesCompiled[key] = [re.compile(&quot;^{}$&quot;.format(x)) for x in expressions]
+    except re.error, e:
+        raise ConfigurationError(&quot;Invalid regular expression in ClientFixes: %s&quot; % (e,))
+
+
+
</ins><span class="cx"> def _updateLogLevels(configDict, reloading=False):
</span><span class="cx">     log.publisher.levels.clearLogLevels()
</span><span class="cx"> 
</span><span class="lines">@@ -1648,6 +1672,7 @@
</span><span class="cx">     _postUpdateAugmentService,
</span><span class="cx">     _updateACLs,
</span><span class="cx">     _updateRejectClients,
</span><ins>+    _updateClientFixes,
</ins><span class="cx">     _updateLogLevels,
</span><span class="cx">     _updateNotifications,
</span><span class="cx">     _updateICalendar,
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavstorebridgepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/storebridge.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/storebridge.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/storebridge.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -49,7 +49,7 @@
</span><span class="cx"> from twistedcaldav.sharing import (
</span><span class="cx">     invitationBindStatusToXMLMap, invitationBindModeToXMLMap
</span><span class="cx"> )
</span><del>-from twistedcaldav.util import bestAcceptType
</del><ins>+from twistedcaldav.util import bestAcceptType, matchClientFixes
</ins><span class="cx"> from twistedcaldav.vcard import Component as VCard, InvalidVCardDataError
</span><span class="cx"> from txdav.base.propertystore.base import PropertyName
</span><span class="cx"> from txdav.caldav.icalendarstore import (
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx">     InvalidPerUserDataMerge,
</span><span class="cx">     AttendeeAllowedError, ResourceDeletedError, InvalidAttachmentOperation,
</span><span class="cx">     ShareeAllowedError, DuplicatePrivateCommentsError, InvalidSplit,
</span><del>-    AttachmentSizeTooLarge, UnknownTimezone)
</del><ins>+    AttachmentSizeTooLarge, UnknownTimezone, SetComponentOptions)
</ins><span class="cx"> from txdav.carddav.iaddressbookstore import (
</span><span class="cx">     KindChangeNotAllowedError, GroupWithUnsharedAddressNotAllowedError
</span><span class="cx"> )
</span><span class="lines">@@ -2892,8 +2892,18 @@
</span><span class="cx">                     &quot;Can't parse calendar data: %s&quot; % (str(e),)
</span><span class="cx">                 ))
</span><span class="cx"> 
</span><ins>+            # Look for client fixes
+            ua = request.headers.getHeader(&quot;User-Agent&quot;)
+            client_fix_transp = matchClientFixes(config, ua)
+
+            # Setup options
+            options = {
+                SetComponentOptions.smartMerge: schedule_tag_match,
+                SetComponentOptions.clientFixTRANSP: client_fix_transp,
+            }
+
</ins><span class="cx">             try:
</span><del>-                response = (yield self.storeComponent(component, smart_merge=schedule_tag_match))
</del><ins>+                response = (yield self.storeComponent(component, options=options))
</ins><span class="cx">             except ResourceDeletedError:
</span><span class="cx">                 # This is OK - it just means the server deleted the resource during the PUT. We make it look
</span><span class="cx">                 # like the PUT succeeded.
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavtesttest_collectioncontentspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/test/test_collectioncontents.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/test/test_collectioncontents.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/test/test_collectioncontents.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx">                    _getFakeMemcacheProtocol)
</span><span class="cx"> 
</span><span class="cx">         # Need to not do implicit behavior during these tests
</span><del>-        def _fakeDoImplicitScheduling(self, component, inserting, internal_state):
</del><ins>+        def _fakeDoImplicitScheduling(self, component, inserting, internal_state, options):
</ins><span class="cx">             return False, None, False, None
</span><span class="cx"> 
</span><span class="cx">         self.patch(CalendarObject, &quot;doImplicitScheduling&quot;,
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavtesttest_utilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/test/test_util.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/test/test_util.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/test/test_util.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -16,8 +16,10 @@
</span><span class="cx"> 
</span><span class="cx"> from txweb2.http_headers import Headers
</span><span class="cx"> 
</span><ins>+from twistedcaldav.config import ConfigDict
+from twistedcaldav.stdconfig import _updateClientFixes
+from twistedcaldav.util import bestAcceptType, userAgentProductTokens, matchClientFixes
</ins><span class="cx"> import twistedcaldav.test.util
</span><del>-from twistedcaldav.util import bestAcceptType
</del><span class="cx"> 
</span><span class="cx"> class AcceptType(twistedcaldav.test.util.TestCase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -142,3 +144,78 @@
</span><span class="cx">                 hdrs.addRawHeader(*hdr)
</span><span class="cx">             check = bestAcceptType(hdrs.getHeader(&quot;accept&quot;), allowedTypes)
</span><span class="cx">             self.assertEqual(check, result, msg=&quot;Failed %s&quot; % (title,))
</span><ins>+
+
+    def test_userAgentProductTokens(self):
+        &quot;&quot;&quot;
+        Test that L{userAgentProductTokens} correctly parses a User-Agent header.
+        &quot;&quot;&quot;
+        for hdr, result in (
+            # Valid syntax
+            (&quot;Client/1.0&quot;, [&quot;Client/1.0&quot;, ]),
+            (&quot;Client/1.0 FooBar/2&quot;, [&quot;Client/1.0&quot;, &quot;FooBar/2&quot;, ]),
+            (&quot;Client/1.0 (commentary here)&quot;, [&quot;Client/1.0&quot;, ]),
+            (&quot;Client/1.0 (FooBar/2)&quot;, [&quot;Client/1.0&quot;, ]),
+            (&quot;Client/1.0 (commentary here) FooBar/2&quot;, [&quot;Client/1.0&quot;, &quot;FooBar/2&quot;, ]),
+            (&quot;Client/1.0 (commentary here) FooBar/2 (more commentary here) &quot;, [&quot;Client/1.0&quot;, &quot;FooBar/2&quot;, ]),
+
+            # Invalid syntax
+            (&quot;Client/1.0 (commentary here FooBar/2&quot;, [&quot;Client/1.0&quot;, ]),
+            (&quot;Client/1.0 commentary here) FooBar/2&quot;, [&quot;Client/1.0&quot;, &quot;commentary&quot;, &quot;here)&quot;, &quot;FooBar/2&quot;, ]),
+        ):
+            self.assertEqual(userAgentProductTokens(hdr), result, msg=&quot;Mismatch: {}&quot;.format(hdr))
+
+
+    def test_matchClientFixes(self):
+        &quot;&quot;&quot;
+        Test that L{matchClientFixes} correctly identifies clients with matching fix tokens.
+        &quot;&quot;&quot;
+        c = ConfigDict()
+        c.ClientFixes = {
+            &quot;fix1&quot;: [
+                &quot;Client/1\\.0.*&quot;,
+                &quot;Client/1\\.1(\\..*)?&quot;,
+                &quot;Client/2&quot;,
+            ],
+            &quot;fix2&quot;: [
+                &quot;Other/1\\.0.*&quot;,
+            ],
+        }
+        _updateClientFixes(c)
+        _updateClientFixes(c)
+
+        # Valid matches
+        for ua in (
+            &quot;Client/1.0 FooBar/2&quot;,
+            &quot;Client/1.0.1 FooBar/2&quot;,
+            &quot;Client/1.0.1.1 FooBar/2&quot;,
+            &quot;Client/1.1 FooBar/2&quot;,
+            &quot;Client/1.1.1 FooBar/2&quot;,
+            &quot;Client/2 FooBar/2&quot;,
+        ):
+            self.assertEqual(
+                matchClientFixes(c, ua),
+                set((&quot;fix1&quot;,)),
+                msg=&quot;Did not match {}&quot;.format(ua),
+            )
+
+        # Valid non-matches
+        for ua in (
+            &quot;Client/1 FooBar/2&quot;,
+            &quot;Client/1.10 FooBar/2&quot;,
+            &quot;Client/2.0 FooBar/2&quot;,
+            &quot;Client/2.0.1 FooBar/2&quot;,
+            &quot;Client FooBar/2&quot;,
+            &quot;Client/3 FooBar/2&quot;,
+            &quot;Client/3.0 FooBar/2&quot;,
+            &quot;Client/10 FooBar/2&quot;,
+            &quot;Client/10.0 FooBar/2&quot;,
+            &quot;Client/10.0.1 FooBar/2&quot;,
+            &quot;Client/10.0.1 (Client/1.0) FooBar/2&quot;,
+            &quot;Client/10.0.1 (foo Client/1.0 bar) FooBar/2&quot;,
+        ):
+            self.assertEqual(
+                matchClientFixes(c, ua),
+                set(),
+                msg=&quot;Incorrectly matched {}&quot;.format(ua),
+            )
</ins></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtwistedcaldavutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/util.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/util.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/twistedcaldav/util.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -18,6 +18,7 @@
</span><span class="cx"> import re
</span><span class="cx"> import sys
</span><span class="cx"> import base64
</span><ins>+import itertools
</ins><span class="cx"> 
</span><span class="cx"> from subprocess import Popen, PIPE, STDOUT
</span><span class="cx"> from hashlib import md5, sha1
</span><span class="lines">@@ -541,3 +542,57 @@
</span><span class="cx">                 result_qval = qval
</span><span class="cx"> 
</span><span class="cx">     return result
</span><ins>+
+
+
+def userAgentProductTokens(user_agent):
+    &quot;&quot;&quot;
+    Parse an HTTP User-Agent header to extract the product tokens and ignore
+    any parenthesized comment strings in the header.
+
+    @param user_agent: text of User-Agent header value
+    @type user_agent: L{str}
+
+    @return: list of product tokens extracted from the header
+    @rtype: L{list}
+    &quot;&quot;&quot;
+
+    ua_hdr = user_agent.split()
+    ua_tokens = []
+    comment = False
+    for token in ua_hdr:
+        if comment:
+            if token.endswith(&quot;)&quot;):
+                comment = False
+        elif token.startswith(&quot;(&quot;):
+            if not token.endswith(&quot;)&quot;):
+                comment = True
+        else:
+            ua_tokens.append(token)
+
+    return ua_tokens
+
+
+
+def matchClientFixes(config, user_agent):
+    &quot;&quot;&quot;
+    Given a user-agent string, see if it matches any of the configured client fixes.
+
+    @param config: the L{config} to match against.
+    @type config: L{ConfigDict}
+    @param user_agent: the HTTP User-Agent header value to test.
+    @type user_agent: L{str}
+    &quot;&quot;&quot;
+
+    if len(config.ClientFixesCompiled) == 0 or not user_agent:
+        return set()
+
+    ua_tokens = userAgentProductTokens(user_agent)
+
+    client_fixes = set()
+    for fix, patterns in config.ClientFixesCompiled.items():
+        for pattern, token in itertools.product(patterns, ua_tokens):
+            if pattern.match(token) is not None:
+                client_fixes.add(fix)
+                break
+    return client_fixes
</ins></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoreschedulingicaldiffpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/icaldiff.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/icaldiff.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/icaldiff.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -27,10 +27,6 @@
</span><span class="cx"> from txdav.caldav.datastore.scheduling.utils import normalizeCUAddr
</span><span class="cx"> from txdav.caldav.datastore.scheduling.itip import iTipGenerator
</span><span class="cx"> 
</span><del>-&quot;&quot;&quot;
-Class that handles diff'ing two calendar objects.
-&quot;&quot;&quot;
-
</del><span class="cx"> __all__ = [
</span><span class="cx">     &quot;iCalDiff&quot;,
</span><span class="cx"> ]
</span><span class="lines">@@ -38,19 +34,32 @@
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="cx"> class iCalDiff(object):
</span><ins>+    &quot;&quot;&quot;
+    This object is used for doing comparisons between two calendar objects to
+    work out what the changes are, in order to determine whether a scheduling
+    operation might be needed. The behavior will varying based on whether the
+    change is being triggered by an Organizer or an Attendee.
+    &quot;&quot;&quot;
</ins><span class="cx"> 
</span><del>-    def __init__(self, oldcalendar, newcalendar, smart_merge):
</del><ins>+    def __init__(self, oldcalendar, newcalendar, smart_merge, forceTRANSP=False):
</ins><span class="cx">         &quot;&quot;&quot;
</span><ins>+        Note that this object will always duplicate the calendar objects when doing
+        comparisons so as not to change the calendar objects passed in.
</ins><span class="cx"> 
</span><del>-        @param oldcalendar:
-        @type oldcalendar:
-        @param newcalendar:
-        @type newcalendar:
</del><ins>+        @param oldcalendar: the existing calendar object to compare to
+        @type oldcalendar: L{Component}
+        @param newcalendar: the new calendar object
+        @type newcalendar: L{Component}
+        @param smart_merge: whether or not a &quot;smart&quot; CalDAV merge is done (If-Schedule-Tag-Match)
+        @type smart_merge: L{bool}
+        @param forceTRANSP: whether or not to apply a fix for clients failing to set TRANSP properly
+        @type forceTRANSP: L{bool}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         self.oldcalendar = oldcalendar
</span><span class="cx">         self.newcalendar = newcalendar
</span><span class="cx">         self.smart_merge = smart_merge
</span><ins>+        self.forceTRANSP = forceTRANSP
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def organizerDiff(self):
</span><span class="lines">@@ -501,6 +510,13 @@
</span><span class="cx"> 
</span><span class="cx">             replyNeeded = True
</span><span class="cx"> 
</span><ins>+            # Apply client fix only if the PARTSTAT was changed
+            if self.forceTRANSP:
+                if clientAttendee.parameterValue(&quot;PARTSTAT&quot;, &quot;NEEDS-ACTION&quot;) in (&quot;ACCEPTED&quot;, &quot;TENTATIVE&quot;,):
+                    clientComponent.replaceProperty(Property(&quot;TRANSP&quot;, &quot;OPAQUE&quot;))
+                else:
+                    clientComponent.replaceProperty(Property(&quot;TRANSP&quot;, &quot;TRANSPARENT&quot;))
+
</ins><span class="cx">         if serverAttendee.parameterValue(&quot;RSVP&quot;, &quot;FALSE&quot;) != clientAttendee.parameterValue(&quot;RSVP&quot;, &quot;FALSE&quot;):
</span><span class="cx">             if clientAttendee.parameterValue(&quot;RSVP&quot;, &quot;FALSE&quot;) == &quot;FALSE&quot;:
</span><span class="cx">                 try:
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoreschedulingimplicitpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/implicit.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/implicit.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/implicit.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> from txdav.caldav.datastore.scheduling.utils import getCalendarObjectForRecord
</span><span class="cx"> from txdav.caldav.datastore.scheduling.work import ScheduleReplyWork, \
</span><span class="cx">     ScheduleReplyCancelWork, ScheduleOrganizerWork, ScheduleOrganizerSendWork
</span><ins>+from txdav.caldav.icalendarstore import SetComponentOptions
</ins><span class="cx"> 
</span><span class="cx"> import collections
</span><span class="cx"> 
</span><span class="lines">@@ -65,10 +66,11 @@
</span><span class="cx">     STATUS_ORPHANED_CANCELLED_EVENT = 1
</span><span class="cx">     STATUS_ORPHANED_EVENT = 2
</span><span class="cx"> 
</span><del>-    def __init__(self, logItems=None):
</del><ins>+    def __init__(self, logItems=None, options=None):
</ins><span class="cx"> 
</span><span class="cx">         self.return_status = ImplicitScheduler.STATUS_OK
</span><span class="cx">         self.logItems = logItems
</span><ins>+        self.options = options
</ins><span class="cx">         self.allowed_to_schedule = True
</span><span class="cx">         self.suppress_refresh = False
</span><span class="cx"> 
</span><span class="lines">@@ -1683,7 +1685,11 @@
</span><span class="cx">                     (caldav_namespace, &quot;valid-attendee-change&quot;),
</span><span class="cx">                     &quot;Cannot use an event when not listed as an attendee in the organizer's copy&quot;,
</span><span class="cx">                 ))
</span><del>-        differ = iCalDiff(oldcalendar, self.calendar, self.do_smart_merge)
</del><ins>+
+        # Check for a required client fix
+        forceTRANSP = SetComponentOptions.value(self.options, SetComponentOptions.clientFixTRANSP)
+
+        differ = iCalDiff(oldcalendar, self.calendar, self.do_smart_merge, forceTRANSP=forceTRANSP)
</ins><span class="cx">         return differ.attendeeMerge(self.attendee)
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoreschedulingtesttest_icaldiffpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/test/test_icaldiff.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/test/test_icaldiff.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/scheduling/test/test_icaldiff.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -5248,6 +5248,391 @@
</span><span class="cx">             self.assertEqual(got_rescheduled, rescheduled, msg=&quot;%s expected rescheduled: '%s', got: '%s'&quot; % (description, rescheduled, got_rescheduled,))
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def test_attendee_merge_forceTRANSP(self):
+
+        data = (
+            (
+                &quot;#1.1 Simple component, no change&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;mailto:user2@example.com&quot;,
+                (True, False, (), &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2@example.com
+ORGANIZER;CN=User 01:mailto:user1@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;)
+            ),
+            (
+                &quot;#1.2 Simple component, change to ACCEPTED&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;mailto:user2@example.com&quot;,
+                (True, True, (None,), &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2@example.com
+ORGANIZER;CN=User 01:mailto:user1@example.com
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;)
+            ),
+            (
+                &quot;#1.3 Simple component, change to DECLINED&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=DECLINED:mailto:user2@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;mailto:user2@example.com&quot;,
+                (True, True, (None,), &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=DECLINED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2@example.com
+ORGANIZER;CN=User 01:mailto:user1@example.com
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;)
+            ),
+            (
+                &quot;#1.4 Simple component, change to TENTATIVE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=TENTATIVE:mailto:user2@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;mailto:user2@example.com&quot;,
+                (True, True, (None,), &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=TENTATIVE;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2@example.com
+ORGANIZER;CN=User 01:mailto:user1@example.com
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;)
+            ),
+            (
+                &quot;#1.5 Simple component, change to ACCEPTED with TRANSP&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2@example.com
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=TENTATIVE:mailto:user2@example.com
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;mailto:user2@example.com&quot;,
+                (True, True, (None,), &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=TENTATIVE;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2@example.com
+ORGANIZER;CN=User 01:mailto:user1@example.com
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;)
+            ),
+            (
+                &quot;#1.6 Simple component, remain as ACCEPTED with TRANSP&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2@example.com
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2@example.com
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;mailto:user2@example.com&quot;,
+                (True, False, (), &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2@example.com
+ORGANIZER;CN=User 01:mailto:user1@example.com
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;)
+            ),
+            (
+                &quot;#1.7 Simple component, remain as ACCEPTED change TRANSP&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2@example.com
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2@example.com
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;mailto:user2@example.com&quot;,
+                (True, False, (), &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2@example.com
+ORGANIZER;CN=User 01:mailto:user1@example.com
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;)
+            ),
+            (
+                &quot;#1.8 Simple component, ACCEPTED-&gt;DECLINED with TRANSP&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2@example.com
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=&quot;User 01&quot;:mailto:user1@example.com
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=DECLINED:mailto:user2@example.com
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;,
+                &quot;mailto:user2@example.com&quot;,
+                (True, True, (None,), &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1@example.com
+ATTENDEE;PARTSTAT=DECLINED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2@example.com
+ORGANIZER;CN=User 01:mailto:user1@example.com
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;)
+            ),
+        )
+
+        for description, calendar1, calendar2, attendee, result in data:
+            differ = iCalDiff(
+                Component.fromString(calendar1),
+                Component.fromString(calendar2),
+                False,
+                forceTRANSP=True,
+            )
+            diffResult = differ.attendeeMerge(attendee)
+            diffResult = (
+                diffResult[0],
+                diffResult[1],
+                tuple(sorted(diffResult[2])),
+                re.sub(
+                    &quot;X-CALENDARSERVER-DTSTAMP=[^Z]+&quot;,
+                    &quot;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXX&quot;,
+                    str(diffResult[3]).replace(&quot;\r&quot;, &quot;&quot;).replace(&quot;\n &quot;, &quot;&quot;)
+                ) if diffResult[3] else None,
+            )
+            self.assertEqual(diffResult, result, msg=&quot;%s: actual result: (%s)&quot; % (description, &quot;, &quot;.join([str(i).replace(&quot;\r&quot;, &quot;&quot;) for i in diffResult]),))
+
+
</ins><span class="cx">     def test_organizer_smart_merge(self):
</span><span class="cx"> 
</span><span class="cx">         data1 = (
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/sql.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/sql.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/sql.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -78,7 +78,7 @@
</span><span class="cx">     InvalidDefaultCalendar, \
</span><span class="cx">     InvalidAttachmentOperation, DuplicatePrivateCommentsError, \
</span><span class="cx">     TimeRangeUpperLimit, TimeRangeLowerLimit, InvalidSplit, \
</span><del>-    AttachmentSizeTooLarge, UnknownTimezone
</del><ins>+    AttachmentSizeTooLarge, UnknownTimezone, SetComponentOptions
</ins><span class="cx"> from txdav.caldav.icalendarstore import QuotaExceeded
</span><span class="cx"> from txdav.common.datastore.sql import CommonHome, CommonHomeChild, \
</span><span class="cx">     CommonObjectResource, ECALENDARTYPE
</span><span class="lines">@@ -2961,7 +2961,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def doImplicitScheduling(self, component, inserting, internal_state, split_details=None):
</del><ins>+    def doImplicitScheduling(self, component, inserting, internal_state, options, split_details=None):
</ins><span class="cx"> 
</span><span class="cx">         new_component = None
</span><span class="cx">         did_implicit_action = False
</span><span class="lines">@@ -2983,7 +2983,7 @@
</span><span class="cx">                 user_uuid = self._parentCollection.viewerHome().uid()
</span><span class="cx">                 component = PerUserDataFilter(user_uuid).filter(component.duplicate())
</span><span class="cx"> 
</span><del>-            scheduler = ImplicitScheduler(logItems=self._txn.logItems)
</del><ins>+            scheduler = ImplicitScheduler(logItems=self._txn.logItems, options=options)
</ins><span class="cx"> 
</span><span class="cx">             # PUT
</span><span class="cx">             do_implicit_action, is_scheduling_resource = (yield scheduler.testImplicitSchedulingPUT(
</span><span class="lines">@@ -3120,7 +3120,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def setComponent(self, component, inserting=False, smart_merge=False):
</del><ins>+    def setComponent(self, component, inserting=False, options=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Public api for storing a component. This will do full data validation checks on the specified component.
</span><span class="cx">         Scheduling will be done automatically.
</span><span class="lines">@@ -3133,7 +3133,7 @@
</span><span class="cx">             except InvalidICalendarDataError as e:
</span><span class="cx">                 raise InvalidComponentForStoreError(str(e))
</span><span class="cx">         try:
</span><del>-            result = yield self._setComponentInternal(component, inserting, ComponentUpdateState.NORMAL, smart_merge)
</del><ins>+            result = yield self._setComponentInternal(component, inserting, ComponentUpdateState.NORMAL, options)
</ins><span class="cx">         except Exception:
</span><span class="cx">             ex = Failure()
</span><span class="cx"> 
</span><span class="lines">@@ -3148,7 +3148,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def _setComponentInternal(self, component, inserting=False, internal_state=ComponentUpdateState.NORMAL, smart_merge=False, split_details=None):
</del><ins>+    def _setComponentInternal(self, component, inserting=False, internal_state=ComponentUpdateState.NORMAL, options=None, split_details=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Setting the component internally to the store itself. This will bypass a whole bunch of data consistency checks
</span><span class="cx">         on the assumption that those have been done prior to the component data being provided, provided the flag is set.
</span><span class="lines">@@ -3156,7 +3156,11 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         self._componentChanged = False
</span><del>-        self.schedule_tag_match = not self.calendar().isInbox() and internal_state == ComponentUpdateState.NORMAL and smart_merge
</del><ins>+        self.schedule_tag_match = (
+            not self.calendar().isInbox() and
+            internal_state == ComponentUpdateState.NORMAL and
+            SetComponentOptions.value(options, SetComponentOptions.smartMerge)
+        )
</ins><span class="cx">         schedule_state = None
</span><span class="cx"> 
</span><span class="cx">         if internal_state in (ComponentUpdateState.SPLIT_OWNER, ComponentUpdateState.SPLIT_ATTENDEE,):
</span><span class="lines">@@ -3175,7 +3179,7 @@
</span><span class="cx"> 
</span><span class="cx">             # Do scheduling only for owner split
</span><span class="cx">             if internal_state == ComponentUpdateState.SPLIT_OWNER:
</span><del>-                yield self.doImplicitScheduling(component, inserting, internal_state, split_details)
</del><ins>+                yield self.doImplicitScheduling(component, inserting, internal_state, options, split_details)
</ins><span class="cx"> 
</span><span class="cx">             self.isScheduleObject = True
</span><span class="cx">             self.processScheduleTags(component, inserting, internal_state)
</span><span class="lines">@@ -3211,7 +3215,7 @@
</span><span class="cx">                 yield self.decorateHostedStatus(component)
</span><span class="cx"> 
</span><span class="cx">             # Do scheduling
</span><del>-            implicit_result = (yield self.doImplicitScheduling(component, inserting, internal_state))
</del><ins>+            implicit_result = (yield self.doImplicitScheduling(component, inserting, internal_state, options))
</ins><span class="cx">             if isinstance(implicit_result, int):
</span><span class="cx">                 if implicit_result == ImplicitScheduler.STATUS_ORPHANED_CANCELLED_EVENT:
</span><span class="cx">                     raise ResourceDeletedError(&quot;Resource created but immediately deleted by the server.&quot;)
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavdatastoresql_externalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/sql_external.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/sql_external.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/datastore/sql_external.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -171,7 +171,7 @@
</span><span class="cx">         raise AssertionError(&quot;CalendarObjectExternal: not supported&quot;)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def _setComponentInternal(self, component, inserting=False, internal_state=ComponentUpdateState.NORMAL, smart_merge=False, split_details=None):
</del><ins>+    def _setComponentInternal(self, component, inserting=False, internal_state=ComponentUpdateState.NORMAL, options=None, split_details=None):
</ins><span class="cx">         raise AssertionError(&quot;CalendarObjectExternal: not supported&quot;)
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtxdavcaldavicalendarstorepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/icalendarstore.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/icalendarstore.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/caldav/icalendarstore.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -950,3 +950,30 @@
</span><span class="cx">     NORMAL.description = &quot;normal&quot;
</span><span class="cx">     NORMAL_NO_IMPLICIT.description = &quot;normal-no-implicit&quot;
</span><span class="cx">     INTERNAL.description = &quot;internal&quot;
</span><ins>+
+
+
+class SetComponentOptions(Names):
+    &quot;&quot;&quot;
+    Constants for keys used in the L{ICalendarObject.setComponent} method's
+    C{options} dict. The definitions below define the constant key name and
+    the type used for the dict entry's value.
+
+    @cvar smartMerge: Apply CalDAV smart merge to data (If-Schedule-Tag-Match)
+        Value: L{bool}
+
+    @cvar clientFixTRANSP: Apply fix for clients not setting TRANSP.
+        Value: L{bool}
+    &quot;&quot;&quot;
+
+    smartMerge = NamedConstant()
+    smartMerge.description = u&quot;Smart Merge: CalDAV If-Schedule-Tag-Match behavior&quot;
+    smartMerge.defaultValue = False
+
+    clientFixTRANSP = NamedConstant()
+    clientFixTRANSP.description = u&quot;Fix for clients not setting TRANSP&quot;
+    clientFixTRANSP.defaultValue = False
+
+    @staticmethod
+    def value(options, key):
+        return options.get(key, key.defaultValue) if options is not None else key.defaultValue
</ins></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtxdavcarddavdatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/carddav/datastore/sql.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/carddav/datastore/sql.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/carddav/datastore/sql.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -2041,7 +2041,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def remove(self):
</del><ins>+    def remove(self, options=None):
</ins><span class="cx"> 
</span><span class="cx">         if self.owned():
</span><span class="cx">             yield self.unshare() # storebridge should already have done this
</span><span class="lines">@@ -2412,7 +2412,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def setComponent(self, component, inserting=False):
</del><ins>+    def setComponent(self, component, inserting=False, options=None):
</ins><span class="cx"> 
</span><span class="cx">         if isinstance(component, str) or isinstance(component, unicode):
</span><span class="cx">             component = self._componentClass.fromString(component)
</span></span></pre></div>
<a id="CalendarServerbranchesreleaseCalendarServer60devtxdavcommondatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/common/datastore/sql.py (14173 => 14174)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/common/datastore/sql.py        2014-11-14 21:01:03 UTC (rev 14173)
+++ CalendarServer/branches/release/CalendarServer-6.0-dev/txdav/common/datastore/sql.py        2014-11-14 21:08:05 UTC (rev 14174)
</span><span class="lines">@@ -7217,7 +7217,7 @@
</span><span class="cx">         self._locked = True
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def setComponent(self, component, inserting=False):
</del><ins>+    def setComponent(self, component, inserting=False, options=None):
</ins><span class="cx">         raise NotImplementedError
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -7264,7 +7264,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def remove(self):
</del><ins>+    def remove(self, options=None):
</ins><span class="cx">         yield self._deleteQuery.on(self._txn, NoSuchObjectResourceError,
</span><span class="cx">                                    resourceID=self._resourceID)
</span><span class="cx">         yield self.properties()._removeResource()
</span></span></pre>
</div>
</div>

</body>
</html>