[CalendarServer-changes] [14382] CalendarServer/branches/users/cdaboo/pod2pod-migration

source_changes at macosforge.org source_changes at macosforge.org
Fri Feb 6 11:17:54 PST 2015


Revision: 14382
          http://trac.calendarserver.org//changeset/14382
Author:   cdaboo at apple.com
Date:     2015-02-06 11:17:54 -0800 (Fri, 06 Feb 2015)
Log Message:
-----------
Merge from trunk.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/pod2pod-migration/bin/_build.sh
    CalendarServer/branches/users/cdaboo/pod2pod-migration/bin/package
    CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/dashboard_service.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tap/caldav.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/agent.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/dkimtool.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/test/test_calverify.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/requirements-dev.txt
    CalendarServer/branches/users/cdaboo/pod2pod-migration/requirements-stable.txt
    CalendarServer/branches/users/cdaboo/pod2pod-migration/support/Apple.make
    CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/resource.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/sharing.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/stdconfig.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/storebridge.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/test/test_sharing.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/upgrade.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/dkim.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/resource.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/test/test_dkim.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/itip.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/processing.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/scheduler.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/test/test_itip.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/sql.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/test/test_sql.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/test/util.py
    CalendarServer/branches/users/cdaboo/pod2pod-migration/txweb2/dav/resource.py

Property Changed:
----------------
    CalendarServer/branches/users/cdaboo/pod2pod-migration/


Property changes on: CalendarServer/branches/users/cdaboo/pod2pod-migration
___________________________________________________________________
Modified: svn:mergeinfo
   - /CalDAVTester/trunk:11193-11198
/CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
/CalendarServer/branches/release/CalendarServer-5.1-dev:11846
/CalendarServer/branches/release/CalendarServer-5.2-dev:11972,12357-12358,12794,12814
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
/CalendarServer/branches/users/cdaboo/cross-pod-sharing:12038-12191
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/fix-no-ischedule:11607-11871
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
/CalendarServer/branches/users/cdaboo/json:11622-11912
/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/performance-tweaks:11824-11836
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/reverse-proxy-pods:11875-11900
/CalendarServer/branches/users/cdaboo/scheduling-queue-refresh:11783-12557
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/sharing-in-the-store:11935-12016
/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
/CalendarServer/branches/users/gaya/cleanrevisions:12152-12334
/CalendarServer/branches/users/gaya/groupsharee2:13669-13773
/CalendarServer/branches/users/gaya/sharedgroupfixes:12120-12142
/CalendarServer/branches/users/gaya/sharedgroups-3:11088-11204
/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/enforce-max-requests:11640-11643
/CalendarServer/branches/users/glyph/hang-fix:11465-11491
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
/CalendarServer/branches/users/glyph/launchd-wrapper-bis:11413-11436
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/log-cleanups:11691-11731
/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
/CalendarServer/branches/users/glyph/q:9560-9688
/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/sharing-api:9192-9205
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/table-alias:8651-8664
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
/CalendarServer/branches/users/glyph/warning-cleanups:11347-11357
/CalendarServer/branches/users/glyph/whenNotProposed:11881-11897
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/move2who:12819-12860
/CalendarServer/branches/users/sagen/move2who-2:12861-12898
/CalendarServer/branches/users/sagen/move2who-3:12899-12913
/CalendarServer/branches/users/sagen/move2who-4:12914-13157
/CalendarServer/branches/users/sagen/move2who-5:13158-13163
/CalendarServer/branches/users/sagen/newcua:13309-13327
/CalendarServer/branches/users/sagen/newcua-1:13328-13330
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/recordtypes:13648-13656
/CalendarServer/branches/users/sagen/recordtypes-2:13657
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
/CalendarServer/branches/users/wsanchez/transations:5515-5593
   + /CalDAVTester/trunk:11193-11198
/CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
/CalendarServer/branches/release/CalendarServer-5.1-dev:11846
/CalendarServer/branches/release/CalendarServer-5.2-dev:11972,12357-12358,12794,12814
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
/CalendarServer/branches/users/cdaboo/cross-pod-sharing:12038-12191
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/fix-no-ischedule:11607-11871
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
/CalendarServer/branches/users/cdaboo/json:11622-11912
/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/performance-tweaks:11824-11836
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/reverse-proxy-pods:11875-11900
/CalendarServer/branches/users/cdaboo/scheduling-queue-refresh:11783-12557
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/sharing-in-the-store:11935-12016
/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
/CalendarServer/branches/users/gaya/cleanrevisions:12152-12334
/CalendarServer/branches/users/gaya/groupsharee2:13669-13773
/CalendarServer/branches/users/gaya/sharedgroupfixes:12120-12142
/CalendarServer/branches/users/gaya/sharedgroups-3:11088-11204
/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/enforce-max-requests:11640-11643
/CalendarServer/branches/users/glyph/hang-fix:11465-11491
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
/CalendarServer/branches/users/glyph/launchd-wrapper-bis:11413-11436
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/log-cleanups:11691-11731
/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
/CalendarServer/branches/users/glyph/q:9560-9688
/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/sharing-api:9192-9205
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/table-alias:8651-8664
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
/CalendarServer/branches/users/glyph/warning-cleanups:11347-11357
/CalendarServer/branches/users/glyph/whenNotProposed:11881-11897
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/move2who:12819-12860
/CalendarServer/branches/users/sagen/move2who-2:12861-12898
/CalendarServer/branches/users/sagen/move2who-3:12899-12913
/CalendarServer/branches/users/sagen/move2who-4:12914-13157
/CalendarServer/branches/users/sagen/move2who-5:13158-13163
/CalendarServer/branches/users/sagen/newcua:13309-13327
/CalendarServer/branches/users/sagen/newcua-1:13328-13330
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/recordtypes:13648-13656
/CalendarServer/branches/users/sagen/recordtypes-2:13657
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
/CalendarServer/branches/users/wsanchez/transations:5515-5593
/CalendarServer/trunk:14338-14381

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/bin/_build.sh
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/bin/_build.sh	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/bin/_build.sh	2015-02-06 19:17:54 UTC (rev 14382)
@@ -516,7 +516,7 @@
     local p="${n}-${v}";
 
     c_dependency -m "a7f4e5e559a0e37b3ffc438c9456e425" \
-      "Cyrus SASL" "${p}" \
+      "CyrusSASL" "${p}" \
       "ftp://ftp.cyrusimap.org/cyrus-sasl/${p}.tar.gz" \
       --disable-macos-framework;
   fi;
@@ -640,9 +640,9 @@
   mkdir -p "${py_ve_tools}/junk";
 
   for pkg in             \
-      setuptools-5.4.1   \
-      pip-6.0.6          \
-      virtualenv-1.11.6  \
+      setuptools-12.0.5  \
+      pip-6.0.8          \
+      virtualenv-12.0.7  \
   ; do
       local    name="${pkg%-*}";
       local version="${pkg#*-}";
@@ -695,7 +695,6 @@
 pip_download_and_install () {
   "${python}" -m pip install                 \
     --pre --allow-all-external               \
-    --download-cache="${dev_home}/pip_cache" \
     --log-file="${dev_home}/pip.log"         \
     "$@";
 }

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/bin/package
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/bin/package	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/bin/package	2015-02-06 19:17:54 UTC (rev 14382)
@@ -65,7 +65,7 @@
 
 
 parse_options () {
-  OPTIND=1;
+  local OPTIND=1;
   while getopts "hFfn" option; do
     case "${option}" in
       '?') usage; ;;
@@ -93,37 +93,35 @@
 
   parse_options "$@";
 
-  # Build the product
+  #
+  # Build everything
+  #
 
   if "${clean}"; then
     develop_clean;
   fi;
 
-  develop;
-
   install -d "${destination}";
+  local destination="$(cd "${destination}" && pwd)";
 
-  install -d "${destination}/virtualenv";
-  cp -pR "${py_virtualenv}/" "${destination}/virtualenv";
+  init_build;
 
-  # Make the python virtualenv relocatable
-  "${bootstrap_python}" -m virtualenv --relocatable "${destination}/virtualenv";
+      dev_roots="${destination}/roots";
+  py_virtualenv="${destination}/virtualenv";
+      py_bindir="${py_virtualenv}/bin";
 
-  cp -pR "${dev_roots}"/*/ "${destination}/virtualenv/";
+  c_dependencies;
+  py_dependencies;
 
   install -d "${destination}/bin";
-  install -m 555 "${wd}/support/_run_from_ve" "${destination}/bin";
-  ln -fsv _run_from_ve "${destination}/bin/caldavd";
 
-  for script in $(
-    python -c 'import setup; print "\n".join("calendarserver_{}".format(n) for n in setup.script_entry_points.keys())';
-  ); do
-    ln -fsv _run_from_ve "${destination}/bin/${script}";
-  done;
+  (
+    cd "${destination}/bin" && \
+      find ../virtualenv/bin \
+        '(' -name 'caldavd' -o -name 'calendarserver_*' -o -name 'python' ')' \
+        -exec ln -fs '{}' . ';';
+  );
 
-  # More here...
-  # Looks like we need to install calendarserver.
-  # Maybe should rebuild virtualenv insted of copying it.
 }
 
 

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/dashboard_service.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/dashboard_service.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/dashboard_service.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -151,9 +151,9 @@
         """
 
         if self.factory.store:
-            queuer = self.factory.store.queuer
-            loads = queuer.workerPool.eachWorkerLoad()
-            level = queuer.workerPool.loadLevel()
+            pool = self.factory.store.pool
+            loads = pool.workerPool.eachWorkerLoad()
+            level = pool.workerPool.loadLevel()
         else:
             loads = []
             level = 0

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tap/caldav.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tap/caldav.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -193,7 +193,9 @@
         "PATH",
         "PYTHONPATH",
         "LD_LIBRARY_PATH",
+        "LD_PRELOAD",
         "DYLD_LIBRARY_PATH",
+        "DYLD_INSERT_LIBRARIES",
     ]
 
     optionalVars = [
@@ -1262,6 +1264,7 @@
             )
             self._initJobQueue(pool)
             store.queuer = store.queuer.transferProposalCallbacks(pool)
+            store.pool = pool
             pool.setServiceParent(result)
 
             # Optionally set up mail retrieval
@@ -1856,6 +1859,7 @@
 
             # The master should not perform queued work
             store.queuer = NonPerformingQueuer()
+            store.pool = pool
 
             controlSocket.addFactory(
                 _QUEUE_ROUTE, pool.workerListenerFactory()

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/agent.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/agent.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/agent.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -34,7 +34,7 @@
 from plistlib import readPlistFromString, writePlistToString
 import socket
 
-from twext.python.launchd import getLaunchDSocketFDs
+from twext.python.launchd import launchActivateSocket
 from twext.python.log import Logger
 from twext.who.checker import HTTPDigestCredentialChecker
 from twext.who.opendirectory import (
@@ -153,8 +153,8 @@
     """
     from twisted.internet import reactor
 
-    sockets = getLaunchDSocketFDs()
-    fd = sockets["AgentSocket"][0]
+    sockets = launchActivateSocket("AgentSocket")
+    fd = sockets[0]
 
     family = socket.AF_INET
     endpoint = AdoptedStreamServerEndpoint(reactor, fd, family)

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/dkimtool.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/dkimtool.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/dkimtool.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -15,6 +15,7 @@
 # limitations under the License.
 ##
 
+import os
 import sys
 from Crypto.PublicKey import RSA
 from StringIO import StringIO
@@ -24,9 +25,7 @@
 from twisted.python.usage import Options
 
 from twext.python.log import Logger, LogLevel, StandardIOObserver
-from txweb2.client.http import ClientRequest
 from txweb2.http_headers import Headers
-from txweb2.stream import MemoryStream
 
 from txdav.caldav.datastore.scheduling.ischedule.dkim import RSA256, DKIMRequest, \
     PublicKeyLookup, DKIMVerifier, DKIMVerificationError
@@ -114,19 +113,17 @@
 @inlineCallbacks
 def _doVerify(options):
     # Parse the HTTP file
-    verify = open(options["verify"]).read()
-    method, uri, headers, stream = _parseRequest(verify)
+    verify = open(os.path.expanduser(options["verify"])).read()
+    _method, _uri, headers, body = _parseRequest(verify)
 
-    request = ClientRequest(method, uri, headers, stream)
-
     # Check for local public key
     if options["pub-key"]:
-        PublicKeyLookup_File.pubkeyfile = options["pub-key"]
+        PublicKeyLookup_File.pubkeyfile = os.path.expanduser(options["pub-key"])
         lookup = (PublicKeyLookup_File,)
     else:
         lookup = None
 
-    dkim = DKIMVerifier(request, lookup)
+    dkim = DKIMVerifier(headers, body, lookup)
     if options["fake-time"]:
         dkim.time = 0
 
@@ -162,7 +159,7 @@
         name, value = hdr.split(':', 1)
         headers.addRawHeader(name, value.strip())
 
-    stream = MemoryStream("".join(body))
+    stream = "".join(body)
 
     return method, uri, headers, stream
 

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/test/test_calverify.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/test/test_calverify.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/calendarserver/tools/test/test_calverify.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -2507,8 +2507,8 @@
 UID:INVITE_VALID_ORGANIZER_ICS
 DTSTART:%(now)s
 DURATION:PT1H
-ATTENDEE:urn:x-uid:%(uuid1)s
-ATTENDEE:urn:x-uid:%(uuid2)s
+ATTENDEE;PARTSTAT=ACCPETED:urn:x-uid:%(uuid1)s
+ATTENDEE;RSVP=TRUE:urn:x-uid:%(uuid2)s
 ORGANIZER:urn:x-uid:%(uuid1)s
 RRULE:FREQ=DAILY
 SUMMARY:INVITE_VALID_ORGANIZER_ICS
@@ -2524,8 +2524,8 @@
 UID:INVITE_VALID_ORGANIZER_ICS
 DTSTART:%(now)s
 DURATION:PT1H
-ATTENDEE:urn:x-uid:%(uuid1)s
-ATTENDEE:urn:x-uid:%(uuid2)s
+ATTENDEE;PARTSTAT=ACCPETED:urn:x-uid:%(uuid1)s
+ATTENDEE;RSVP=TRUE:urn:x-uid:%(uuid2)s
 ORGANIZER:urn:x-uid:%(uuid1)s
 RRULE:FREQ=DAILY
 SUMMARY:INVITE_VALID_ORGANIZER_ICS
@@ -2541,8 +2541,8 @@
 UID:INVITE_VALID_ORGANIZER_ICS
 DTSTART:%(now_fwd11)s
 DURATION:PT1H
-ATTENDEE:urn:x-uid:%(uuid1)s
-ATTENDEE:urn:x-uid:%(uuid2)s
+ATTENDEE;PARTSTAT=ACCPETED:urn:x-uid:%(uuid1)s
+ATTENDEE;RSVP=TRUE:urn:x-uid:%(uuid2)s
 ORGANIZER:urn:x-uid:%(uuid1)s
 RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
 RRULE:FREQ=DAILY
@@ -2560,8 +2560,8 @@
 UID:INVITE_VALID_ORGANIZER_ICS
 DTSTART:%(now_fwd11)s
 DURATION:PT1H
-ATTENDEE:urn:x-uid:%(uuid1)s
-ATTENDEE:urn:x-uid:%(uuid2)s
+ATTENDEE;PARTSTAT=ACCPETED:urn:x-uid:%(uuid1)s
+ATTENDEE;RSVP=TRUE:urn:x-uid:%(uuid2)s
 ORGANIZER:urn:x-uid:%(uuid1)s
 RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
 RRULE:FREQ=DAILY
@@ -2579,8 +2579,8 @@
 UID:%(uid)s
 DTSTART:%(now)s
 DURATION:PT1H
-ATTENDEE:urn:x-uid:%(uuid1)s
-ATTENDEE:urn:x-uid:%(uuid2)s
+ATTENDEE;PARTSTAT=ACCPETED:urn:x-uid:%(uuid1)s
+ATTENDEE;RSVP=TRUE:urn:x-uid:%(uuid2)s
 ORGANIZER:urn:x-uid:%(uuid1)s
 RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
 RRULE:FREQ=DAILY;UNTIL=%(now_fwd11_1)s
@@ -2598,8 +2598,8 @@
 UID:%(uid)s
 DTSTART:%(now)s
 DURATION:PT1H
-ATTENDEE:urn:x-uid:%(uuid1)s
-ATTENDEE:urn:x-uid:%(uuid2)s
+ATTENDEE;PARTSTAT=ACCPETED:urn:x-uid:%(uuid1)s
+ATTENDEE;RSVP=TRUE:urn:x-uid:%(uuid2)s
 ORGANIZER:urn:x-uid:%(uuid1)s
 RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
 RRULE:FREQ=DAILY;UNTIL=%(now_fwd11_1)s
@@ -2617,8 +2617,8 @@
 UID:VALID_ORGANIZER_OVERRIDE_ICS
 DTSTART:%(now)s
 DURATION:PT1H
-ATTENDEE:urn:x-uid:%(uuid1)s
-ATTENDEE:urn:x-uid:%(uuid2)s
+ATTENDEE;PARTSTAT=ACCPETED:urn:x-uid:%(uuid1)s
+ATTENDEE;RSVP=TRUE:urn:x-uid:%(uuid2)s
 ORGANIZER:urn:x-uid:%(uuid1)s
 RRULE:FREQ=DAILY
 SUMMARY:INVITE_VALID_ORGANIZER_ICS
@@ -2628,8 +2628,8 @@
 RECURRENCE-ID:%(now_fwd11)s
 DTSTART:%(now_fwd11)s
 DURATION:PT2H
-ATTENDEE:urn:x-uid:%(uuid1)s
-ATTENDEE:urn:x-uid:%(uuid2)s
+ATTENDEE;PARTSTAT=ACCPETED:urn:x-uid:%(uuid1)s
+ATTENDEE;RSVP=TRUE:urn:x-uid:%(uuid2)s
 ORGANIZER:urn:x-uid:%(uuid1)s
 RRULE:FREQ=DAILY
 SUMMARY:INVITE_VALID_ORGANIZER_ICS

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/requirements-dev.txt
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/requirements-dev.txt	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/requirements-dev.txt	2015-02-06 19:17:54 UTC (rev 14382)
@@ -8,4 +8,4 @@
 q
 tl.eggdeps
 --editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVClientLibrary/trunk@13420#egg=CalDAVClientLibrary
---editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@14306#egg=CalDAVTester
+--editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@14377#egg=CalDAVTester

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/requirements-stable.txt
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/requirements-stable.txt	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/requirements-stable.txt	2015-02-06 19:17:54 UTC (rev 14382)
@@ -20,7 +20,7 @@
 
 --editable .  # calendarserver
 
-    zope.interface==4.1.1
+    zope.interface==4.1.2
 
     Twisted==14.0.2
         #zope.interface
@@ -30,19 +30,19 @@
         #   added to calendarserver.
         #pyOpenSSL
         service_identity==14.0.0
-            characteristic==14.0.0
+            characteristic==14.3.0
             pyasn1==0.1.7
             pyasn1-modules==0.0.5
             #pyOpenSSL
         pycrypto==2.6.1
 
-    --editable svn+http://svn.calendarserver.org/repository/calendarserver/twext/trunk@14327#egg=twextpy
+    --editable svn+http://svn.calendarserver.org/repository/calendarserver/twext/trunk@14351#egg=twextpy
         cffi==0.8.6
             pycparser==2.10
         #twisted
 
         # [LDAP] extra
-            python-ldap==2.4.18
+            python-ldap==2.4.19
                 #setuptools
 
         # [DAL] extra
@@ -55,14 +55,14 @@
             PyGreSQL==4.1.1
 
         # [Oracle] extra
-            #cx_Oracle  # Not in PyPI
+            #cx_Oracle==5.1.3  # Not in PyPI
 
     pyOpenSSL==0.14
-        cryptography==0.7.1
+        cryptography==0.7.2
             #pyasn1
             #cffi
             enum34==1.0.4
-            setuptools==11.3.1
+            setuptools==12.0.5
             #six
         six==1.9.0
 

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/support/Apple.make
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/support/Apple.make	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/support/Apple.make	2015-02-06 19:17:54 UTC (rev 14382)
@@ -89,7 +89,7 @@
 	@# Use --system-site-packages so that we use the packages provided by the
 	@# OS, such as PyObjC.
 	@# Use --always-copy because we want copies of, not links to, the system
-	@# python, as Server.app is an indenpendant product train.
+	@# python, as Server.app is an independent product train.
 	@#
 	@echo "Creating virtual environment...";
 	$(_v) $(RMDIR) "$(DSTROOT)$(CS_VIRTUALENV)";
@@ -138,19 +138,6 @@
 	@echo "Putting comments into empty files...";
 	$(_v) find "$(DSTROOT)$(CS_VIRTUALENV)" -type f -size 0 -name "*.py" -exec sh -c 'printf "# empty\n" > {}' ";";
 	$(_v) find "$(DSTROOT)$(CS_VIRTUALENV)" -type f -size 0 -name "*.h" -exec sh -c 'printf "/* empty */\n" > {}' ";";
-	@# This is obsoleted by using --always-copy when we create the virtualenv:
-	@# @echo "Replacing symbolic links...";
-	@# $(_v) find "$(DSTROOT)$(CS_VIRTUALENV)" -type l |                       \
-	@#           while read link; do                                           \
-	@#               target="$$(readlink "$${link}")";                         \
-	@#               if [ "$$(echo $${target} | cut -f 1 -d /)" == "" ]; then  \
-	@#                   rm -fv "$${link}";                                    \
-	@#                   cp -aLfv "$${target}" "$${link}" || {                 \
-	@#                       rm -rfv "$${link}";                               \
-	@#                       ln -sfv "$${target}" "$${link}";                  \
-	@#                   }                                                     \
-	@#               fi;                                                       \
-	@#           done;
 
 install:: install-config
 install-config::

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/resource.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/resource.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -776,7 +776,7 @@
             else:
                 home = self._newStoreObject.ownerHome()
             principal = (yield self.principalForUID(home.uid()))
-            returnValue(element.HRef(principal.principalURL()))
+            returnValue(element.HRef(principal.principalURL()) if principal else None)
         else:
             parent = (yield self.locateParent(request, request.urlForResource(self)))
         if parent and isinstance(parent, CalDAVResource):
@@ -1162,7 +1162,8 @@
         sharedParent = None
         if self.isShareeResource():
             # A sharee collection's quota root is the resource owner's root
-            sharedParent = (yield request.locateResource(parentForURL(self._share_url)))
+            if self._share_url:
+                sharedParent = (yield request.locateResource(parentForURL(self._share_url)))
         else:
             parent = (yield self.locateParent(request, request.urlForResource(self)))
             if isCalendarCollectionResource(parent) or isAddressBookCollectionResource(parent):

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/sharing.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/sharing.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -424,8 +424,7 @@
         if principal:
             if request:
                 ownerPrincipal = (yield self.ownerPrincipal(request))
-                owner = ownerPrincipal.principalURL()
-                if owner == principal.principalURL():
+                if ownerPrincipal is None or ownerPrincipal.principalURL() == principal.principalURL():
                     returnValue(None)
             returnValue(principal.principalURL())
 

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/stdconfig.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/stdconfig.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -15,30 +15,27 @@
 # limitations under the License.
 ##
 
+import copy
 import os
-import copy
+from plistlib import PlistParser  # @UnresolvedImport
 import re
 from socket import getfqdn, gethostbyname
 
+from calendarserver.push.util import getAPNTopicFromCertificate
+from twext.python.log import Logger, InvalidLogLevelError, LogLevel
+from twisted.python.filepath import FilePath
 from twisted.python.runtime import platform
-
-from plistlib import PlistParser  # @UnresolvedImport
-from twext.python.log import Logger, InvalidLogLevelError, LogLevel
-from txweb2.dav.resource import TwistedACLInheritable
-
-from txdav.xml import element as davxml
-
 from twistedcaldav import caldavxml, customxml, carddavxml, mkcolxml
+from twistedcaldav import ical
 from twistedcaldav.config import ConfigProvider, ConfigurationError, ConfigDict
 from twistedcaldav.config import config, mergeData, fullServerPath
-from twistedcaldav.util import getPasswordFromKeychain
+from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
 from twistedcaldav.util import KeychainAccessError, KeychainPasswordNotFound
 from twistedcaldav.util import computeProcessCount
-from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
+from twistedcaldav.util import getPasswordFromKeychain
+from txdav.xml import element as davxml
+from txweb2.dav.resource import TwistedACLInheritable
 
-from calendarserver.push.util import getAPNTopicFromCertificate
-from twistedcaldav import ical
-
 log = Logger()
 
 
@@ -1363,8 +1360,18 @@
             if param not in DEFAULT_RESOURCE_PARAMS[configDict.ResourceService.type]:
                 del configDict.ResourceService.params[param]
 
+    # Upgrading resources.xml must be done prior to using the store/directory
+    if configDict.ResourceService.Enabled and configDict.ResourceService.type == "xml":
+        resourcesFileName = configDict.ResourceService.params.xmlFile
+        if resourcesFileName[0] not in ("/", "."):
+            resourcesFileName = os.path.join(configDict.DataRoot, resourcesFileName)
+        resourcesFilePath = FilePath(resourcesFileName)
+        if resourcesFilePath.exists():
+            from twistedcaldav.upgrade import upgradeResourcesXML
+            upgradeResourcesXML(resourcesFilePath)
 
 
+
 def _preUpdateDirectoryAddressBookBackingDirectoryService(configDict, items, reloading=False):
     #
     # Special handling for directory address book configs
@@ -1402,8 +1409,18 @@
                 log.warn("Parameter %s is not supported by service %s" % (param, configDict.AugmentService.type))
                 del configDict.AugmentService.params[param]
 
+    # Upgrading augments.xml must be done prior to using the store/directory
+    if configDict.AugmentService.type == "twistedcaldav.directory.augment.AugmentXMLDB":
+        for fileName in configDict.AugmentService.params.xmlFiles:
+            if fileName[0] not in ("/", "."):
+                fileName = os.path.join(configDict.DataRoot, fileName)
+            filePath = FilePath(fileName)
+            if filePath.exists():
+                from twistedcaldav.upgrade import upgradeAugmentsXML
+                upgradeAugmentsXML(filePath)
 
 
+
 def _updateACLs(configDict, reloading=False):
     #
     # Base resource ACLs
@@ -1714,6 +1731,7 @@
     _updateCompliance,
 )
 
+
 def _cleanup(configDict, defaultDict):
     cleanDict = copy.deepcopy(configDict)
 

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/storebridge.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/storebridge.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -301,7 +301,7 @@
 
     def owner_url(self):
         if self.isShareeResource():
-            return joinURL(self._share_url, "/")
+            return joinURL(self._share_url, "/") if self._share_url else ""
         else:
             return self.url()
 
@@ -2982,6 +2982,16 @@
         if not self.exists():
             raise HTTPError(NOT_FOUND)
 
+        # Do schedule tag check
+        try:
+            self.validIfScheduleMatch(request)
+        except HTTPError as e:
+            if e.response.code == responsecode.PRECONDITION_FAILED:
+                response = yield self._processPrefer(request, e.response)
+                raise HTTPError(response)
+            else:
+                raise
+
         # Split point is in the rid query parameter
         rid = request.args.get("rid")
         if rid is None:
@@ -3007,11 +3017,11 @@
 
         try:
             otherStoreObject = yield self._newStoreObject.splitAt(rid, pastUID)
-        except InvalidSplit:
+        except InvalidSplit as e:
             raise HTTPError(ErrorResponse(
                 FORBIDDEN,
-                (calendarserver_namespace, "invalid-split",),
-                "The rid parameter in the request-URI contains an invalid value",
+                (calendarserver_namespace, "valid-split",),
+                str(e),
             ))
 
         other = yield request.locateChildResource(self._parentResource, otherStoreObject.name())
@@ -3029,6 +3039,8 @@
                 raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, "Cannot generate requested data type"))
             etag1 = yield self.etag()
             etag2 = yield other.etag()
+            scheduletag1 = self.scheduleTag
+            scheduletag2 = otherStoreObject.scheduleTag
             cal1 = yield self.component()
             cal2 = yield other.component()
 
@@ -3038,6 +3050,7 @@
                     davxml.PropertyStatus(
                         davxml.PropertyContainer(
                             davxml.GETETag.fromString(etag1.generate()),
+                            caldavxml.ScheduleTag.fromString(scheduletag1),
                             caldavxml.CalendarData.fromComponent(cal1, accepted_type),
                         ),
                         davxml.Status.fromResponseCode(OK),
@@ -3048,6 +3061,7 @@
                     davxml.PropertyStatus(
                         davxml.PropertyContainer(
                             davxml.GETETag.fromString(etag2.generate()),
+                            caldavxml.ScheduleTag.fromString(scheduletag2),
                             caldavxml.CalendarData.fromComponent(cal2, accepted_type),
                         ),
                         davxml.Status.fromResponseCode(OK),
@@ -3920,15 +3934,21 @@
 
         if jsondata["notification-type"] == "invite-notification":
             ownerPrincipal = yield self.principalForUID(jsondata["owner"])
-            ownerCN = ownerPrincipal.displayName()
-            ownerHomeURL = ownerPrincipal.calendarHomeURLs()[0] if jsondata["shared-type"] == "calendar" else ownerPrincipal.addressBookHomeURLs()[0]
-
-            # FIXME:  use urn:uuid always?
-            if jsondata["shared-type"] == "calendar":
-                owner = ownerPrincipal.principalURL()
+            if ownerPrincipal is None:
+                ownerCN = ""
+                ownerCollectionURL = ""
+                owner = "urn:x-uid:" + jsondata["owner"]
             else:
-                owner = "urn:x-uid:" + ownerPrincipal.principalUID()
+                ownerCN = ownerPrincipal.displayName()
+                ownerHomeURL = ownerPrincipal.calendarHomeURLs()[0] if jsondata["shared-type"] == "calendar" else ownerPrincipal.addressBookHomeURLs()[0]
+                ownerCollectionURL = urljoin(ownerHomeURL, jsondata["ownerName"])
 
+                # FIXME:  use urn:uuid always?
+                if jsondata["shared-type"] == "calendar":
+                    owner = ownerPrincipal.principalURL()
+                else:
+                    owner = "urn:x-uid:" + ownerPrincipal.principalUID()
+
             shareePrincipal = yield self.principalForUID(jsondata["sharee"])
 
             if "supported-components" in jsondata:
@@ -3952,7 +3972,7 @@
                     invitationBindStatusToXMLMap[jsondata["status"]](),
                     customxml.InviteAccess(invitationBindModeToXMLMap[jsondata["access"]]()),
                     customxml.HostURL(
-                        element.HRef.fromString(urljoin(ownerHomeURL, jsondata["ownerName"])),
+                        element.HRef.fromString(ownerCollectionURL),
                     ),
                     customxml.Organizer(
                         element.HRef.fromString(owner),

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/test/test_sharing.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/test/test_sharing.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -102,6 +102,66 @@
 
 
     @inlineCallbacks
+    def _doPROPFINDHome(self, resultcode=responsecode.MULTI_STATUS):
+        body = """<?xml version="1.0" encoding="UTF-8"?>
+<A:propfind xmlns:A="DAV:">
+  <A:prop>
+    <A:add-member/>
+    <C:allowed-sharing-modes xmlns:C="http://calendarserver.org/ns/"/>
+    <D:autoprovisioned xmlns:D="http://apple.com/ns/ical/"/>
+    <E:bulk-requests xmlns:E="http://me.com/_namespace/"/>
+    <D:calendar-color xmlns:D="http://apple.com/ns/ical/"/>
+    <B:calendar-description xmlns:B="urn:ietf:params:xml:ns:caldav"/>
+    <B:calendar-free-busy-set xmlns:B="urn:ietf:params:xml:ns:caldav"/>
+    <D:calendar-order xmlns:D="http://apple.com/ns/ical/"/>
+    <B:calendar-timezone xmlns:B="urn:ietf:params:xml:ns:caldav"/>
+    <A:current-user-privilege-set/>
+    <B:default-alarm-vevent-date xmlns:B="urn:ietf:params:xml:ns:caldav"/>
+    <B:default-alarm-vevent-datetime xmlns:B="urn:ietf:params:xml:ns:caldav"/>
+    <A:displayname/>
+    <C:getctag xmlns:C="http://calendarserver.org/ns/"/>
+    <C:invite xmlns:C="http://calendarserver.org/ns/"/>
+    <D:language-code xmlns:D="http://apple.com/ns/ical/"/>
+    <D:location-code xmlns:D="http://apple.com/ns/ical/"/>
+    <A:owner/>
+    <C:pre-publish-url xmlns:C="http://calendarserver.org/ns/"/>
+    <C:publish-url xmlns:C="http://calendarserver.org/ns/"/>
+    <C:push-transports xmlns:C="http://calendarserver.org/ns/"/>
+    <C:pushkey xmlns:C="http://calendarserver.org/ns/"/>
+    <A:quota-available-bytes/>
+    <A:quota-used-bytes/>
+    <D:refreshrate xmlns:D="http://apple.com/ns/ical/"/>
+    <A:resource-id/>
+    <A:resourcetype/>
+    <B:schedule-calendar-transp xmlns:B="urn:ietf:params:xml:ns:caldav"/>
+    <B:schedule-default-calendar-URL xmlns:B="urn:ietf:params:xml:ns:caldav"/>
+    <C:source xmlns:C="http://calendarserver.org/ns/"/>
+    <C:subscribed-strip-alarms xmlns:C="http://calendarserver.org/ns/"/>
+    <C:subscribed-strip-attachments xmlns:C="http://calendarserver.org/ns/"/>
+    <C:subscribed-strip-todos xmlns:C="http://calendarserver.org/ns/"/>
+    <B:supported-calendar-component-set xmlns:B="urn:ietf:params:xml:ns:caldav"/>
+    <B:supported-calendar-component-sets xmlns:B="urn:ietf:params:xml:ns:caldav"/>
+    <A:supported-report-set/>
+    <A:sync-token/>
+  </A:prop>
+</A:propfind>
+"""
+        authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user02")
+        request = SimpleStoreRequest(self, "PROPFIND", "/calendars/__uids__/user02/", content=body, authPrincipal=authPrincipal)
+        request.headers.setHeader("content-type", MimeType("text", "xml"))
+        request.headers.setHeader("depth", "1")
+        response = yield self.send(request)
+        response = IResponse(response)
+        self.assertEqual(response.code, resultcode)
+
+        if response.stream:
+            data = yield allDataFromStream(response.stream)
+            returnValue(data)
+        else:
+            returnValue(None)
+
+
+    @inlineCallbacks
     def _getResource(self):
         request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/calendar/")
         resource = yield request.locateResource("/calendars/__uids__/user01/calendar/")
@@ -1234,6 +1294,9 @@
         record = yield self.userRecordWithShortName("user01")
         yield self.changeRecord(record, self.directory.fieldName.hasCalendars, False)
 
+        data = yield self._doPROPFINDHome()
+        self.assertTrue(data is not None)
+
         resource = (yield self._getResourceSharer(href))
         propInvite = yield resource.inviteProperty(None)
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
@@ -1297,6 +1360,9 @@
         yield self.directory.removeRecords(((yield self.userUIDFromShortName("user01")),))
         self.assertTrue((yield self.userUIDFromShortName("user01")) is None)
 
+        data = yield self._doPROPFINDHome()
+        self.assertTrue(data is not None)
+
         resource = (yield self._getResourceSharer(href))
         propInvite = yield resource.inviteProperty(None)
         self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
@@ -1314,6 +1380,33 @@
 
 
     @inlineCallbacks
+    def test_shareeNotificationWithMissingSharer(self):
+
+        yield self.resource.upgradeToShare()
+
+        yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
+            <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
+                <CS:set>
+                    <D:href>mailto:user02 at example.com</D:href>
+                    <CS:summary>My Shared Calendar</CS:summary>
+                    <CS:read-write/>
+                </CS:set>
+            </CS:share>
+            """)
+
+        yield self.directory.removeRecords(((yield self.userUIDFromShortName("user01")),))
+        self.assertTrue((yield self.userUIDFromShortName("user01")) is None)
+
+        request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user02/notification/")
+        notification = yield request.locateResource("/calendars/__uids__/user02/notification/")
+        names = yield notification.listChildren()
+        self.assertEqual(len(names), 1)
+        note_child = yield notification.getChild(names[0])
+        note = yield note_child.text()
+        self.assertTrue(isinstance(note, str))
+
+
+    @inlineCallbacks
     def test_hideInvalidSharers(self):
 
         yield self.resource.upgradeToShare()

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/upgrade.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/twistedcaldav/upgrade.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -758,22 +758,6 @@
 @inlineCallbacks
 def upgradeData(config, directory):
 
-    if config.ResourceService.Enabled:
-        resourcesFileName = config.ResourceService.params.xmlFile
-        if resourcesFileName[0] not in ("/", "."):
-            resourcesFileName = os.path.join(config.DataRoot, resourcesFileName)
-        resourcesFilePath = FilePath(resourcesFileName)
-        if resourcesFilePath.exists():
-            upgradeResourcesXML(resourcesFilePath)
-
-    if config.AugmentService.type == "twistedcaldav.directory.augment.AugmentXMLDB":
-        for fileName in config.AugmentService.params.xmlFiles:
-            if fileName[0] not in ("/", "."):
-                fileName = os.path.join(config.DataRoot, fileName)
-            filePath = FilePath(fileName)
-            if filePath.exists():
-                upgradeAugmentsXML(filePath)
-
     triggerPath = os.path.join(config.ServerRoot, TRIGGER_FILE)
     if os.path.exists(triggerPath):
         try:

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/dkim.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/dkim.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/dkim.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -294,8 +294,16 @@
 
     @staticmethod
     def canonicalizeBody(data):
-        if not data.endswith("\r\n"):
-            data += "\r\n"
+        """
+        DKIM simple body canonicalization: remove empty lines at the end
+        and ensure it ends with one \r\n.
+
+        @param data: data to canonicalize
+        @type data: L{str}
+        """
+        while data.endswith("\r\n"):
+            data = data[:-2]
+        data += "\r\n"
         return data
 
 

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/resource.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/resource.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -179,31 +179,35 @@
                     "version": "2.0",
                 })
             )
-        result = ischedulexml.QueryResult(
 
-            ischedulexml.Capabilities(
-                ischedulexml.Version.fromString(config.Scheduling.iSchedule.SerialNumber),
-                ischedulexml.Versions(
-                    ischedulexml.Version.fromString("1.0"),
-                ),
-                ischedulexml.SchedulingMessages(
+        componentTypes = []
+        from twistedcaldav.ical import allowedSchedulingComponents
+        for name in allowedSchedulingComponents:
+            if name == "VFREEBUSY":
+                componentTypes.append(
                     ischedulexml.Component(
                         ischedulexml.Method(name="REQUEST"),
-                        ischedulexml.Method(name="CANCEL"),
-                        ischedulexml.Method(name="REPLY"),
-                        name="VEVENT"
-                    ),
+                        name=name
+                    )
+                )
+            else:
+                componentTypes.append(
                     ischedulexml.Component(
                         ischedulexml.Method(name="REQUEST"),
                         ischedulexml.Method(name="CANCEL"),
                         ischedulexml.Method(name="REPLY"),
-                        name="VTODO"
-                    ),
-                    ischedulexml.Component(
-                        ischedulexml.Method(name="REQUEST"),
-                        name="VFREEBUSY"
-                    ),
+                        name=name
+                    )
+                )
+
+        result = ischedulexml.QueryResult(
+
+            ischedulexml.Capabilities(
+                ischedulexml.Version.fromString(config.Scheduling.iSchedule.SerialNumber),
+                ischedulexml.Versions(
+                    ischedulexml.Version.fromString("1.0"),
                 ),
+                ischedulexml.SchedulingMessages(*componentTypes),
                 ischedulexml.CalendarDataTypes(*dataTypes),
                 ischedulexml.Attachments(
                     ischedulexml.External(),

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/test/test_dkim.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/test/test_dkim.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/ischedule/test/test_dkim.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -389,6 +389,33 @@
             self.assertEqual(extracted, result.replace("\n", "\r\n"))
 
 
+    def test_canonicalize_body(self):
+        """
+        L{DKIMUtils.canonicalizeBody} correctly canonicalizes bodies.
+        """
+
+        data = (
+            (
+                """Simple""",
+                """Simple\n""",
+            ),
+            (
+                """Simple\n""",
+                """Simple\n""",
+            ),
+            (
+                """Simple\n\n""",
+                """Simple\n""",
+            ),
+        )
+
+        for text, result in data:
+            self.assertEqual(
+                DKIMUtils.canonicalizeBody(text.replace("\n", "\r\n")),
+                result.replace("\n", "\r\n"),
+            )
+
+
     @inlineCallbacks
     def test_locate_public_key(self):
         """

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/itip.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/itip.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/itip.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -358,6 +358,40 @@
 
 
     @staticmethod
+    def processPollStatus(itip_message, calendar, recipient):
+        """
+        Process a METHOD=POLLSTATUS.
+
+        @param itip_message: the iTIP message to process.
+        @type itip_message: L{Component}
+        @param calendar: the calendar object to apply the POLLSTATUS to
+        @type calendar: L{Component}
+
+        @return: the update calendar component or C{None}
+        """
+
+        # Check sequencing
+        if not iTipProcessing.sequenceComparison(itip_message, calendar):
+            # Ignore out of sequence message
+            return None
+
+        calendar_master = calendar.masterComponent()
+        itip_master = itip_message.masterComponent()
+
+        # Remove each VVOTER in the original (except for the recipients)
+        for component in tuple(calendar_master.subcomponents()):
+            if component.name() == "VVOTER" and component.propertyValue("VOTER") != recipient:
+                calendar_master.removeComponent(component)
+
+        # Add each VVOTER in the iTip message
+        for component in itip_master.subcomponents():
+            if component.name() == "VVOTER" and component.propertyValue("VOTER") != recipient:
+                calendar_master.addComponent(component.duplicate())
+
+        return calendar
+
+
+    @staticmethod
     def processReply(itip_message, calendar):
         """
         Process a METHOD=REPLY.
@@ -576,7 +610,7 @@
             # Do VPOLL transfer
             if reply_component.name() == "VPOLL":
                 # TODO: figure out how to report changes back
-                iTipProcessing.updateVPOLLDataFromReply(reply_component, organizer_component, attendee)
+                partstat_changed = iTipProcessing.updateVPOLLDataFromReply(reply_component, organizer_component, attendee)
 
         return attendee.value(), partstat_changed, private_comment_changed
 
@@ -595,6 +629,8 @@
         @type attendee: L{Property}
         """
 
+        partstat_changed = False
+
         # Get REQUEST-STATUS as we need to write that into the saved ATTENDEE property
         reqstatus = tuple(reply_component.properties("REQUEST-STATUS"))
         if reqstatus:
@@ -607,12 +643,13 @@
         organizerVoter = organizer_component.voterComponentForVoter(attendee.value())
 
         if replyVoter is None:
-            return
+            return partstat_changed
 
         if organizerVoter is None:
             # Add in the new one
             organizerVoter = replyVoter.duplicate()
             reply_component.addComponent(organizerVoter)
+            partstat_changed = True
         else:
             # Merge each vote
             replyMap = replyVoter.voteMap()
@@ -621,9 +658,12 @@
             # Add new ones
             for vote in set(replyMap.keys()) - set(organizerMap.keys()):
                 organizerVoter.addComponent(replyMap[vote].duplicate())
+                partstat_changed = True
 
             # Replace existing ones
             for vote in set(replyMap.keys()) & set(organizerMap.keys()):
+                if organizerMap[vote].propertyValue("RESPONSE") != replyMap[vote].propertyValue("RESPONSE"):
+                    partstat_changed = True
                 organizerVoter.removeComponent(organizerMap[vote])
                 organizerVoter.addComponent(replyMap[vote].duplicate())
 
@@ -635,7 +675,9 @@
         except KeyError:
             pass
 
+        return partstat_changed
 
+
     @staticmethod
     def transferItems(from_calendar, to_component, needs_action_rids, reschedule, master_details, remove_matched=False):
         """

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/processing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/processing.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/processing.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -90,8 +90,9 @@
         @param recipient: calendar user receiving the message
         @type recipient: C{str}
 
-        @return: a C{tuple} of (C{bool}, C{bool}) indicating whether the message was processed, and if it was whether
-            auto-processing has taken place.
+        @return: a C{tuple} of (C{bool}, C{bool}, C{bool}, C{bool}) indicating whether the message was processed,
+            and if it was whether auto-processing has taken place, whether it needs to be stored in the inbox, and
+            the changes property for the inbox item.
         """
 
         self.txn = txn
@@ -151,7 +152,7 @@
 
 
     def isAttendeeReceivingMessage(self):
-        return self.method in ("REQUEST", "ADD", "CANCEL")
+        return self.method in ("REQUEST", "ADD", "CANCEL", "POLLSTATUS")
 
 
     @inlineCallbacks
@@ -393,6 +394,8 @@
         elif self.method == "ADD":
             # TODO: implement ADD
             result = (False, False, False, None)
+        elif self.method == "POLLSTATUS":
+            result = (yield self.doImplicitAttendeePollStatus())
         else:
             # NB We should never get here as we will have rejected unsupported METHODs earlier.
             result = (True, True, False, None,)
@@ -552,7 +555,7 @@
             else:
                 # Request needs to be ignored
                 log.debug("ImplicitProcessing - originator '%s' to recipient '%s' processing METHOD:REQUEST, UID: '%s' - ignoring" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
-                result = (True, True, False, None,)
+                result = (True, False, False, None,)
 
         returnValue(result)
 
@@ -570,7 +573,7 @@
         # If there is no existing copy, then ignore
         if self.recipient_calendar is None:
             log.debug("ImplicitProcessing - originator '%s' to recipient '%s' ignoring METHOD:CANCEL, UID: '%s' - attendee has no copy" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
-            result = (True, True, True, None)
+            result = (True, False, True, None)
         else:
             # Need to check for auto-respond attendees. These need to suppress the inbox message
             # if the cancel is processed. However, if the principal is a user we always force the
@@ -631,12 +634,36 @@
                     result = (True, autoprocessed, store_inbox, changes)
             else:
                 log.debug("ImplicitProcessing - originator '%s' to recipient '%s' processing METHOD:CANCEL, UID: '%s' - ignoring" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
-                result = (True, True, False, None)
+                result = (True, False, False, None)
 
         returnValue(result)
 
 
     @inlineCallbacks
+    def doImplicitAttendeePollStatus(self):
+        """
+        An iTIP message status update has been sent to an attendee by the organizer. We need to update the
+        attendee state based on the nature of the iTIP message.
+        """
+        # If there is no existing copy, then we must fail
+        if self.new_resource:
+            log.debug("ImplicitProcessing - originator '%s' to recipient '%s' processing METHOD:POLLSTATUS, UID: '%s' - attendee has no copy" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
+            returnValue((True, False, False, None,))
+
+        processed_message = iTipProcessing.processPollStatus(self.message, self.recipient_calendar)
+
+        # Let the store know that no time-range info has changed for a refresh (assuming that
+        # no auto-accept changes were made)
+        processed_message.noInstanceIndexing = True
+
+        # Update the attendee's copy of the event
+        log.debug("ImplicitProcessing - originator '%s' to recipient '%s' processing METHOD:POLLSTATUS, UID: '%s' - updating poll" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
+        yield self.writeCalendarResource(None, self.recipient_calendar_resource, processed_message)
+
+        returnValue((True, False, False, None,))
+
+
+    @inlineCallbacks
     def checkAttendeeAutoReply(self, calendar, automode):
         """
         Check whether a reply to the given iTIP message is needed and if so make the

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/scheduler.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/scheduler.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/scheduler.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -515,7 +515,7 @@
             yield self.generateRemoteSchedulingResponses(otherserver_recipients, responses, freebusy, getattr(self.txn, 'doing_attendee_refresh', False))
 
         # To reduce chatter, we suppress certain messages
-        if not self.suppress_refresh:
+        if not self.suppress_refresh or self.calendar.mainType() == "VPOLL":
 
             # Now process remote recipients
             if remote_recipients:

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/test/test_itip.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/test/test_itip.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/scheduling/test/test_itip.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -21,7 +21,7 @@
 from twisted.trial import unittest
 
 from twistedcaldav.stdconfig import config
-from twistedcaldav.ical import Component
+from twistedcaldav.ical import Component, normalize_iCalStr
 
 from txdav.caldav.datastore.scheduling.itip import iTipProcessing, iTipGenerator
 
@@ -1289,6 +1289,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "1.2 Simple Reply - recurring no overrides",
@@ -1335,6 +1336,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "1.3 Simple Reply - recurring with missing master",
@@ -1389,6 +1391,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "1.4 Simple Reply - recurring with overrides in master but not reply",
@@ -1453,6 +1456,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "1.5 Simple Reply - recurring with overrides in master invalid in reply",
@@ -1517,6 +1521,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "1.6 Simple Reply - recurring with overrides in master, invalid ones in reply",
@@ -1590,6 +1595,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "2.1 X-CALENDARSERVER-RESET-PARTSTAT Reply - non recurring",
@@ -1636,6 +1642,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "2.2 X-CALENDARSERVER-RESET-PARTSTAT Reply - non recurring",
@@ -1682,6 +1689,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "2.3 X-CALENDARSERVER-RESET-PARTSTAT Reply - non recurring",
@@ -1728,6 +1736,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "2.4 X-CALENDARSERVER-RESET-PARTSTAT Reply - non recurring",
@@ -1774,6 +1783,7 @@
 END:VCALENDAR
 """,
                 True,
+                None,
             ),
             (
                 "3.1 Simple VPOLL Reply - response added",
@@ -1874,6 +1884,7 @@
 END:VCALENDAR
 """,
                 True,
+                ('mailto:user2 at example.com', set([("", True, False,)])),
             ),
             (
                 "3.2 Simple VPOLL Reply - response changed",
@@ -1978,6 +1989,7 @@
 END:VCALENDAR
 """,
                 True,
+                ('mailto:user2 at example.com', set([("", True, False,)])),
             ),
             (
                 "3.3 Simple VPOLL Reply - response added and changed",
@@ -2090,6 +2102,7 @@
 END:VCALENDAR
 """,
                 True,
+                ('mailto:user2 at example.com', set([("", True, False,)])),
             ),
             (
                 "3.4 Simple VPOLL Reply - response one changed",
@@ -2202,21 +2215,475 @@
 END:VCALENDAR
 """,
                 True,
+                ('mailto:user2 at example.com', set([("", True, False,)])),
             ),
+            (
+                "3.5 Simple VPOLL Reply - no changes",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VPOLL
+UID:8D2B2048-7915-6ECD-A82B-01F4EF8EEBEA
+DTSTAMP:20150113T152404Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+SUMMARY:New Poll
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user2 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:50
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+END:VOTE
+END:VVOTER
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+POLL-ITEM-ID:1
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+POLL-ITEM-ID:2
+END:VEVENT
+END:VPOLL
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+METHOD:REPLY
+BEGIN:VPOLL
+UID:8D2B2048-7915-6ECD-A82B-01F4EF8EEBEA
+DTSTAMP:20150113T152404Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+SUMMARY:New Poll
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user2 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:50
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+END:VOTE
+END:VVOTER
+END:VPOLL
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VPOLL
+UID:8D2B2048-7915-6ECD-A82B-01F4EF8EEBEA
+DTSTAMP:20150113T152404Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+SUMMARY:New Poll
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;SCHEDULE-STATUS=2.0:mailto:user2 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:50
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+END:VOTE
+END:VVOTER
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+POLL-ITEM-ID:1
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+POLL-ITEM-ID:2
+END:VEVENT
+END:VPOLL
+END:VCALENDAR
+""",
+                True,
+                ('mailto:user2 at example.com', set([])),
+            ),
         )
 
-        for title, calendar_txt, itip_txt, changed_txt, expected in data:
+        for title, calendar_txt, itip_txt, changed_txt, expected, processed in data:
             calendar = Component.fromString(calendar_txt)
             itip = Component.fromString(itip_txt)
             if expected:
                 changed = Component.fromString(changed_txt)
 
-            result, _ignore = iTipProcessing.processReply(itip, calendar)
+            result, result_processed = iTipProcessing.processReply(itip, calendar)
             self.assertEqual(result, expected, msg="Result mismatch: %s" % (title,))
             if expected:
                 self.assertEqual(changed, calendar, msg="Calendar mismatch: %s" % (title,))
+            if processed is not None:
+                self.assertEqual(result_processed, processed, msg="Process mismatch: %s" % (title,))
 
 
+    def test_processPollStatus(self):
+        """
+        Test iTIPProcessing.processPollStatus
+        """
+
+        data = (
+            (
+                "3.1 Simple VPOLL - response added",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VPOLL
+UID:8D2B2048-7915-6ECD-A82B-01F4EF8EEBEA
+DTSTAMP:20150113T152404Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+SUMMARY:New Poll
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user1 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+END:VOTE
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user2 at example.com
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user3 at example.com
+END:VVOTER
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+POLL-ITEM-ID:1
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+POLL-ITEM-ID:2
+END:VEVENT
+END:VPOLL
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+METHOD:POLLSTATUS
+BEGIN:VPOLL
+UID:8D2B2048-7915-6ECD-A82B-01F4EF8EEBEA
+DTSTAMP:20150113T152404Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+SUMMARY:New Poll
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user1 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+END:VOTE
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user2 at example.com
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user3 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:0
+END:VOTE
+END:VVOTER
+END:VPOLL
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VPOLL
+UID:8D2B2048-7915-6ECD-A82B-01F4EF8EEBEA
+DTSTAMP:20150113T152404Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+SUMMARY:New Poll
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user1 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+END:VOTE
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user2 at example.com
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user3 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:0
+END:VOTE
+END:VVOTER
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-ITEM-ID:1
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-ITEM-ID:2
+END:VEVENT
+END:VPOLL
+END:VCALENDAR
+""",
+            ),
+            (
+                "3.2 Simple VPOLL - recipient response not changed",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VPOLL
+UID:8D2B2048-7915-6ECD-A82B-01F4EF8EEBEA
+DTSTAMP:20150113T152404Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+SUMMARY:New Poll
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user1 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+END:VOTE
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user2 at example.com
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user3 at example.com
+END:VVOTER
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+POLL-ITEM-ID:1
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+POLL-ITEM-ID:2
+END:VEVENT
+END:VPOLL
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+METHOD:POLLSTATUS
+BEGIN:VPOLL
+UID:8D2B2048-7915-6ECD-A82B-01F4EF8EEBEA
+DTSTAMP:20150113T152404Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+SUMMARY:New Poll
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user1 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+END:VOTE
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user2 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:50
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:0
+END:VOTE
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user3 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:0
+END:VOTE
+END:VVOTER
+END:VPOLL
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VPOLL
+UID:8D2B2048-7915-6ECD-A82B-01F4EF8EEBEA
+DTSTAMP:20150113T152404Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+SUMMARY:New Poll
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user1 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+END:VOTE
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user2 at example.com
+END:VVOTER
+BEGIN:VVOTER
+DTSTAMP:20150113T152404Z
+VOTER;RSVP=TRUE:mailto:user3 at example.com
+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:0
+END:VOTE
+END:VVOTER
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-ITEM-ID:1
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+POLL-ITEM-ID:2
+END:VEVENT
+END:VPOLL
+END:VCALENDAR
+""",
+            ),
+        )
+
+        for title, calendar_txt, itip_txt, changed_txt in data:
+            calendar = Component.fromString(calendar_txt)
+            itip = Component.fromString(itip_txt)
+
+            result = iTipProcessing.processPollStatus(itip, calendar, "mailto:user2 at example.com")
+            self.assertEqual(normalize_iCalStr(result), normalize_iCalStr(changed_txt), msg="Calendar mismatch: %s" % (title,))
+
+
     def test_update_attendee_partstat(self):
 
         data = (

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/sql.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/sql.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -2303,7 +2303,9 @@
         self._cachedComponent = None
         self._cachedCommponentPerUser = {}
 
+        self._lockedUID = False
 
+
     @classmethod
     @inlineCallbacks
     def _createInternal(cls, parent, name, component, internal_state, options=None, split_details=None):
@@ -3116,8 +3118,8 @@
                 internal_request=is_internal,
             ))
 
-            # group attendees
-            if scheduler.state == "organizer":
+            # Group attendees - though not during a split
+            if scheduler.state == "organizer" and internal_state != ComponentUpdateState.SPLIT_OWNER:
                 changed = yield self.reconcileGroupAttendees(component, inserting)
                 if changed:
                     yield scheduler.extractAttendees()
@@ -3214,15 +3216,26 @@
 
 
     @inlineCallbacks
-    def _lockUID(self, component, inserting, internal_state):
+    def _lockUID(self, uid, internal_state):
         """
         Create a lock on the component's UID and verify, after getting the lock, that the incoming UID
         meets the requirements of the store.
         """
 
+        if not self._lockedUID and internal_state in (ComponentUpdateState.NORMAL, ComponentUpdateState.SPLIT_OWNER):
+            yield NamedLock.acquire(self._txn, "ImplicitUIDLock:%s" % (hashlib.md5(uid).hexdigest(),))
+            self._lockedUID = True
+
+
+    @inlineCallbacks
+    def _lockAndCheckUID(self, component, inserting, internal_state):
+        """
+        Create a lock on the component's UID and verify, after getting the lock, that the incoming UID
+        meets the requirements of the store.
+        """
+
         new_uid = component.resourceUID()
-        if internal_state == ComponentUpdateState.NORMAL:
-            yield NamedLock.acquire(self._txn, "ImplicitUIDLock:{0}".format(hashlib.md5(new_uid).hexdigest(),))
+        yield self._lockUID(new_uid, internal_state)
 
         # UID conflict check - note we do this after reserving the UID to avoid a race condition where two requests
         # try to write the same calendar data to two different resource URIs.
@@ -3302,9 +3315,27 @@
 
             # Do scheduling only for owner split
             if internal_state == ComponentUpdateState.SPLIT_OWNER:
-                yield self.doImplicitScheduling(component, inserting, internal_state, options, split_details)
+                # UID lock - this will remain active until the end of the current txn
+                yield self._lockAndCheckUID(component, inserting, internal_state)
 
-            self.isScheduleObject = True
+                # Make sure various bits of scheduling meta-data are correctly setup to ensure the
+                # new resource created by a split has the proper state
+                implicit_result = yield self.doImplicitScheduling(component, inserting, internal_state, options, split_details)
+                if isinstance(implicit_result, int):
+                    msg = "Invalid return status code from ImplicitScheduler during split: %s" % (implicit_result,)
+                    log.error(msg)
+                    raise InvalidObjectResourceError(msg)
+
+                self.isScheduleObject, new_component, did_implicit_action, schedule_state = implicit_result
+                if new_component is not None:
+                    component = new_component
+                if did_implicit_action:
+                    self._componentChanged = True
+
+            elif internal_state == ComponentUpdateState.SPLIT_ATTENDEE:
+                # This must always be set since the only time we get is is during scheduling
+                self.isScheduleObject = True
+
             self.processScheduleTags(component, inserting, internal_state)
 
         elif internal_state != ComponentUpdateState.RAW:
@@ -3312,7 +3343,7 @@
             yield self.fullValidation(component, inserting, internal_state)
 
             # UID lock - this will remain active until the end of the current txn
-            yield self._lockUID(component, inserting, internal_state)
+            yield self._lockAndCheckUID(component, inserting, internal_state)
 
             # Preserve private comments
             yield self.preservePrivateComments(component, inserting, internal_state)
@@ -4691,25 +4722,32 @@
         @type pastuid: L{str}
         """
 
+        # Cannot create one with the same UID as this
+        if pastUID and pastUID == self._uid:
+            raise InvalidSplit("Cannot split an event and re-use the same UID.")
+
         # Must be recurring
         component = yield self.component()
         if not component.isRecurring():
-            raise InvalidSplit()
+            raise InvalidSplit("Cannot split a non-recurring event.")
 
         # Cannot be attendee
         organizer = component.getOrganizer()
         organizerAddress = (yield calendarUserFromCalendarUserAddress(organizer, self._txn)) if organizer else None
         if organizer is not None and organizerAddress.record.uid != self.calendar().ownerHome().uid():
-            raise InvalidSplit()
+            raise InvalidSplit("Only organizers can split events.")
 
         # Determine valid split point
         splitter = iCalSplitter(1024, 14)
         rid = splitter.whereSplit(component, break_point=rid, allow_past_the_end=False)
         if rid is None:
-            raise InvalidSplit()
+            raise InvalidSplit("Cannot find a suitable recurrence-id to split at.")
 
         # Do split and return new resource
-        olderObject = yield self.split(rid=rid, olderUID=pastUID)
+        try:
+            olderObject = yield self.split(rid=rid, olderUID=pastUID)
+        except (UIDExistsError, UIDExistsElsewhereError):
+            raise InvalidSplit("Chosen UID exists elsewhere.")
         returnValue(olderObject)
 
 
@@ -4747,7 +4785,7 @@
         """
 
         # First job is to grab a UID lock on this entire series of events
-        yield NamedLock.acquire(self._txn, "ImplicitUIDLock:{0}".format(hashlib.md5(self._uid).hexdigest(),))
+        yield self._lockUID(self._uid, internal_state=ComponentUpdateState.SPLIT_OWNER)
 
         # Find all other calendar objects on this server with the same UID
         if onlyThis:

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/test/test_sql.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/caldav/datastore/test/test_sql.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -5455,7 +5455,10 @@
 
             responses = ScheduleResponseQueue("REQUEST", responsecode.OK)
             for recipient in recipients:
-                responses.add(recipient, responsecode.OK, reqstatus=iTIPRequestStatus.MESSAGE_DELIVERED)
+                if recipient.startswith("urn:x-uid"):
+                    responses.add(recipient, responsecode.OK, reqstatus=iTIPRequestStatus.MESSAGE_DELIVERED)
+                else:
+                    responses.add(recipient, responsecode.NOT_FOUND, reqstatus=iTIPRequestStatus.INVALID_CALENDAR_USER)
             return succeed(responses)
 
         component = Component.fromString(data % self.subs)
@@ -6867,13 +6870,13 @@
 
         # Get the existing and new object data
         cobj1 = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
-        self.assertTrue(cobj1.isScheduleObject)
+        self.assertFalse(cobj1.isScheduleObject)
         ical1 = yield cobj1.component()
         relID = ical1.masterComponent().propertyValue("RELATED-TO")
 
         cobj2 = yield self.calendarObjectUnderTest(name=oldname, calendar_name="calendar", home="user01")
         self.assertTrue(cobj2 is not None)
-        self.assertTrue(cobj2.isScheduleObject)
+        self.assertFalse(cobj2.isScheduleObject)
         ical2 = yield cobj2.component()
         newUID = ical2.masterComponent().propertyValue("UID")
 
@@ -7013,7 +7016,57 @@
         self.assertEqual(normalize_iCalStr(ical_inbox), normalize_iCalStr(data_inbox2) % relsubs, "Failed inbox: %s" % (title,))
 
 
+    @inlineCallbacks
+    def test_calendarObjectSplit_splitat_no_same_uid(self):
+        """
+        Test that user triggered splitting of calendar objects does not work if the specified UID is the same
+        as the resource being split.
+        """
 
+        yield self._setupSplitAt()
+
+        # Update it
+        cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.subs), pastUID="12345-67890"), InvalidSplit)
+
+
+    @inlineCallbacks
+    def test_calendarObjectSplit_splitat_no_existing_uid(self):
+        """
+        Test that user triggered splitting of calendar objects does not work if the specified UID is the same
+        as another resource.
+        """
+
+        data_existing = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-existing
+DTSTART:%(now_back28)s
+DURATION:PT1H
+DTSTAMP:20051222T210507Z
+RRULE:FREQ=DAILY;COUNT=50
+SUMMARY:1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+END:VEVENT
+END:VCALENDAR
+"""
+
+        yield self._setupSplitAt()
+
+        calendar = yield self.calendarUnderTest(name="calendar", home="user01")
+        component = Component.fromString(data_existing % self.subs)
+        yield calendar.createCalendarObjectWithName("data2.ics", component)
+        yield self.commit()
+
+        # Update it
+        cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.subs), pastUID="12345-67890-existing"), InvalidSplit)
+
+
+
 class TimeRangeUpdateOptimization(CommonCommonTests, unittest.TestCase):
     """
     CalendarObject time range optimization tests.

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/test/util.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/test/util.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txdav/common/datastore/test/util.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -262,6 +262,7 @@
                 reactor, store.newTransaction, None, useWorkerPool=False
             )
             store.queuer = store.queuer.transferProposalCallbacks(pool)
+            store.pool = pool
             pool.startService()
 
         returnValue(store)

Modified: CalendarServer/branches/users/cdaboo/pod2pod-migration/txweb2/dav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/pod2pod-migration/txweb2/dav/resource.py	2015-02-06 01:31:25 UTC (rev 14381)
+++ CalendarServer/branches/users/cdaboo/pod2pod-migration/txweb2/dav/resource.py	2015-02-06 19:17:54 UTC (rev 14382)
@@ -706,7 +706,7 @@
         def gotChildren(listChildrenResult):
             children[:] = list(listChildrenResult)
             getChild()
-        maybeDeferred(self.listChildren).addCallback(gotChildren)
+        maybeDeferred(self.listChildren).addCallback(gotChildren).addErrback(completionDeferred.errback)
 
         return completionDeferred
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20150206/12c20db0/attachment-0001.html>


More information about the calendarserver-changes mailing list